From ac797e111c50923fb1aec8787ec3de2b0b44e919 Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 6 May 2025 22:22:24 +1200 Subject: [PATCH] Default to safe --- src/utils/execute.cpp | 55 ++++++++++++++++++++++++++----------------- src/utils/execute.hpp | 5 +++- 2 files changed, 37 insertions(+), 23 deletions(-) diff --git a/src/utils/execute.cpp b/src/utils/execute.cpp index c4c4b87..bd25e86 100644 --- a/src/utils/execute.cpp +++ b/src/utils/execute.cpp @@ -53,27 +53,14 @@ bool execute_local_command_interactive(const sCommand &command, bool silent) } } -bool execute_local_command(const sCommand& command, bool silent, bool safe) { - if (command.get_command_to_run().empty()) - return false; - cStyle style = safe ? cStyle::Safe : cStyle::Raw; - std::string full_cmd = command.construct_cmd(style) + " 2>&1" + (silent ? " > /dev/null" : ""); - int ret = system(full_cmd.c_str()); - - bool ok = EXITSTATUSCHECK(ret); - if (!ok) { - std::cerr << "Error: Failed to execute command: " << std::endl; - std::cerr << full_cmd << std::endl; - } - return ok; -} - -bool execute_local_command_and_capture_output(const sCommand& command, std::string * output, bool silent, bool safe) +bool execute_local_command_and_capture_output(const sCommand& command, std::string * output, cMode mode) { ASSERT_MSG(output != nullptr, "Output string must be provided"); + ASSERT_MSG(is_raw(mode), "Capture output mode requires raw command mode"); + ASSERT_MSG(!hasFlag(mode, cMode::Silent), "Silent mode is not allowed with capture output mode"); if (command.get_command_to_run().empty()) return false; - cStyle style = safe ? cStyle::Safe : cStyle::Raw; + cStyle style = getStyle(mode); std::string full_cmd = command.construct_cmd(style) + " 2>&1"; FILE *pipe = popen(full_cmd.c_str(), "r"); if (!pipe) { @@ -94,16 +81,29 @@ bool execute_local_command(const sCommand & command, cMode mode, std::string * o if (hasFlag(mode, cMode::Interactive)) { ASSERT_MSG(! hasFlag(mode, cMode::CaptureOutput), "Interactive mode and capture output mode cannot be used together"); ASSERT_MSG(output == nullptr, "Interactive mode and an output string cannot be used together"); - ASSERT_MSG(! hasFlag(mode, cMode::SafeCommand), "Interactive mode and safe command mode cannot be used together"); + ASSERT_MSG(is_raw(mode), "Interactive mode requires raw command mode"); + return execute_local_command_interactive(command, hasFlag(mode, cMode::Silent)); } if (hasFlag(mode, cMode::CaptureOutput)) { ASSERT_MSG(output != nullptr, "Capture output mode requires an output string to be provided"); - return execute_local_command_and_capture_output(command, output, hasFlag(mode, cMode::Silent), hasFlag(mode, cMode::SafeCommand)); + + return execute_local_command_and_capture_output(command, output, mode); } - return execute_local_command(command, hasFlag(mode, cMode::Silent), hasFlag(mode, cMode::SafeCommand)); + if (command.get_command_to_run().empty()) + return false; + cStyle style = getStyle(mode); + std::string full_cmd = command.construct_cmd(style) + " 2>&1" + (hasFlag(mode, cMode::Silent) ? " > /dev/null" : ""); + int ret = system(full_cmd.c_str()); + + bool ok = EXITSTATUSCHECK(ret); + if (!ok) { + std::cerr << "Error: Failed to execute command: " << std::endl; + std::cerr << full_cmd << std::endl; + } + return ok; } bool execute_ssh_command(const sSSHInfo &ssh_info, const sCommand &command, cMode mode, std::string *output) @@ -111,14 +111,25 @@ bool execute_ssh_command(const sSSHInfo &ssh_info, const sCommand &command, cMod if (command.get_command_to_run().empty()) return false; - ASSERT_MSG(!(hasFlag(mode, cMode::Interactive) && hasFlag(mode, cMode::SafeCommand)), "Safe command mode must not be used with Interactive mode"); + ASSERT_MSG(!(hasFlag(mode, cMode::Interactive) && !is_raw(mode)), "Interactive mode requires raw command mode"); ASSERT_MSG(!(hasFlag(mode, cMode::CaptureOutput) && output == nullptr), "Capture output mode must be used with an output string"); std::stringstream ssh_cmd; ssh_cmd << "ssh -p " << ssh_info.port << " " << (hasFlag(mode, cMode::Interactive) ? "-tt " : "") << ssh_info.user << "@" << ssh_info.host; - sCommand ssh_command(ssh_cmd.str() + " bash -c " + quote(escapequotes(command.construct_cmd(hasFlag(mode, cMode::SafeCommand) ? cStyle::Safe : cStyle::Raw)))); + std::string cmdstr; + if (!is_raw(mode)) + cmdstr = quote("bash -c " + command.construct_cmd(cStyle::Safe)); + else + { + std::string raw_cmd = command.construct_cmd(cStyle::Raw); + ASSERT_MSG(raw_cmd.find("'") == std::string::npos, "Raw command must not contain single quotes"); + ASSERT_MSG(raw_cmd.find("\"") == std::string::npos, "Raw command must not contain double quotes"); + cmdstr = halfquote("bash -c " + quote(raw_cmd)); + } + + sCommand ssh_command(ssh_cmd.str() + " " + cmdstr); bool rval = execute_local_command(ssh_command, mode, output); diff --git a/src/utils/execute.hpp b/src/utils/execute.hpp index d2a3eed..d0dba15 100644 --- a/src/utils/execute.hpp +++ b/src/utils/execute.hpp @@ -14,7 +14,7 @@ enum class cMode { Interactive = 1, Silent = 2, CaptureOutput = 4, - SafeCommand = 8 + RawCommand = 8 }; typedef struct sSSHInfo { @@ -36,7 +36,10 @@ enum class cStyle { Raw = 1 }; +inline cStyle getStyle(cMode mode) { return is_raw(mode) ? cStyle::Raw : cStyle::Safe; } inline bool is_safe(cStyle style) { return style == cStyle::Safe; } +inline bool is_raw(cStyle style) { return style == cStyle::Raw; } +inline bool is_raw(cMode mode) { return hasFlag(mode, cMode::RawCommand); } // class to hold a command to run on the remote server. class sCommand {