#include #include #include #include #include #include #include "command.h" std::pair readCommand(const std::vector &args) { int pipefd[2]; if (pipe(pipefd) < 0) { throw std::runtime_error("readCommand: pipe: " + std::string{strerror(errno)}); } pid_t pid = fork(); if (pid < 0) { throw std::runtime_error("readCommand: fork: " + std::string{strerror(errno)}); } if (pid == 0) { close(STDOUT_FILENO); dup2(pipefd[1], STDOUT_FILENO); close(pipefd[0]); close(pipefd[1]); std::vector argv(args.size() + 1); for (size_t i = 0; i < args.size(); i++) { argv[i] = new char[args[i].size() + 1]; memcpy(argv[i], args[i].data(), args[i].size() + 1); } argv[args.size()] = nullptr; execvp(argv[0], argv.data()); perror("execvp"); exit(255); } close(pipefd[1]); std::string output; while (true) { size_t base = output.size(); output.resize(base + 4096); ssize_t nr = read(pipefd[0], output.data() + base, 4096); if (nr < 0) { if (errno == EINTR) { output.resize(base); continue; } kill(pid, SIGTERM); throw std::runtime_error("readCommand: read: " + std::string{strerror(errno)}); } output.resize(base + nr); if (nr == 0) break; } while (true) { int status; pid_t wpid = waitpid(pid, &status, 0); if (wpid < 0) { if (errno == EINTR) continue; kill(pid, SIGTERM); throw std::runtime_error("readCommand: wait: " + std::string{strerror(errno)}); } if (WIFEXITED(status)) { return std::make_pair(WEXITSTATUS(status), output); } } } std::string runCommand(const std::vector &args) { auto result = readCommand(args); if (result.first != 0) { std::string cmdline; for (const std::string &a : args) cmdline += " " + a; throw std::runtime_error( "Command exited with exit code " + std::to_string(result.first) + ":" + cmdline ); } return result.second; }