You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

89 lines
3.1 KiB

#include "runner.hpp"
#include <array>
#include <cerrno>
#include <poll.h>
#include <spawn.h>
#include <system_error>
#include <unistd.h>
#include <wait.h>
namespace sk {
run_result runner::run_blocking(const program &program) {
int in_pipe[2];
int out_pipe[2];
int err_pipe[2];
if (pipe(in_pipe) == -1 || pipe(out_pipe) == -1 || pipe(err_pipe) == -1) {
throw std::system_error{errno, std::generic_category()};
}
posix_spawn_file_actions_t actions;
posix_spawn_file_actions_init(&actions);
posix_spawn_file_actions_addclose(&actions, in_pipe[1]);
posix_spawn_file_actions_addclose(&actions, out_pipe[0]);
posix_spawn_file_actions_addclose(&actions, err_pipe[0]);
posix_spawn_file_actions_adddup2(&actions, in_pipe[0], 0);
posix_spawn_file_actions_adddup2(&actions, out_pipe[1], 1);
posix_spawn_file_actions_adddup2(&actions, err_pipe[1], 2);
posix_spawn_file_actions_addclose(&actions, in_pipe[0]);
posix_spawn_file_actions_addclose(&actions, out_pipe[1]);
posix_spawn_file_actions_addclose(&actions, err_pipe[1]);
const char *const args[] = {"docker",
"run",
"--rm",
"-i",
"--pull=never",
"--cap-drop=ALL",
"--network=none",
"--memory=64m",
"--memory-swap=64m",
"--pids-limit=128",
program.image.c_str(),
nullptr};
pid_t pid;
int exit_code;
if (posix_spawnp(&pid, args[0], &actions, nullptr,
const_cast<char *const *>(args), nullptr) != 0) {
throw std::system_error{errno, std::generic_category()};
}
close(in_pipe[0]);
close(out_pipe[1]);
close(err_pipe[1]);
write(in_pipe[1], program.code.data(), program.code.size());
close(in_pipe[1]);
std::array<char, 1024> buffer{};
std::string out;
std::string err;
std::array<pollfd, 2> plist = {pollfd{out_pipe[0], POLLIN, 0},
pollfd{err_pipe[0], POLLIN, 0}};
while (poll(plist.data(), plist.size(), /*timeout*/ -1) > 0) {
if (plist[0].revents & POLLIN) {
ssize_t bytes_read =
read(out_pipe[0], buffer.data(), buffer.size());
if (bytes_read == -1) {
throw std::system_error{errno, std::generic_category()};
}
out.append(buffer.data(), bytes_read);
} else if (plist[1].revents & POLLIN) {
ssize_t bytes_read =
read(err_pipe[0], buffer.data(), buffer.size());
if (bytes_read == -1) {
throw std::system_error{errno, std::generic_category()};
}
err.append(buffer.data(), bytes_read);
} else {
break;
}
}
waitpid(pid, &exit_code, 0);
close(out_pipe[0]);
close(err_pipe[0]);
posix_spawn_file_actions_destroy(&actions);
return run_result{out, err};
}
}