diff --git a/src/utils/execute.cpp b/src/utils/execute.cpp index b4a7c7e..8648695 100644 --- a/src/utils/execute.cpp +++ b/src/utils/execute.cpp @@ -32,7 +32,8 @@ bool execute_local_command_interactive(const sCommand &command, bool silent) return false; } else if (pid == 0) { // Child process - std::vector commandvec = {"bash", "-c", full_command.c_str(),NULL}; + ASSERT(full_command.find("'") == std::string::npos, "Raw command must not contain single quotes"); + std::vector commandvec = {"bash", "-c", halfquote(full_command).c_str(),NULL}; if (!silent) { std::cout << "Executing command: "; @@ -121,28 +122,17 @@ bool execute_ssh_command(const sSSHInfo &ssh_info, const sCommand &command, cMod 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); - } - + std::string cmdstr = command.construct_cmd(is_raw(mode) ? cStyle::Raw : cStyle::Safe); + ASSERT(cmdstr.find("'") == std::string::npos, "Raw command must not contain single quotes"); + cmdstr = "bash -c " + halfquote(cmdstr); sCommand ssh_command(ssh_cmd.str() + " " + cmdstr); bool rval = execute_local_command(ssh_command, mode, output); if (!rval) { std::cerr < -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace runner { - -namespace { - -// String trimming functions -void ltrim(std::string& s) { - s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) { - return !std::isspace(ch); - })); -} - -void rtrim(std::string& s) { - s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) { - return !std::isspace(ch); - }).base(), s.end()); -} - -void trim(std::string& s) { - ltrim(s); - rtrim(s); -} - -// Safe version that handles nullptr -void trim(std::string* s) { - if (s) { - trim(*s); - } -} - -ssh_session ssh_connect_and_auth(const sSSHInfo* sshinfo, const std::map& env, std::string* error) { - ssh_session session = ssh_new(); - if (!session) { - if (error) *error = "Failed to create SSH session."; - return nullptr; - } - ssh_options_set(session, SSH_OPTIONS_HOST, sshinfo->host.c_str()); - if (!sshinfo->port.empty()) { - int port = std::stoi(sshinfo->port); - ssh_options_set(session, SSH_OPTIONS_PORT, &port); - } - if (!sshinfo->user.empty()) { - ssh_options_set(session, SSH_OPTIONS_USER, sshinfo->user.c_str()); - } - int rc = ssh_connect(session); - if (rc != SSH_OK) { - if (error) *error = std::string("SSH connection failed: ") + ssh_get_error(session); - ssh_free(session); - return nullptr; - } - rc = ssh_userauth_publickey_auto(session, nullptr, nullptr); - if (rc != SSH_AUTH_SUCCESS) { - auto it = env.find("SSHPASS"); - if (it != env.end()) { - rc = ssh_userauth_password(session, nullptr, it->second.c_str()); - } - } - if (rc != SSH_AUTH_SUCCESS) { - if (error) *error = std::string("SSH authentication failed: ") + ssh_get_error(session); - ssh_disconnect(session); - ssh_free(session); - return nullptr; - } - return session; -} - -} // namespace runner - -// runner_local: non-interactive local command execution -bool runner_local::execute() { - pid_t pid = fork(); - if (pid == -1) { - std::cerr << "Failed to fork" << std::endl; - mReturnCode = -1; - return false; - } - if (pid == 0) { - // Child process - if (!mWorkingDir.empty()) { - if (chdir(mWorkingDir.c_str()) != 0) { - perror("chdir"); - exit(127); - } - } - // Set environment variables - for (const auto& [k, v] : mEnv) { - setenv(k.c_str(), v.c_str(), 1); - } - // Build argv - std::vector argv; - argv.push_back(const_cast(mCommand.c_str())); - for (auto& arg : mArgs) argv.push_back(const_cast(arg.c_str())); - argv.push_back(nullptr); - if (mSilent) { - int fd = open("/dev/null", O_WRONLY); - if (fd != -1) { - dup2(fd, STDOUT_FILENO); - dup2(fd, STDERR_FILENO); - close(fd); - } - } - - std::cout << "Executing command: " << mCommand << std::endl; - std::cout << "Args: "; - for (auto& arg : mArgs) std::cout << "[" << arg << "] "; - std::cout << std::endl; - - 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; - } -} - -// 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 argv; - argv.push_back(const_cast(mCommand.c_str())); - for (auto& arg : mArgs) argv.push_back(const_cast(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; - } -} - -// runner_ssh: non-interactive SSH command execution -bool runner_ssh::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; - 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_close(channel); - ssh_channel_free(channel); - ssh_disconnect(session); - ssh_free(session); - return mReturnCode == 0; -} - -// 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 \ No newline at end of file diff --git a/src/utils/runner.hpp b/src/utils/runner.hpp deleted file mode 100644 index c3effc6..0000000 --- a/src/utils/runner.hpp +++ /dev/null @@ -1,81 +0,0 @@ -#ifndef RUNNER_HPP -#define RUNNER_HPP - - -#include -#include -#include - -namespace runner { - -struct sSSHInfo { - std::string host; - std::string user; - std::string port; -}; - -class runner { - public: - runner(std::string command, std::vector args={}, std::string working_dir="", std::map env={}, bool silent=false) : - mCommand(command), - mArgs(args), - mWorkingDir(working_dir), - mEnv(env), - mSilent(silent), - mReturnCode(0) {} - virtual ~runner() {} - - virtual bool execute() = 0; - - int return_code() const { return mReturnCode; } - protected: - std::string mCommand; - std::vector mArgs; - std::string mWorkingDir; - std::map mEnv; - bool mSilent; - int mReturnCode; -}; - -class runner_local : public runner { - public: - runner_local(std::string command, std::vector args={}, std::string working_dir="", std::map env={}, bool silent=false) : - runner(command, args, working_dir, env, silent) {} - bool execute() override; -}; - -class runner_local_interactive : public runner { - public: - runner_local_interactive(std::string command, std::vector args={}, std::string working_dir="", std::map 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 args={}, std::string working_dir="", std::map 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 args={}, std::string working_dir="", std::map 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 args={}, std::string working_dir="", std::map env={}) : - runner_ssh(sshinfo, command, args, working_dir, env, true), mOutput(output) {} - bool execute() override; - protected: - std::string & mOutput; -}; - -} // namespace runner - -#endif // RUNNER_HPP \ No newline at end of file diff --git a/templates/simple-object-storage/ports.sh b/templates/simple-object-storage/ports.sh index deb0295..b3dbbc2 100644 --- a/templates/simple-object-storage/ports.sh +++ b/templates/simple-object-storage/ports.sh @@ -1,6 +1,6 @@ #!/bin/bash source "${AGENT_PATH}/_common.sh" -_check_required_env_vars +_check_required_env_vars "CONFIG_PATH" # PORT SCRIPT # The port script is OPTIONAL.