Refactoring to use Docker sockets directly as well as fork() to call processes instead of opening shells
This commit is contained in:
parent
6635446438
commit
802550f6e7
9 changed files with 720 additions and 1229 deletions
122
src/process_runner.cpp
Normal file
122
src/process_runner.cpp
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
#include "process_runner.hpp"
|
||||
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <array>
|
||||
#include <poll.h>
|
||||
namespace {
|
||||
|
||||
struct Pipe {
|
||||
int read = -1;
|
||||
int write = -1;
|
||||
|
||||
~Pipe() {
|
||||
if (read != -1) close(read);
|
||||
if (write != -1) close(write);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
ProcessResult ProcessRunner::run(const std::vector<std::string>& args,
|
||||
const ProcessOptions& options) {
|
||||
ProcessResult result;
|
||||
if (args.empty()) {
|
||||
result.stderr_text = "No executable specified.";
|
||||
return result;
|
||||
}
|
||||
|
||||
Pipe stdout_pipe;
|
||||
Pipe stderr_pipe;
|
||||
if (!options.inherit_stdio && options.capture_stdout) {
|
||||
int fds[2];
|
||||
if (pipe(fds) != 0) {
|
||||
result.stderr_text = std::strerror(errno);
|
||||
return result;
|
||||
}
|
||||
stdout_pipe.read = fds[0];
|
||||
stdout_pipe.write = fds[1];
|
||||
}
|
||||
if (!options.inherit_stdio && options.capture_stderr) {
|
||||
int fds[2];
|
||||
if (pipe(fds) != 0) {
|
||||
result.stderr_text = std::strerror(errno);
|
||||
return result;
|
||||
}
|
||||
stderr_pipe.read = fds[0];
|
||||
stderr_pipe.write = fds[1];
|
||||
}
|
||||
|
||||
pid_t pid = fork();
|
||||
if (pid == -1) {
|
||||
result.stderr_text = std::strerror(errno);
|
||||
return result;
|
||||
}
|
||||
|
||||
if (pid == 0) {
|
||||
if (!options.inherit_stdio && options.capture_stdout) {
|
||||
if (dup2(stdout_pipe.write, STDOUT_FILENO) == -1) _exit(127);
|
||||
}
|
||||
if (!options.inherit_stdio && options.capture_stderr) {
|
||||
if (dup2(stderr_pipe.write, STDERR_FILENO) == -1) _exit(127);
|
||||
}
|
||||
if (stdout_pipe.read != -1) close(stdout_pipe.read);
|
||||
if (stdout_pipe.write != -1) close(stdout_pipe.write);
|
||||
if (stderr_pipe.read != -1) close(stderr_pipe.read);
|
||||
if (stderr_pipe.write != -1) close(stderr_pipe.write);
|
||||
|
||||
std::vector<char*> argv;
|
||||
argv.reserve(args.size() + 1);
|
||||
for (const auto& arg : args) argv.push_back(const_cast<char*>(arg.c_str()));
|
||||
argv.push_back(nullptr);
|
||||
execvp(argv[0], argv.data());
|
||||
_exit(127);
|
||||
}
|
||||
|
||||
if (stdout_pipe.write != -1) close(stdout_pipe.write);
|
||||
stdout_pipe.write = -1;
|
||||
if (stderr_pipe.write != -1) close(stderr_pipe.write);
|
||||
stderr_pipe.write = -1;
|
||||
std::array<char, 4096> buffer{};
|
||||
pollfd poll_fds[2]{};
|
||||
int active = 0;
|
||||
if (stdout_pipe.read != -1) poll_fds[active++] = {stdout_pipe.read, POLLIN, 0};
|
||||
if (stderr_pipe.read != -1) poll_fds[active++] = {stderr_pipe.read, POLLIN, 0};
|
||||
while (active > 0) {
|
||||
if (poll(poll_fds, static_cast<nfds_t>(active), -1) == -1) {
|
||||
if (errno == EINTR) continue;
|
||||
break;
|
||||
}
|
||||
for (int i = 0; i < active;) {
|
||||
if ((poll_fds[i].revents & (POLLIN | POLLHUP)) == 0) {
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
const ssize_t count = read(poll_fds[i].fd, buffer.data(), buffer.size());
|
||||
if (count > 0) {
|
||||
if (poll_fds[i].fd == stdout_pipe.read) result.stdout_text.append(buffer.data(), static_cast<std::size_t>(count));
|
||||
else result.stderr_text.append(buffer.data(), static_cast<std::size_t>(count));
|
||||
++i;
|
||||
} else {
|
||||
close(poll_fds[i].fd);
|
||||
poll_fds[i] = poll_fds[--active];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int status = 0;
|
||||
if (waitpid(pid, &status, 0) == -1) {
|
||||
result.stderr_text = std::strerror(errno);
|
||||
return result;
|
||||
}
|
||||
if (WIFEXITED(status)) {
|
||||
result.exit_code = WEXITSTATUS(status);
|
||||
} else if (WIFSIGNALED(status)) {
|
||||
result.signaled = true;
|
||||
result.signal = WTERMSIG(status);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue