diff --git a/runner/build.sh b/runner/build.sh index 89f35ac..96214ff 100755 --- a/runner/build.sh +++ b/runner/build.sh @@ -19,11 +19,6 @@ if ! pkg-config --exists openssl; then exit 1 fi -# Check for nlohmann_json -if ! pkg-config --exists nlohmann_json; then - echo "Warning: nlohmann_json not found via pkg-config. Make sure it is installed or available to CMake." >&2 -fi - BUILD_DIR=build mkdir -p "$BUILD_DIR" cd "$BUILD_DIR" @@ -32,7 +27,7 @@ cmake .. make -j$(nproc) if [ -f runner ]; then - echo "Build successful. Run ./build/runner BASE64COMMAND to test." + echo "Build successful. Run ./build/runner" else echo "Build failed. Check the output above for errors." exit 1 diff --git a/runner/runner.cpp b/runner/runner.cpp index 009ff54..d513eb8 100644 --- a/runner/runner.cpp +++ b/runner/runner.cpp @@ -6,6 +6,8 @@ #include #include +namespace runner { + int execute_cmd( const std::string& command, const std::vector& args, @@ -16,79 +18,162 @@ int execute_cmd( sSSHInfo* sshinfo, std::string* output ) { - // SSH execution is not implemented in this demo if (sshinfo) { - std::cerr << "Remote SSH execution is not implemented in this demo.\n"; - return -1; - } - - 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); - } - } + // Build remote command string + std::ostringstream remote_cmd; // Set environment variables for (const auto& kv : env) { - setenv(kv.first.c_str(), kv.second.c_str(), 1); + remote_cmd << kv.first << "='" << kv.second << "' "; } - 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); + // Change working directory + if (!working_dir.empty()) { + remote_cmd << "cd '" << working_dir << "' && "; } - if (!interactive) { - // Detach from terminal if not interactive - setsid(); - } - std::vector argv; - argv.push_back(const_cast(command.c_str())); + // Command and args + remote_cmd << command; for (const auto& arg : args) { - argv.push_back(const_cast(arg.c_str())); + 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); - 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 { + + 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; + } + } } -} \ No newline at end of file +} + + +} // namespace runner \ No newline at end of file diff --git a/runner/runner.h b/runner/runner.h index 70c5c89..5be59a5 100644 --- a/runner/runner.h +++ b/runner/runner.h @@ -3,6 +3,8 @@ #include #include +namespace runner { + struct sSSHInfo { std::string host; std::string user; @@ -18,4 +20,6 @@ int execute_cmd( bool interactive, sSSHInfo* sshinfo = nullptr, std::string* output = nullptr -); \ No newline at end of file +); + +} // namespace runner \ No newline at end of file diff --git a/runner/runner_demo.cpp b/runner/runner_demo.cpp index 36c858a..9f3fac6 100644 --- a/runner/runner_demo.cpp +++ b/runner/runner_demo.cpp @@ -11,53 +11,69 @@ #include #include -using json = nlohmann::json; +// using json = nlohmann::json; + +// std::string base64_decode(const std::string& encoded) { +// BIO* bio, *b64; +// int decodeLen = (encoded.length() * 3) / 4; +// std::string decoded(decodeLen, '\0'); +// bio = BIO_new_mem_buf(encoded.data(), encoded.length()); +// b64 = BIO_new(BIO_f_base64()); +// bio = BIO_push(b64, bio); +// BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL); +// int len = BIO_read(bio, &decoded[0], encoded.length()); +// decoded.resize(len > 0 ? len : 0); +// BIO_free_all(bio); +// return decoded; +// } + +// int main(int argc, char* argv[]) { +// if (argc != 2) { +// std::cerr << "Usage: runner BASE64COMMAND\n"; +// return -1; +// } +// std::string decoded = base64_decode(argv[1]); +// json j; +// try { +// j = json::parse(decoded); +// } catch (...) { +// std::cerr << "Invalid JSON in decoded command\n"; +// return -1; +// } +// std::string command = j.value("command", ""); +// std::vector args = j.value("args", std::vector{}); +// std::string working_dir = j.value("working_dir", ""); +// std::map env = j.value("env", std::map{}); +// bool silent = j.value("silent", false); +// bool interactive = j.value("interactive", false); +// sSSHInfo* sshinfo = nullptr; +// sSSHInfo ssh; +// if (j.contains("sshinfo")) { +// ssh.host = j["sshinfo"].value("host", ""); +// ssh.user = j["sshinfo"].value("user", ""); +// ssh.port = j["sshinfo"].value("port", ""); +// sshinfo = &ssh; +// } +// std::string output; +// int ret = execute_cmd(command, args, working_dir, env, silent, interactive, sshinfo, &output); +// if (!silent && !output.empty()) { +// std::cout << output; +// } +// return ret; +// } -std::string base64_decode(const std::string& encoded) { - BIO* bio, *b64; - int decodeLen = (encoded.length() * 3) / 4; - std::string decoded(decodeLen, '\0'); - bio = BIO_new_mem_buf(encoded.data(), encoded.length()); - b64 = BIO_new(BIO_f_base64()); - bio = BIO_push(b64, bio); - BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL); - int len = BIO_read(bio, &decoded[0], encoded.length()); - decoded.resize(len > 0 ? len : 0); - BIO_free_all(bio); - return decoded; -} int main(int argc, char* argv[]) { - if (argc != 2) { - std::cerr << "Usage: runner BASE64COMMAND\n"; - return -1; - } - std::string decoded = base64_decode(argv[1]); - json j; - try { - j = json::parse(decoded); - } catch (...) { - std::cerr << "Invalid JSON in decoded command\n"; - return -1; - } - std::string command = j.value("command", ""); - std::vector args = j.value("args", std::vector{}); - std::string working_dir = j.value("working_dir", ""); - std::map env = j.value("env", std::map{}); - bool silent = j.value("silent", false); - bool interactive = j.value("interactive", false); - sSSHInfo* sshinfo = nullptr; - sSSHInfo ssh; - if (j.contains("sshinfo")) { - ssh.host = j["sshinfo"].value("host", ""); - ssh.user = j["sshinfo"].value("user", ""); - ssh.port = j["sshinfo"].value("port", ""); - sshinfo = &ssh; - } - std::string output; - int ret = execute_cmd(command, args, working_dir, env, silent, interactive, sshinfo, &output); - if (!silent && !output.empty()) { - std::cout << output; - } - return ret; -} \ No newline at end of file + std::string command = "docker"; + std::vector args = {"exec", "-it", "squashkiwi", "/bin/bash"}; + std::string working_dir = "."; + std::map env = {}; + bool silent = false; + bool interactive = true; + runner::sSSHInfo ssh; + ssh.host = "10.10.10.13"; + ssh.user = "katie"; + ssh.port = "22"; + + runner::execute_cmd(command, args, working_dir, env, silent, interactive, &ssh); +} \ No newline at end of file