#include #include #include #include #include #include #include #include #include #include "execute.hpp" #include "contrib/base64.hpp" #include "utils/utils.hpp" bool EXITSTATUSCHECK(int ret) { return (ret != -1 && WIFEXITED(ret) && (WEXITSTATUS(ret) == 0)); // ret is -1 if the command failed to execute. } namespace dropshell { bool execute_local_command_interactive(const sCommand &command, bool silent) { if (command.get_command_to_run().empty()) return false; std::string full_command = command.construct_cmd(cStyle::Raw); // Get the command string pid_t pid = fork(); if (pid == -1) { // Fork failed perror("fork failed"); return false; } else if (pid == 0) { // Child process std::vector commandvec = {"bash", "-c", full_command.c_str(),NULL}; if (!silent) { std::cout << "Executing command: "; for (auto & x : commandvec) std::cout << x << " "; std::cout << std::endl; } execvp(commandvec[0], const_cast(commandvec.data())); // If execvp returns, it means an error occurred perror("execvp failed"); exit(EXIT_FAILURE); // Exit child process on error } else { // Parent process int ret; // Wait for the child process to complete waitpid(pid, &ret, 0); return EXITSTATUSCHECK(ret); } } bool execute_local_command_and_capture_output(const sCommand& command, std::string * output, cMode mode) { ASSERT(output != nullptr, "Output string must be provided"); ASSERT(is_raw(mode), "Capture output mode requires raw command mode"); ASSERT(!hasFlag(mode, cMode::Silent), "Silent mode is not allowed with capture output mode"); if (command.get_command_to_run().empty()) return false; cStyle style = getStyle(mode); std::string full_cmd = command.construct_cmd(style) + " 2>&1"; FILE *pipe = popen(full_cmd.c_str(), "r"); if (!pipe) { return false; } char buffer[128]; while (fgets(buffer, sizeof(buffer), pipe) != nullptr) { (*output) += buffer; } int ret = pclose(pipe); return EXITSTATUSCHECK(ret); } bool execute_local_command(const sCommand & command, cMode mode, std::string * output /* = nullptr */) { if (hasFlag(mode, cMode::Interactive)) { ASSERT(! hasFlag(mode, cMode::CaptureOutput), "Interactive mode and capture output mode cannot be used together"); ASSERT(output == nullptr, "Interactive mode and an output string cannot be used together"); ASSERT(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(output != nullptr, "Capture output mode requires an output string to be provided"); ASSERT(is_raw(mode), "Capture output mode requires raw command mode"); ASSERT(!hasFlag(mode, cMode::Silent), "Silent mode is not allowed with capture output mode"); return execute_local_command_and_capture_output(command, output, mode); } 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) { if (command.get_command_to_run().empty()) return false; ASSERT(!(hasFlag(mode, cMode::Interactive) && !is_raw(mode)), "Interactive mode requires raw command mode"); ASSERT(!(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; 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(raw_cmd.find("'") == std::string::npos, "Raw command must not contain single quotes"); cmdstr = "bash -c "+ halfquote(raw_cmd); } sCommand ssh_command(ssh_cmd.str() + " " + cmdstr); bool rval = execute_local_command(ssh_command, mode, output); if (!rval) { std::cerr <