diff --git a/src/applib/async_command_executor.h b/src/applib/async_command_executor.h index a5fc2c1..8ff2128 100644 --- a/src/applib/async_command_executor.h +++ b/src/applib/async_command_executor.h @@ -54,8 +54,8 @@ class AsyncCommandExecutor : public hz::ErrorHolder { /// Set the command to execute. Call before execute(). - /// Note: The command and the arguments _must_ be shell-escaped. - /// Use g_shell_quote() or Glib::shell_quote(). Note that each argument + /// Note: The command and the arguments _must_ be shell-escaped + /// using CommandExecutor::shell_quote(). Note that each argument /// must be escaped separately. void set_command(const std::string& command_exec, const std::string& command_args); diff --git a/src/applib/command_executor.cpp b/src/applib/command_executor.cpp index 18756ca..81bb362 100644 --- a/src/applib/command_executor.cpp +++ b/src/applib/command_executor.cpp @@ -13,6 +13,8 @@ Copyright: #include // g_usleep() #include "command_executor.h" +#include "build_config.h" +#include "hz/string_algo.h" @@ -251,6 +253,18 @@ std::string CommandExecutor::get_error_header() +std::string CommandExecutor::shell_quote(const std::string& str) +{ + if (!BuildEnv::is_kernel_family_windows()) { + return Glib::shell_quote(str); + } + // This may be somewhat insecure, but g_spawn_command_line_async() + // does not work with single quotes on Windows. + return "\"" + hz::string_replace_copy(str, "\"", "\\\"") + "\""; +} + + + sigc::signal& CommandExecutor::signal_execute_tick() { return signal_execute_tick_; diff --git a/src/applib/command_executor.h b/src/applib/command_executor.h index 3da3b66..9903157 100644 --- a/src/applib/command_executor.h +++ b/src/applib/command_executor.h @@ -162,6 +162,12 @@ class CommandExecutor : public sigc::trackable { [[nodiscard]] std::string get_error_header(); + /// Quote a string for shell execution. This is similar to + /// g_shell_quote(), but it uses double quotes in Windows so that + /// the command can be actually executed by g_spawn_command_line_async(). + [[nodiscard]] static std::string shell_quote(const std::string& str); + + // ----------------- Signals diff --git a/src/applib/smartctl_executor.cpp b/src/applib/smartctl_executor.cpp index 47aacb3..a2dbc3b 100644 --- a/src/applib/smartctl_executor.cpp +++ b/src/applib/smartctl_executor.cpp @@ -115,9 +115,9 @@ hz::ExpectedVoid execute_smartctl(const std::string& devi device_specific_options += " "; - smartctl_ex->set_command(Glib::shell_quote(hz::fs_path_to_string(smartctl_binary)), + smartctl_ex->set_command(CommandExecutor::shell_quote(hz::fs_path_to_string(smartctl_binary)), smartctl_def_options + device_specific_options + command_options - + " " + Glib::shell_quote(device)); + + " " + CommandExecutor::shell_quote(device)); if (!smartctl_ex->execute() || !smartctl_ex->get_error_msg().empty()) { debug_out_warn("app", DBG_FUNC_MSG << "Smartctl binary did not execute cleanly.\n"); diff --git a/src/applib/storage_detector_helpers.h b/src/applib/storage_detector_helpers.h index 11fdfef..b02d5af 100644 --- a/src/applib/storage_detector_helpers.h +++ b/src/applib/storage_detector_helpers.h @@ -53,7 +53,7 @@ inline hz::ExpectedVoid execute_tw_cli(const CommandExecut } for (const auto& bin : binaries) { - executor->set_command(Glib::shell_quote(bin), command_options); + executor->set_command(CommandExecutor::shell_quote(bin), command_options); if (!executor->execute() || !executor->get_error_msg().empty()) { debug_out_warn("app", DBG_FUNC_MSG << "Error while executing tw_cli binary.\n"); diff --git a/src/applib/storage_detector_win32.cpp b/src/applib/storage_detector_win32.cpp index 1bd9897..fc4ce77 100644 --- a/src/applib/storage_detector_win32.cpp +++ b/src/applib/storage_detector_win32.cpp @@ -206,7 +206,7 @@ hz::ExpectedVoid get_scan_open_multiport_devices(std::vect if (!smartctl_def_options.empty()) smartctl_def_options += " "; - smartctl_ex->set_command(Glib::shell_quote(hz::fs_path_to_string(smartctl_binary)), + smartctl_ex->set_command(CommandExecutor::shell_quote(hz::fs_path_to_string(smartctl_binary)), smartctl_def_options + "--scan-open"); if (bool execute_status = smartctl_ex->execute(); !execute_status) { @@ -280,7 +280,7 @@ inline hz::ExpectedVoid execute_areca_cli(const CommandExe { std::shared_ptr executor = ex_factory->create_executor(CommandExecutorFactory::ExecutorType::ArecaCli); - executor->set_command(Glib::shell_quote(cli_binary), command_options); + executor->set_command(CommandExecutor::shell_quote(cli_binary), command_options); if (!executor->execute() || !executor->get_error_msg().empty()) { debug_out_warn("app", DBG_FUNC_MSG << "Error while executing Areca cli binary.\n"); diff --git a/src/gsc_main_window.cpp b/src/gsc_main_window.cpp index 46192f0..f01bedf 100644 --- a/src/gsc_main_window.cpp +++ b/src/gsc_main_window.cpp @@ -104,8 +104,8 @@ GscMainWindow::GscMainWindow(BaseObjectType* gtkcobj, Glib::RefPtr ex.create_running_dialog(this); ex.set_running_msg(_("Checking if smartctl is executable...")); -// ex.set_command(Glib::shell_quote(smartctl_binary), smartctl_def_options + "-V"); // --version - ex.set_command(Glib::shell_quote(smartctl_binary), "-V"); // --version +// ex.set_command(CommandExecutor::shell_quote(smartctl_binary), smartctl_def_options + "-V"); // --version + ex.set_command(CommandExecutor::shell_quote(smartctl_binary), "-V"); // --version if (!ex.execute() || !ex.get_error_msg().empty()) { error_msg = ex.get_error_msg(); @@ -946,7 +946,7 @@ void GscMainWindow::run_update_drivedb() if (smartctl_binary.is_absolute()) { update_binary_path = smartctl_binary.parent_path() / update_binary_path; } - std::string update_binary = Glib::shell_quote(hz::fs_path_to_string(update_binary_path)); + std::string update_binary = CommandExecutor::shell_quote(hz::fs_path_to_string(update_binary_path)); if constexpr(!BuildEnv::is_kernel_family_windows()) { // X11 update_binary = "xterm -hold -e " + update_binary;