This commit is contained in:
parent
f9dca5fea1
commit
dbcef96bc2
@ -134,11 +134,13 @@ std::string server_env_manager::get_variable(const std::string& name) const {
|
|||||||
|
|
||||||
bool server_env_manager::check_remote_dir_exists(const std::string &dir_path) const
|
bool server_env_manager::check_remote_dir_exists(const std::string &dir_path) const
|
||||||
{
|
{
|
||||||
return 0==runner::execute_cmd("test",{"-d", quote(dir_path)}, {}, {}, true, false, get_SSH_INFO());
|
runner::runner_ssh test_runner(get_SSH_INFO(),"test",{"-d", quote(dir_path)});
|
||||||
|
return test_runner.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool server_env_manager::check_remote_file_exists(const std::string& file_path) const {
|
bool server_env_manager::check_remote_file_exists(const std::string& file_path) const {
|
||||||
return 0==runner::execute_cmd("test",{"-f",quote(file_path)}, {}, {}, true, false, get_SSH_INFO());
|
runner::runner_ssh test_runner(get_SSH_INFO(),"test",{"-f",quote(file_path)});
|
||||||
|
return test_runner.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool server_env_manager::check_remote_items_exist(const std::vector<std::string> &file_paths) const
|
bool server_env_manager::check_remote_items_exist(const std::vector<std::string> &file_paths) const
|
||||||
@ -149,8 +151,8 @@ bool server_env_manager::check_remote_items_exist(const std::vector<std::string>
|
|||||||
file_paths_str += quote(file_path) + " ";
|
file_paths_str += quote(file_path) + " ";
|
||||||
}
|
}
|
||||||
// check if all items in the vector exist on the remote server, in a single command.
|
// check if all items in the vector exist on the remote server, in a single command.
|
||||||
|
runner::runner_ssh test_runner(get_SSH_INFO(),"bash",{"-c","for item in " + file_paths_str + "; do test -f $item; done"});
|
||||||
return 0==runner::execute_cmd("bash",{"-c","for item in " + file_paths_str + "; do test -f $item; done"}, {}, {}, true, false, get_SSH_INFO());
|
return test_runner.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool server_env_manager::run_remote_template_command(const std::string &service_name, const std::string &command, std::vector<std::string> args, bool silent, std::map<std::string, std::string> extra_env_vars, std::string * output) const
|
bool server_env_manager::run_remote_template_command(const std::string &service_name, const std::string &command, std::vector<std::string> args, bool silent, std::map<std::string, std::string> extra_env_vars, std::string * output) const
|
||||||
@ -177,7 +179,13 @@ bool server_env_manager::run_remote_template_command(const std::string &service_
|
|||||||
ASSERT(!output || !silent); // if output is captured, silent must be false
|
ASSERT(!output || !silent); // if output is captured, silent must be false
|
||||||
ASSERT(!interactive || !silent); // if command is ssh, silent must be false
|
ASSERT(!interactive || !silent); // if command is ssh, silent must be false
|
||||||
|
|
||||||
return 0==runner::execute_cmd("bash",{"-c", quote(script_path) + argstr}, working_dir, env_vars, silent, interactive, get_SSH_INFO(), output);
|
if (interactive) {
|
||||||
|
runner::runner_ssh_interactive bash_runner(get_SSH_INFO(),"bash",{"-c", quote(script_path) + argstr}, working_dir, env_vars);
|
||||||
|
return bash_runner.execute();
|
||||||
|
} else {
|
||||||
|
runner::runner_ssh bash_runner(get_SSH_INFO(),"bash",{"-c", quote(script_path) + argstr}, working_dir, env_vars, silent);
|
||||||
|
return bash_runner.execute();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// base64 <<< "FOO=BAR WHEE=YAY bash ./test.sh"
|
// base64 <<< "FOO=BAR WHEE=YAY bash ./test.sh"
|
||||||
|
@ -52,19 +52,24 @@ bool service_runner::install(bool silent) {
|
|||||||
if (!tinfo.is_set())
|
if (!tinfo.is_set())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Create service directory
|
|
||||||
if (0!=runner::execute_cmd("mkdir",{"-p",remotepath::service(mServer, mService)},"",{},true,false,mServerEnv.get_SSH_INFO()))
|
{ // Create service directory
|
||||||
|
runner::runner_ssh mkdir_runner(mServerEnv.get_SSH_INFO(),"mkdir",{"-p",remotepath::service(mServer, mService)});
|
||||||
|
if (!mkdir_runner.execute())
|
||||||
{
|
{
|
||||||
std::cerr << "Failed to create service directory " << remotepath::service(mServer, mService) << std::endl;
|
std::cerr << "Failed to create service directory " << remotepath::service(mServer, mService) << std::endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check if rsync is installed on remote host
|
{ // Check if rsync is installed on remote host
|
||||||
if (0!=runner::execute_cmd("which",{"rsync"},"",{},true,false,mServerEnv.get_SSH_INFO()))
|
runner::runner_ssh which_runner(mServerEnv.get_SSH_INFO(),"which",{"rsync"});
|
||||||
|
if (!which_runner.execute())
|
||||||
{
|
{
|
||||||
std::cerr << "rsync is not installed on the remote host" << std::endl;
|
std::cerr << "rsync is not installed on the remote host" << std::endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// make sure all shell files are executable
|
// make sure all shell files are executable
|
||||||
make_shell_files_executable(tinfo.local_template_path().string());
|
make_shell_files_executable(tinfo.local_template_path().string());
|
||||||
@ -125,8 +130,11 @@ bool service_runner::uninstall(bool silent) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 4. Remove the service directory from the server
|
// 4. Remove the service directory from the server
|
||||||
if (0!=runner::execute_cmd("rm -rf " + quote(remotepath::service(mServer, mService)), {}, "", {}, true, false, mServerEnv.get_SSH_INFO()))
|
{
|
||||||
|
runner::runner_ssh rm_runner(mServerEnv.get_SSH_INFO(),"rm",{"-rf",remotepath::service(mServer, mService)});
|
||||||
|
if (!rm_runner.execute())
|
||||||
std::cerr << "Failed to remove remote service directory at " << remotepath::service(mServer, mService) << std::endl;
|
std::cerr << "Failed to remove remote service directory at " << remotepath::service(mServer, mService) << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
std::cout << "Service " << mService << " successfully uninstalled from " << mServer << std::endl;
|
std::cout << "Service " << mService << " successfully uninstalled from " << mServer << std::endl;
|
||||||
return true;
|
return true;
|
||||||
@ -170,8 +178,11 @@ bool service_runner::fullnuke()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (0!=runner::execute_cmd("rm -rf " + quote(local_service_path), {}, "", {}, true, false, mServerEnv.get_SSH_INFO()))
|
{
|
||||||
|
runner::runner_local rm_runner("rm",{"-rf",quote(local_service_path)});
|
||||||
|
if (!rm_runner.execute())
|
||||||
std::cerr << "Failed to remove local service directory at " << local_service_path << std::endl;
|
std::cerr << "Failed to remove local service directory at " << local_service_path << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
std::cout << "Service " << mService << " successfully fully nuked from " << mServer << std::endl;
|
std::cout << "Service " << mService << " successfully fully nuked from " << mServer << std::endl;
|
||||||
return true;
|
return true;
|
||||||
@ -265,7 +276,6 @@ std::map<std::string, ServiceStatus> service_runner::get_all_services_status(std
|
|||||||
{
|
{
|
||||||
std::map<std::string, ServiceStatus> status;
|
std::map<std::string, ServiceStatus> status;
|
||||||
|
|
||||||
std::string command = "_allservicesstatus";
|
|
||||||
std::string service_name = "dropshell-agent";
|
std::string service_name = "dropshell-agent";
|
||||||
|
|
||||||
|
|
||||||
@ -275,13 +285,16 @@ std::map<std::string, ServiceStatus> service_runner::get_all_services_status(std
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string cmd_path = remotepath::service_template(server_name,service_name) + "/shared/";
|
std::string cmd_path = remotepath::service_template(server_name,service_name) + "/shared/_allservicesstatus.sh";
|
||||||
std::string output;
|
std::string output;
|
||||||
if (0!=runner::execute_cmd("bash",{cmd_path+command+".sh"}, cmd_path, {}, true, false, env.get_SSH_INFO(), &output))
|
{
|
||||||
|
runner::runner_ssh_capture bash_runner(env.get_SSH_INFO(),output,cmd_path);
|
||||||
|
if (!bash_runner.execute())
|
||||||
{
|
{
|
||||||
std::cerr << "Error: Failed to run command script at " << cmd_path << std::endl;
|
std::cerr << "Error: Failed to run command script at " << cmd_path << std::endl;
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::stringstream ss(output);
|
std::stringstream ss(output);
|
||||||
std::string line;
|
std::string line;
|
||||||
@ -390,7 +403,8 @@ bool service_runner::interactive_ssh(const std::string & server_name, const std:
|
|||||||
std::cerr << "Error: Invalid server environment file: " << server_name << std::endl;
|
std::cerr << "Error: Invalid server environment file: " << server_name << std::endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return 0==runner::execute_cmd("", {}, "", {}, false, true, env.get_SSH_INFO());
|
runner::runner_ssh_interactive ssh_runner(env.get_SSH_INFO(),command);
|
||||||
|
return ssh_runner.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
void service_runner::edit_server(const std::string &server_name)
|
void service_runner::edit_server(const std::string &server_name)
|
||||||
@ -438,7 +452,8 @@ bool service_runner::edit_file(const std::string &file_path)
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "Editing file: " << file_path << std::endl;
|
std::cout << "Editing file: " << file_path << std::endl;
|
||||||
return 0==runner::execute_cmd(editor_cmd, {file_path}, "", {}, false, true, nullptr);
|
runner::runner_local_interactive editor_runner(editor_cmd,{file_path});
|
||||||
|
return editor_runner.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool service_runner::interactive_ssh_service()
|
bool service_runner::interactive_ssh_service()
|
||||||
@ -544,7 +559,8 @@ bool service_runner::restore(std::string backup_file, bool silent)
|
|||||||
std::string remote_backup_file_path = remote_backups_dir + "/" + backup_file;
|
std::string remote_backup_file_path = remote_backups_dir + "/" + backup_file;
|
||||||
|
|
||||||
// Copy backup file from local to server
|
// Copy backup file from local to server
|
||||||
if (0!=runner::execute_cmd("scp", {quote(local_backup_file_path), mServerEnv.get_SSH_USER() + "@" + mServerEnv.get_SSH_HOST() + ":" + quote(remote_backup_file_path)}, "", {}, false, false, mServerEnv.get_SSH_INFO()))
|
runner::runner_local scp_runner("scp",{quote(local_backup_file_path), mServerEnv.get_SSH_USER() + "@" + mServerEnv.get_SSH_HOST() + ":" + quote(remote_backup_file_path)});
|
||||||
|
if (!scp_runner.execute())
|
||||||
{
|
{
|
||||||
std::cerr << "Failed to copy backup file from server" << std::endl;
|
std::cerr << "Failed to copy backup file from server" << std::endl;
|
||||||
return false;
|
return false;
|
||||||
@ -622,11 +638,14 @@ bool service_runner::backup(bool silent) {
|
|||||||
// Create backups directory on server if it doesn't exist
|
// Create backups directory on server if it doesn't exist
|
||||||
std::string remote_backups_dir = remotepath::backups(mServer);
|
std::string remote_backups_dir = remotepath::backups(mServer);
|
||||||
if (!silent) std::cout << "Remote backups directory on "<< mServer <<": " << remote_backups_dir << std::endl;
|
if (!silent) std::cout << "Remote backups directory on "<< mServer <<": " << remote_backups_dir << std::endl;
|
||||||
if (0!=runner::execute_cmd("mkdir", {"-p",quote(remote_backups_dir)}, "", {}, true, false, mServerEnv.get_SSH_INFO()))
|
{
|
||||||
|
runner::runner_ssh mkdir_runner(mServerEnv.get_SSH_INFO(),"mkdir",{"-p",quote(remote_backups_dir)});
|
||||||
|
if (!mkdir_runner.execute())
|
||||||
{
|
{
|
||||||
std::cerr << "Failed to create backups directory on server" << std::endl;
|
std::cerr << "Failed to create backups directory on server" << std::endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Create backups directory locally if it doesn't exist
|
// Create backups directory locally if it doesn't exist
|
||||||
std::string local_backups_dir = gConfig().get_local_backup_path();
|
std::string local_backups_dir = gConfig().get_local_backup_path();
|
||||||
@ -664,7 +683,8 @@ bool service_runner::backup(bool silent) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Copy backup file from server to local
|
// Copy backup file from server to local
|
||||||
if (0!=runner::execute_cmd("scp", {quote(remote_backup_file_path), quote(local_backup_file_path)}, "", {}, silent, false, mServerEnv.get_SSH_INFO()))
|
runner::runner_local scp_runner("scp",{"-P", mServerEnv.get_SSH_PORT(), mServerEnv.get_SSH_USER() + "@" + mServerEnv.get_SSH_HOST() + ":" + quote(remote_backup_file_path), quote(local_backup_file_path)});
|
||||||
|
if (!scp_runner.execute())
|
||||||
{
|
{
|
||||||
std::cerr << "Failed to copy backup file from server" << std::endl;
|
std::cerr << "Failed to copy backup file from server" << std::endl;
|
||||||
return false;
|
return false;
|
||||||
@ -681,15 +701,19 @@ bool service_runner::backup(bool silent) {
|
|||||||
cRemoteTempFolder::cRemoteTempFolder(const server_env_manager &server_env) : mServerEnv(server_env)
|
cRemoteTempFolder::cRemoteTempFolder(const server_env_manager &server_env) : mServerEnv(server_env)
|
||||||
{
|
{
|
||||||
std::string p = remotepath::temp_files(server_env.get_server_name()) + "/" + random_alphanumeric_string(10);
|
std::string p = remotepath::temp_files(server_env.get_server_name()) + "/" + random_alphanumeric_string(10);
|
||||||
if (0!=runner::execute_cmd("mkdir", {"-p",quote(p)}, "", {}, true, false, server_env.get_SSH_INFO()))
|
{
|
||||||
|
runner::runner_ssh mkdir_runner(server_env.get_SSH_INFO(),"mkdir",{"-p",quote(p)});
|
||||||
|
if (!mkdir_runner.execute())
|
||||||
std::cerr << "Failed to create temp directory on server" << std::endl;
|
std::cerr << "Failed to create temp directory on server" << std::endl;
|
||||||
else
|
else
|
||||||
mPath = p;
|
mPath = p;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cRemoteTempFolder::~cRemoteTempFolder()
|
cRemoteTempFolder::~cRemoteTempFolder()
|
||||||
{
|
{
|
||||||
if (0!=runner::execute_cmd("rm", {"-rf",quote(mPath)}, "", {}, true, false, mServerEnv.get_SSH_INFO()))
|
runner::runner_ssh rm_runner(mServerEnv.get_SSH_INFO(),"rm",{"-rf",quote(mPath)});
|
||||||
|
if (!rm_runner.execute())
|
||||||
std::cerr << "Failed to remove temp directory on server" << std::endl;
|
std::cerr << "Failed to remove temp directory on server" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -748,11 +772,10 @@ std::string service_runner::get_latest_backup_file(const std::string& server, co
|
|||||||
bool service_runner::rsync_copy(const std::string& local_path, const std::string& remote_path, bool silent) {
|
bool service_runner::rsync_copy(const std::string& local_path, const std::string& remote_path, bool silent) {
|
||||||
std::cout << "Copying: [LOCAL] " << local_path << std::endl << std::string(8,' ')<<"[REMOTE] " << remote_path << std::endl;
|
std::cout << "Copying: [LOCAL] " << local_path << std::endl << std::string(8,' ')<<"[REMOTE] " << remote_path << std::endl;
|
||||||
|
|
||||||
if (0 != runner::execute_cmd(
|
runner::runner_local rsync_runner("rsync", {"--delete","--mkpath","-zrpc","-e",quote("ssh -p " + mServerEnv.get_SSH_PORT()),local_path,
|
||||||
"rsync",
|
mServerEnv.get_SSH_USER()+"@"+mServerEnv.get_SSH_HOST()+":"+remote_path}, "", {}, true);
|
||||||
{"--delete","--mkpath","-zrpc","-e",quote("ssh -p " + mServerEnv.get_SSH_PORT()),local_path,
|
|
||||||
mServerEnv.get_SSH_USER()+"@"+mServerEnv.get_SSH_HOST()+":"+remote_path},
|
if (!rsync_runner.execute()) {
|
||||||
"", {}, true, false)) {
|
|
||||||
std::cerr << "Failed to copy files using rsync" << std::endl;
|
std::cerr << "Failed to copy files using rsync" << std::endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -77,364 +77,281 @@ ssh_session ssh_connect_and_auth(const sSSHInfo* sshinfo, const std::map<std::st
|
|||||||
return session;
|
return session;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ssh_build_remote_command(const std::string& command, const std::vector<std::string>& args, const std::string& working_dir, const std::map<std::string, std::string>& env) {
|
} // namespace runner
|
||||||
std::ostringstream remote_cmd;
|
|
||||||
for (const auto& kv : env) {
|
|
||||||
if (kv.first == "SSHPASS") continue;
|
|
||||||
remote_cmd << kv.first << "='" << kv.second << "' ";
|
|
||||||
}
|
|
||||||
if (!working_dir.empty()) {
|
|
||||||
remote_cmd << "cd '" << working_dir << "' && ";
|
|
||||||
}
|
|
||||||
remote_cmd << command;
|
|
||||||
for (const auto& arg : args) {
|
|
||||||
remote_cmd << " " << arg;
|
|
||||||
}
|
|
||||||
return remote_cmd.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
// // Utility function to escape special shell characters
|
// runner_local: non-interactive local command execution
|
||||||
// std::string escape_shell_arg(const std::string& arg) {
|
bool runner_local::execute() {
|
||||||
// std::ostringstream escaped;
|
|
||||||
// escaped << '"';
|
|
||||||
// for (char c : arg) {
|
|
||||||
// if (c == '"' || c == '\\' || c == '$' || c == '`') {
|
|
||||||
// escaped << '\\';
|
|
||||||
// }
|
|
||||||
// escaped << c;
|
|
||||||
// }
|
|
||||||
// escaped << '"';
|
|
||||||
// return escaped.str();
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // For non-interactive SSH, just build the command with args
|
|
||||||
// std::string ssh_build_command_only(const std::string& command, const std::vector<std::string>& args) {
|
|
||||||
// std::ostringstream remote_cmd;
|
|
||||||
// remote_cmd << command;
|
|
||||||
// for (const auto& arg : args) {
|
|
||||||
// remote_cmd << " " << arg;
|
|
||||||
// }
|
|
||||||
// return remote_cmd.str();
|
|
||||||
// }
|
|
||||||
|
|
||||||
int ssh_interactive_shell_session(ssh_session session, ssh_channel channel, const std::string& remote_cmd_str, const std::string& command, std::string* output) {
|
|
||||||
// Request a PTY with xterm-256color type for color support
|
|
||||||
// First try using default terminal settings - should work with libssh 0.9.0+
|
|
||||||
int rc = ssh_channel_request_pty(channel);
|
|
||||||
if (rc != SSH_OK) {
|
|
||||||
if (output) *output = std::string("Failed to request pty: ") + ssh_get_error(session);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to explicitly tell the server we want colors through additional means
|
|
||||||
// 1. Set TERM environment variable
|
|
||||||
rc = ssh_channel_request_env(channel, "TERM", "xterm-256color");
|
|
||||||
// Ignore errors - this is optional
|
|
||||||
|
|
||||||
// 2. Request a shell
|
|
||||||
rc = ssh_channel_request_shell(channel);
|
|
||||||
if (rc != SSH_OK) {
|
|
||||||
if (output) *output = std::string("Failed to request shell: ") + ssh_get_error(session);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct termios orig_termios, raw_termios;
|
|
||||||
tcgetattr(STDIN_FILENO, &orig_termios);
|
|
||||||
raw_termios = orig_termios;
|
|
||||||
cfmakeraw(&raw_termios);
|
|
||||||
tcsetattr(STDIN_FILENO, TCSANOW, &raw_termios);
|
|
||||||
|
|
||||||
if (!command.empty()) {
|
|
||||||
ssh_channel_write(channel, remote_cmd_str.c_str(), remote_cmd_str.size());
|
|
||||||
ssh_channel_write(channel, "\n", 1);
|
|
||||||
} else {
|
|
||||||
// Initialize bash with color support if no specific command
|
|
||||||
std::string init_cmd = "export TERM=xterm-256color && if [ -f ~/.bashrc ]; then source ~/.bashrc; fi";
|
|
||||||
ssh_channel_write(channel, init_cmd.c_str(), init_cmd.size());
|
|
||||||
ssh_channel_write(channel, "\n", 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
int maxfd = STDIN_FILENO > STDOUT_FILENO ? STDIN_FILENO : STDOUT_FILENO;
|
|
||||||
maxfd = maxfd > ssh_get_fd(session) ? maxfd : ssh_get_fd(session);
|
|
||||||
char buffer[4096];
|
|
||||||
bool done = false;
|
|
||||||
|
|
||||||
while (!done) {
|
|
||||||
fd_set fds_read;
|
|
||||||
FD_ZERO(&fds_read);
|
|
||||||
FD_SET(STDIN_FILENO, &fds_read);
|
|
||||||
FD_SET(ssh_get_fd(session), &fds_read);
|
|
||||||
|
|
||||||
int ret = select(maxfd + 1, &fds_read, nullptr, nullptr, nullptr);
|
|
||||||
if (ret < 0) break;
|
|
||||||
|
|
||||||
if (FD_ISSET(STDIN_FILENO, &fds_read)) {
|
|
||||||
ssize_t n = read(STDIN_FILENO, buffer, sizeof(buffer));
|
|
||||||
if (n > 0) {
|
|
||||||
ssh_channel_write(channel, buffer, n);
|
|
||||||
} else {
|
|
||||||
ssh_channel_send_eof(channel);
|
|
||||||
done = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FD_ISSET(ssh_get_fd(session), &fds_read)) {
|
|
||||||
int n = ssh_channel_read(channel, buffer, sizeof(buffer), 0);
|
|
||||||
if (n > 0) {
|
|
||||||
write(STDOUT_FILENO, buffer, n);
|
|
||||||
} else if (n == 0) {
|
|
||||||
done = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ssh_channel_is_closed(channel) || ssh_channel_is_eof(channel)) {
|
|
||||||
done = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tcsetattr(STDIN_FILENO, TCSANOW, &orig_termios);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ssh_exec_command(ssh_session session, ssh_channel channel, const std::string& remote_cmd_str, bool silent, std::string* output, const std::map<std::string, std::string>& env, const std::string& working_dir) {
|
|
||||||
// Build complete command with env, working_dir, and the command itself
|
|
||||||
std::ostringstream cmd_with_env;
|
|
||||||
|
|
||||||
// Create a simple, flat command that will work reliably
|
|
||||||
// Format: env VAR=value bash -c 'cd /path && command args'
|
|
||||||
|
|
||||||
// Start with env variables
|
|
||||||
if (!env.empty()) {
|
|
||||||
cmd_with_env << "env ";
|
|
||||||
for (const auto& kv : env) {
|
|
||||||
if (kv.first == "SSHPASS") continue;
|
|
||||||
cmd_with_env << kv.first << "=\"" << kv.second << "\" ";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use a single bash -c with the entire command inside single quotes
|
|
||||||
cmd_with_env << "bash -c '";
|
|
||||||
|
|
||||||
// Add cd if working directory specified
|
|
||||||
if (!working_dir.empty()) {
|
|
||||||
cmd_with_env << "cd " << working_dir << " && ";
|
|
||||||
}
|
|
||||||
cmd_with_env << remote_cmd_str;
|
|
||||||
|
|
||||||
// Close the single quote
|
|
||||||
cmd_with_env << "'";
|
|
||||||
|
|
||||||
std::string final_cmd = cmd_with_env.str();
|
|
||||||
|
|
||||||
std::cout << "Final remote command: " << final_cmd << std::endl;
|
|
||||||
|
|
||||||
int rc = ssh_channel_request_exec(channel, final_cmd.c_str());
|
|
||||||
if (rc != SSH_OK) {
|
|
||||||
std::string error = std::string("Failed to exec remote command: ") + ssh_get_error(session);
|
|
||||||
std::cerr << "SSH exec error: " << error << std::endl;
|
|
||||||
if (output) *output = error;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (output) {
|
|
||||||
std::ostringstream oss;
|
|
||||||
char buffer[4096];
|
|
||||||
int nbytes;
|
|
||||||
|
|
||||||
// Read from stdout
|
|
||||||
while ((nbytes = ssh_channel_read(channel, buffer, sizeof(buffer), 0)) > 0) {
|
|
||||||
oss.write(buffer, nbytes);
|
|
||||||
}
|
|
||||||
if (nbytes < 0) {
|
|
||||||
std::cerr << "Error reading from stdout" << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read from stderr
|
|
||||||
while ((nbytes = ssh_channel_read(channel, buffer, sizeof(buffer), 1)) > 0) {
|
|
||||||
oss.write(buffer, nbytes);
|
|
||||||
}
|
|
||||||
if (nbytes < 0) {
|
|
||||||
std::cerr << "Error reading from stderr" << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
*output = oss.str();
|
|
||||||
} else if (!silent) {
|
|
||||||
char buffer[4096];
|
|
||||||
int nbytes;
|
|
||||||
|
|
||||||
// Read from stdout
|
|
||||||
while ((nbytes = ssh_channel_read(channel, buffer, sizeof(buffer), 0)) > 0) {
|
|
||||||
write(1, buffer, nbytes);
|
|
||||||
}
|
|
||||||
if (nbytes < 0) {
|
|
||||||
std::cerr << "Error reading from stdout" << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read from stderr
|
|
||||||
while ((nbytes = ssh_channel_read(channel, buffer, sizeof(buffer), 1)) > 0) {
|
|
||||||
write(2, buffer, nbytes);
|
|
||||||
}
|
|
||||||
if (nbytes < 0) {
|
|
||||||
std::cerr << "Error reading from stderr" << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int local_execute_cmd(
|
|
||||||
const std::string& command,
|
|
||||||
const std::vector<std::string>& args,
|
|
||||||
const std::string& working_dir,
|
|
||||||
const std::map<std::string, std::string>& env,
|
|
||||||
bool silent,
|
|
||||||
bool interactive,
|
|
||||||
std::string* output
|
|
||||||
) {
|
|
||||||
std::cerr << "Local command: " << command << std::endl;
|
|
||||||
|
|
||||||
int pipefd[2];
|
|
||||||
bool use_pipe = output && !interactive;
|
|
||||||
if (use_pipe && pipe(pipefd) == -1) {
|
|
||||||
perror("pipe");
|
|
||||||
std::cerr << "Pipe error: " << strerror(errno) << std::endl;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
pid_t pid = fork();
|
pid_t pid = fork();
|
||||||
if (pid == -1) {
|
if (pid == -1) {
|
||||||
perror("fork");
|
std::cerr << "Failed to fork" << std::endl;
|
||||||
std::cerr << "Fork error: " << strerror(errno) << std::endl;
|
mReturnCode = -1;
|
||||||
return -1;
|
return false;
|
||||||
}
|
}
|
||||||
if (pid == 0) {
|
if (pid == 0) {
|
||||||
if (!working_dir.empty()) {
|
// Child process
|
||||||
if (chdir(working_dir.c_str()) != 0) {
|
if (!mWorkingDir.empty()) {
|
||||||
|
if (chdir(mWorkingDir.c_str()) != 0) {
|
||||||
perror("chdir");
|
perror("chdir");
|
||||||
std::cerr << "Chdir error: " << strerror(errno) << std::endl;
|
exit(127);
|
||||||
exit(-1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Set environment variables
|
||||||
for (const auto& kv : env) {
|
for (const auto& [k, v] : mEnv) {
|
||||||
setenv(kv.first.c_str(), kv.second.c_str(), 1);
|
setenv(k.c_str(), v.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) {
|
|
||||||
setsid();
|
|
||||||
}
|
}
|
||||||
|
// Build argv
|
||||||
std::vector<char*> argv;
|
std::vector<char*> argv;
|
||||||
argv.push_back(const_cast<char*>(command.c_str()));
|
argv.push_back(const_cast<char*>(mCommand.c_str()));
|
||||||
for (const auto& arg : args) {
|
for (auto& arg : mArgs) argv.push_back(const_cast<char*>(arg.c_str()));
|
||||||
argv.push_back(const_cast<char*>(arg.c_str()));
|
|
||||||
}
|
|
||||||
argv.push_back(nullptr);
|
argv.push_back(nullptr);
|
||||||
|
if (mSilent) {
|
||||||
std::cerr << "Local command: " << command << std::endl;
|
int fd = open("/dev/null", O_WRONLY);
|
||||||
for (const auto& arg : args) {
|
if (fd != -1) {
|
||||||
std::cerr << "Local arg: " << arg << std::endl;
|
dup2(fd, STDOUT_FILENO);
|
||||||
|
dup2(fd, STDERR_FILENO);
|
||||||
|
close(fd);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
execvp(command.c_str(), argv.data());
|
execvp(mCommand.c_str(), argv.data());
|
||||||
perror("execvp");
|
perror("execvp");
|
||||||
exit(-1);
|
exit(127);
|
||||||
} else {
|
} else {
|
||||||
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;
|
int status = 0;
|
||||||
waitpid(pid, &status, 0);
|
waitpid(pid, &status, 0);
|
||||||
std::cerr << "Waitpid status: " << status << std::endl;
|
|
||||||
if (WIFEXITED(status)) {
|
if (WIFEXITED(status)) {
|
||||||
return WEXITSTATUS(status);
|
mReturnCode = WEXITSTATUS(status);
|
||||||
} else {
|
} else {
|
||||||
return -1;
|
mReturnCode = -1;
|
||||||
}
|
}
|
||||||
|
return mReturnCode == 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // anonymous namespace
|
// runner_local_interactive: interactive local command execution
|
||||||
|
bool runner_local_interactive::execute() {
|
||||||
|
pid_t pid = fork();
|
||||||
|
if (pid == -1) {
|
||||||
|
std::cerr << "Failed to fork" << std::endl;
|
||||||
|
mReturnCode = -1;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (pid == 0) {
|
||||||
|
if (!mWorkingDir.empty()) {
|
||||||
|
if (chdir(mWorkingDir.c_str()) != 0) {
|
||||||
|
perror("chdir");
|
||||||
|
exit(127);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const auto& [k, v] : mEnv) {
|
||||||
|
setenv(k.c_str(), v.c_str(), 1);
|
||||||
|
}
|
||||||
|
std::vector<char*> argv;
|
||||||
|
argv.push_back(const_cast<char*>(mCommand.c_str()));
|
||||||
|
for (auto& arg : mArgs) argv.push_back(const_cast<char*>(arg.c_str()));
|
||||||
|
argv.push_back(nullptr);
|
||||||
|
// Attach to terminal (no redirection)
|
||||||
|
execvp(mCommand.c_str(), argv.data());
|
||||||
|
perror("execvp");
|
||||||
|
exit(127);
|
||||||
|
} else {
|
||||||
|
int status = 0;
|
||||||
|
waitpid(pid, &status, 0);
|
||||||
|
if (WIFEXITED(status)) {
|
||||||
|
mReturnCode = WEXITSTATUS(status);
|
||||||
|
} else {
|
||||||
|
mReturnCode = -1;
|
||||||
|
}
|
||||||
|
return mReturnCode == 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int execute_cmd(
|
// runner_ssh: non-interactive SSH command execution
|
||||||
const std::string& command,
|
bool runner_ssh::execute() {
|
||||||
const std::vector<std::string>& args,
|
|
||||||
const std::string& working_dir,
|
|
||||||
const std::map<std::string, std::string>& env,
|
|
||||||
const bool silent,
|
|
||||||
const bool interactive,
|
|
||||||
const copySSHPtr& sshinfo,
|
|
||||||
std::string* output
|
|
||||||
) {
|
|
||||||
if (sshinfo.valid()) {
|
|
||||||
std::string error;
|
std::string error;
|
||||||
ssh_session session = ssh_connect_and_auth(&sshinfo, env, &error);
|
ssh_session session = ssh_connect_and_auth(&mSSHInfo, mEnv, &error);
|
||||||
if (!session) {
|
if (!session) {
|
||||||
if (output) *output = error;
|
std::cerr << error << std::endl;
|
||||||
std::cerr << "SSH connection error: " << error << std::endl;
|
mReturnCode = -1;
|
||||||
return -1;
|
return false;
|
||||||
}
|
}
|
||||||
ssh_channel channel = ssh_channel_new(session);
|
ssh_channel channel = ssh_channel_new(session);
|
||||||
if (!channel) {
|
if (!channel) {
|
||||||
if (output) *output = "Failed to create SSH channel.";
|
std::cerr << "Failed to create SSH channel." << std::endl;
|
||||||
ssh_disconnect(session);
|
ssh_disconnect(session);
|
||||||
ssh_free(session);
|
ssh_free(session);
|
||||||
std::cerr << "SSH channel error: " << output->c_str() << std::endl;
|
mReturnCode = -1;
|
||||||
return -1;
|
return false;
|
||||||
}
|
}
|
||||||
int rc = ssh_channel_open_session(channel);
|
if (ssh_channel_open_session(channel) != SSH_OK) {
|
||||||
if (rc != SSH_OK) {
|
std::cerr << "Failed to open SSH channel: " << ssh_get_error(session) << std::endl;
|
||||||
if (output) *output = std::string("Failed to open SSH channel: ") + ssh_get_error(session);
|
|
||||||
ssh_channel_free(channel);
|
ssh_channel_free(channel);
|
||||||
ssh_disconnect(session);
|
ssh_disconnect(session);
|
||||||
ssh_free(session);
|
ssh_free(session);
|
||||||
std::cerr << "SSH channel open error: " << output->c_str() << std::endl;
|
mReturnCode = -1;
|
||||||
return -1;
|
return false;
|
||||||
}
|
}
|
||||||
|
std::stringstream cmd;
|
||||||
int ret = 0;
|
cmd << mCommand;
|
||||||
std::string remote_cmd_str = ssh_build_remote_command(command, args, working_dir, {});
|
for (const auto& arg : mArgs) {
|
||||||
if (interactive) {
|
cmd << " '" << arg << "'";
|
||||||
ret = ssh_interactive_shell_session(session, channel, remote_cmd_str, command, output);
|
|
||||||
} else {
|
|
||||||
// For non-interactive, handle working directory in ssh_exec_command
|
|
||||||
ret = ssh_exec_command(session, channel, remote_cmd_str, silent, output, env, working_dir);
|
|
||||||
}
|
}
|
||||||
|
int rc = ssh_channel_request_exec(channel, cmd.str().c_str());
|
||||||
|
if (rc != SSH_OK) {
|
||||||
|
std::cerr << "SSH exec failed: " << ssh_get_error(session) << std::endl;
|
||||||
|
ssh_channel_close(channel);
|
||||||
|
ssh_channel_free(channel);
|
||||||
|
ssh_disconnect(session);
|
||||||
|
ssh_free(session);
|
||||||
|
mReturnCode = -1;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
char buffer[256];
|
||||||
|
int nbytes;
|
||||||
|
while ((nbytes = ssh_channel_read(channel, buffer, sizeof(buffer), 0)) > 0) {
|
||||||
|
if (!mSilent) std::cout.write(buffer, nbytes);
|
||||||
|
}
|
||||||
|
mReturnCode = ssh_channel_get_exit_status(channel);
|
||||||
ssh_channel_send_eof(channel);
|
ssh_channel_send_eof(channel);
|
||||||
ssh_channel_close(channel);
|
ssh_channel_close(channel);
|
||||||
ssh_channel_free(channel);
|
ssh_channel_free(channel);
|
||||||
ssh_disconnect(session);
|
ssh_disconnect(session);
|
||||||
ssh_free(session);
|
ssh_free(session);
|
||||||
|
return mReturnCode == 0;
|
||||||
if (output) trim(output);
|
|
||||||
|
|
||||||
std::cerr << "SSH command execution result: " << ret << std::endl;
|
|
||||||
return ret;
|
|
||||||
} else {
|
|
||||||
int ret=local_execute_cmd(command, args, working_dir, env, silent, interactive, output);
|
|
||||||
if (output) trim(output);
|
|
||||||
|
|
||||||
std::cerr << "Local command execution result: " << ret << std::endl;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// runner_ssh_interactive: interactive SSH command execution
|
||||||
|
bool runner_ssh_interactive::execute() {
|
||||||
|
std::string error;
|
||||||
|
ssh_session session = ssh_connect_and_auth(&mSSHInfo, mEnv, &error);
|
||||||
|
if (!session) {
|
||||||
|
std::cerr << error << std::endl;
|
||||||
|
mReturnCode = -1;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ssh_channel channel = ssh_channel_new(session);
|
||||||
|
if (!channel) {
|
||||||
|
std::cerr << "Failed to create SSH channel." << std::endl;
|
||||||
|
ssh_disconnect(session);
|
||||||
|
ssh_free(session);
|
||||||
|
mReturnCode = -1;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (ssh_channel_open_session(channel) != SSH_OK) {
|
||||||
|
std::cerr << "Failed to open SSH channel: " << ssh_get_error(session) << std::endl;
|
||||||
|
ssh_channel_free(channel);
|
||||||
|
ssh_disconnect(session);
|
||||||
|
ssh_free(session);
|
||||||
|
mReturnCode = -1;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
std::stringstream cmd;
|
||||||
|
cmd << mCommand;
|
||||||
|
for (const auto& arg : mArgs) {
|
||||||
|
cmd << " '" << arg << "'";
|
||||||
|
}
|
||||||
|
int rc = ssh_channel_request_pty(channel);
|
||||||
|
if (rc != SSH_OK) {
|
||||||
|
std::cerr << "Failed to request PTY: " << ssh_get_error(session) << std::endl;
|
||||||
|
ssh_channel_close(channel);
|
||||||
|
ssh_channel_free(channel);
|
||||||
|
ssh_disconnect(session);
|
||||||
|
ssh_free(session);
|
||||||
|
mReturnCode = -1;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
rc = ssh_channel_request_shell(channel);
|
||||||
|
if (rc != SSH_OK) {
|
||||||
|
std::cerr << "Failed to request shell: " << ssh_get_error(session) << std::endl;
|
||||||
|
ssh_channel_close(channel);
|
||||||
|
ssh_channel_free(channel);
|
||||||
|
ssh_disconnect(session);
|
||||||
|
ssh_free(session);
|
||||||
|
mReturnCode = -1;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Forward input/output between user and SSH channel
|
||||||
|
fd_set fds;
|
||||||
|
char buffer[256];
|
||||||
|
while (true) {
|
||||||
|
FD_ZERO(&fds);
|
||||||
|
FD_SET(0, &fds); // stdin
|
||||||
|
int ssh_fd = ssh_get_fd(session);
|
||||||
|
FD_SET(ssh_fd, &fds);
|
||||||
|
int maxfd = std::max(0, ssh_fd) + 1;
|
||||||
|
int ret = select(maxfd, &fds, nullptr, nullptr, nullptr);
|
||||||
|
if (ret < 0) break;
|
||||||
|
if (FD_ISSET(0, &fds)) {
|
||||||
|
int n = read(0, buffer, sizeof(buffer));
|
||||||
|
if (n > 0) ssh_channel_write(channel, buffer, n);
|
||||||
|
}
|
||||||
|
if (FD_ISSET(ssh_fd, &fds)) {
|
||||||
|
int n = ssh_channel_read(channel, buffer, sizeof(buffer), 0);
|
||||||
|
if (n > 0) write(1, buffer, n);
|
||||||
|
else if (n == 0) break;
|
||||||
|
}
|
||||||
|
if (ssh_channel_is_closed(channel)) break;
|
||||||
|
}
|
||||||
|
mReturnCode = ssh_channel_get_exit_status(channel);
|
||||||
|
ssh_channel_send_eof(channel);
|
||||||
|
ssh_channel_close(channel);
|
||||||
|
ssh_channel_free(channel);
|
||||||
|
ssh_disconnect(session);
|
||||||
|
ssh_free(session);
|
||||||
|
return mReturnCode == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// runner_ssh_capture: SSH command execution with output capture
|
||||||
|
bool runner_ssh_capture::execute() {
|
||||||
|
std::string error;
|
||||||
|
ssh_session session = ssh_connect_and_auth(&mSSHInfo, mEnv, &error);
|
||||||
|
if (!session) {
|
||||||
|
std::cerr << error << std::endl;
|
||||||
|
mReturnCode = -1;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ssh_channel channel = ssh_channel_new(session);
|
||||||
|
if (!channel) {
|
||||||
|
std::cerr << "Failed to create SSH channel." << std::endl;
|
||||||
|
ssh_disconnect(session);
|
||||||
|
ssh_free(session);
|
||||||
|
mReturnCode = -1;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (ssh_channel_open_session(channel) != SSH_OK) {
|
||||||
|
std::cerr << "Failed to open SSH channel: " << ssh_get_error(session) << std::endl;
|
||||||
|
ssh_channel_free(channel);
|
||||||
|
ssh_disconnect(session);
|
||||||
|
ssh_free(session);
|
||||||
|
mReturnCode = -1;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
std::stringstream cmd;
|
||||||
|
cmd << mCommand;
|
||||||
|
for (const auto& arg : mArgs) {
|
||||||
|
cmd << " '" << arg << "'";
|
||||||
|
}
|
||||||
|
int rc = ssh_channel_request_exec(channel, cmd.str().c_str());
|
||||||
|
if (rc != SSH_OK) {
|
||||||
|
std::cerr << "SSH exec failed: " << ssh_get_error(session) << std::endl;
|
||||||
|
ssh_channel_close(channel);
|
||||||
|
ssh_channel_free(channel);
|
||||||
|
ssh_disconnect(session);
|
||||||
|
ssh_free(session);
|
||||||
|
mReturnCode = -1;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
char buffer[256];
|
||||||
|
int nbytes;
|
||||||
|
mOutput.clear();
|
||||||
|
while ((nbytes = ssh_channel_read(channel, buffer, sizeof(buffer), 0)) > 0) {
|
||||||
|
mOutput.append(buffer, nbytes);
|
||||||
|
}
|
||||||
|
mReturnCode = ssh_channel_get_exit_status(channel);
|
||||||
|
ssh_channel_send_eof(channel);
|
||||||
|
ssh_channel_close(channel);
|
||||||
|
ssh_channel_free(channel);
|
||||||
|
ssh_disconnect(session);
|
||||||
|
ssh_free(session);
|
||||||
|
return mReturnCode == 0;
|
||||||
|
}
|
||||||
} // namespace runner
|
} // namespace runner
|
@ -14,26 +14,67 @@ struct sSSHInfo {
|
|||||||
std::string port;
|
std::string port;
|
||||||
};
|
};
|
||||||
|
|
||||||
class copySSHPtr {
|
class runner {
|
||||||
public:
|
public:
|
||||||
copySSHPtr(const sSSHInfo* sshinfo) : mSSHInfo(sshinfo ? *sshinfo : sSSHInfo()) {}
|
runner(std::string command, std::vector<std::string> args={}, std::string working_dir="", std::map<std::string, std::string> env={}, bool silent=false) :
|
||||||
copySSHPtr(const sSSHInfo& sshinfo) : mSSHInfo(sshinfo) {}
|
mCommand(command),
|
||||||
bool valid() const { return !mSSHInfo.host.empty(); }
|
mArgs(args),
|
||||||
const sSSHInfo * operator&() const { return (valid() ? &mSSHInfo : nullptr); }
|
mWorkingDir(working_dir),
|
||||||
private:
|
mEnv(env),
|
||||||
sSSHInfo mSSHInfo;
|
mSilent(silent),
|
||||||
|
mReturnCode(0) {}
|
||||||
|
virtual ~runner() {}
|
||||||
|
|
||||||
|
virtual bool execute() = 0;
|
||||||
|
|
||||||
|
int return_code() const { return mReturnCode; }
|
||||||
|
protected:
|
||||||
|
std::string mCommand;
|
||||||
|
std::vector<std::string> mArgs;
|
||||||
|
std::string mWorkingDir;
|
||||||
|
std::map<std::string, std::string> mEnv;
|
||||||
|
bool mSilent;
|
||||||
|
int mReturnCode;
|
||||||
};
|
};
|
||||||
|
|
||||||
int execute_cmd(
|
class runner_local : public runner {
|
||||||
const std::string& command,
|
public:
|
||||||
const std::vector<std::string>& args,
|
runner_local(std::string command, std::vector<std::string> args={}, std::string working_dir="", std::map<std::string, std::string> env={}, bool silent=false) :
|
||||||
const std::string& working_dir,
|
runner(command, args, working_dir, env, silent) {}
|
||||||
const std::map<std::string, std::string>& env,
|
bool execute() override;
|
||||||
const bool silent,
|
};
|
||||||
const bool interactive,
|
|
||||||
const copySSHPtr& sshinfo = nullptr,
|
class runner_local_interactive : public runner {
|
||||||
std::string* output = nullptr
|
public:
|
||||||
);
|
runner_local_interactive(std::string command, std::vector<std::string> args={}, std::string working_dir="", std::map<std::string, std::string> env={}) :
|
||||||
|
runner(command, args, working_dir, env, false) {}
|
||||||
|
bool execute() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class runner_ssh : public runner {
|
||||||
|
public:
|
||||||
|
runner_ssh(const sSSHInfo sshinfo, std::string command, std::vector<std::string> args={}, std::string working_dir="", std::map<std::string, std::string> env={}, bool silent=false) :
|
||||||
|
runner(command, args, working_dir, env, silent), mSSHInfo(sshinfo) {}
|
||||||
|
bool execute() override;
|
||||||
|
protected:
|
||||||
|
const sSSHInfo mSSHInfo;
|
||||||
|
};
|
||||||
|
|
||||||
|
class runner_ssh_interactive : public runner_ssh {
|
||||||
|
public:
|
||||||
|
runner_ssh_interactive(const sSSHInfo sshinfo, std::string command, std::vector<std::string> args={}, std::string working_dir="", std::map<std::string, std::string> env={}, bool silent=true) :
|
||||||
|
runner_ssh(sshinfo, command, args, working_dir, env, silent) {}
|
||||||
|
bool execute() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class runner_ssh_capture : public runner_ssh {
|
||||||
|
public:
|
||||||
|
runner_ssh_capture(const sSSHInfo sshinfo, std::string output, std::string command, std::vector<std::string> args={}, std::string working_dir="", std::map<std::string, std::string> env={}) :
|
||||||
|
runner_ssh(sshinfo, command, args, working_dir, env, true), mOutput(output) {}
|
||||||
|
bool execute() override;
|
||||||
|
protected:
|
||||||
|
std::string & mOutput;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace runner
|
} // namespace runner
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user