#include "runner.h" #include #include #include #include #include #include namespace runner { int execute_cmd( const std::string& command, const std::vector& args, const std::string& working_dir, const std::map& env, bool silent, bool interactive, sSSHInfo* sshinfo, std::string* output ) { if (sshinfo) { // Build remote command string std::ostringstream remote_cmd; // Set environment variables for (const auto& kv : env) { remote_cmd << kv.first << "='" << kv.second << "' "; } // Change working directory if (!working_dir.empty()) { remote_cmd << "cd '" << working_dir << "' && "; } // Command and args remote_cmd << command; for (const auto& arg : args) { remote_cmd << " '" << arg << "'"; } std::string remote_cmd_str = remote_cmd.str(); // Build ssh command std::vector ssh_argv = {"ssh"}; if (!sshinfo->port.empty()) { ssh_argv.push_back("-p"); ssh_argv.push_back(sshinfo->port); } std::string userhost = sshinfo->user.empty() ? sshinfo->host : (sshinfo->user + "@" + sshinfo->host); ssh_argv.push_back(userhost); ssh_argv.push_back(remote_cmd_str); // Prepare for exec std::vector argv; for (auto& s : ssh_argv) argv.push_back(const_cast(s.c_str())); argv.push_back(nullptr); int pipefd[2]; bool use_pipe = output && !interactive; if (use_pipe && pipe(pipefd) == -1) { perror("pipe"); return -1; } pid_t pid = fork(); if (pid == -1) { perror("fork"); return -1; } if (pid == 0) { // Child process if (use_pipe) { close(pipefd[0]); dup2(pipefd[1], STDOUT_FILENO); dup2(pipefd[1], STDERR_FILENO); close(pipefd[1]); } else if (silent && !interactive) { int devnull = open("/dev/null", O_WRONLY); dup2(devnull, STDOUT_FILENO); dup2(devnull, STDERR_FILENO); close(devnull); } if (!interactive) { setsid(); } execvp("ssh", argv.data()); perror("execvp ssh"); exit(-1); } else { // Parent process if (use_pipe) { close(pipefd[1]); std::ostringstream oss; char buf[4096]; ssize_t n; while ((n = read(pipefd[0], buf, sizeof(buf))) > 0) { oss.write(buf, n); } close(pipefd[0]); *output = oss.str(); } int status = 0; waitpid(pid, &status, 0); if (WIFEXITED(status)) { return WEXITSTATUS(status); } else { return -1; } } } else { int pipefd[2]; bool use_pipe = output && !interactive; if (use_pipe && pipe(pipefd) == -1) { perror("pipe"); return -1; } pid_t pid = fork(); if (pid == -1) { perror("fork"); return -1; } if (pid == 0) { // Child process if (!working_dir.empty()) { if (chdir(working_dir.c_str()) != 0) { perror("chdir"); exit(-1); } } // Set environment variables for (const auto& kv : env) { setenv(kv.first.c_str(), kv.second.c_str(), 1); } if (use_pipe) { close(pipefd[0]); dup2(pipefd[1], STDOUT_FILENO); dup2(pipefd[1], STDERR_FILENO); close(pipefd[1]); } else if (silent && !interactive) { int devnull = open("/dev/null", O_WRONLY); dup2(devnull, STDOUT_FILENO); dup2(devnull, STDERR_FILENO); close(devnull); } if (!interactive) { // Detach from terminal if not interactive setsid(); } std::vector argv; argv.push_back(const_cast(command.c_str())); for (const auto& arg : args) { argv.push_back(const_cast(arg.c_str())); } argv.push_back(nullptr); execvp(command.c_str(), argv.data()); perror("execvp"); exit(-1); } else { // Parent process if (use_pipe) { close(pipefd[1]); std::ostringstream oss; char buf[4096]; ssize_t n; while ((n = read(pipefd[0], buf, sizeof(buf))) > 0) { oss.write(buf, n); } close(pipefd[0]); *output = oss.str(); } int status = 0; waitpid(pid, &status, 0); if (WIFEXITED(status)) { return WEXITSTATUS(status); } else { return -1; } } } } } // namespace runner