#include <vector> #include <iostream> #include <cstdlib> #include <sstream> using namespace std; #include <unistd.h> #include <sys/types.h> /** * TODO: * - [ ] set tight resources limits * - [ ] make this into a program rather than a shell script for a minimum of safety **/ string compile_and_run = "compile-and-run.sh"; //string bin_dir = "/home/wims/public_html/bin/"; string bin_dir = ""; string docker = "/usr/bin/docker"; void usage () { cerr << "docker-compile-and-run [program.cpp]" << endl; cerr << endl; cerr << "Compiles and executes a c++ program within a sandbox." << endl; cerr << "The standard input and output is passed down to the program." << endl; cerr << "The exit status is that of the compiler." << endl; } int system(string command) { // cerr << "Running " << command << endl; std::system(command.c_str()); } #include <stdio.h> void exec(string cmd, const vector<string> args) { cerr << "Running (exec): "+cmd; for (auto arg: args) cerr << " " << arg; cerr << endl; vector<const char*> argv; argv.push_back(cmd.c_str()); for ( auto &s: args ) argv.push_back(s.c_str()); argv.push_back((char *) 0); const vector<const char *> argv2(argv.begin(), argv.end()); int pid = fork(); if (pid==0) { execv(cmd.c_str(), (char * const*)argv.data()); } } std::string pexec(const string cmd) { cerr << "Running (pexec): "+cmd << endl; FILE* pipe = popen(cmd.c_str(), "r"); if (!pipe) return "ERROR"; char buffer[128]; std::string result = ""; while (!feof(pipe)) { if (fgets(buffer, 128, pipe) != NULL) result += buffer; } pclose(pipe); return result; } string docker_run(string container, string command) { string ID = pexec(docker + " run -d "+container+" "+command); // see http://stackoverflow.com/questions/216823/whats-the-best-way-to-trim-stdstring ID.erase(ID.find_last_not_of(" \n\r\t")+1); return ID; } void docker_oldexec(string docker_id, string command) { string cmd = docker+" exec -i "+ docker_id+ " "+ command; cerr << "Running (docker_oldexec): "+cmd << endl; system(cmd); } void docker_exec(string docker_id, vector<string> args) { vector<string> docker_args = {"exec", "-i", docker_id}; for (auto arg: args) docker_args.push_back(arg); //docker_oldexec(docker_id, command); exec(docker, docker_args); } void docker_cp(string docker_id, string source, string target) { // See http://stackoverflow.com/questions/22907231/copying-files-from-host-to-docker-container // Better replace with 'docker cp' of docker 1.8 docker_oldexec(docker_id, " /bin/bash -c 'cat > "+target+"' < "+source); } void docker_rm(string docker_id) { exec(docker, {"rm", "-f", docker_id}); } int main(int argc, char **argv) { //printf("egid: %d\n", getegid()); //exec("/usr/bin/id", {}); //system("/usr/bin/id"); if (argc != 2) { usage(); return 0; } string program=argv[1]; string docker_id = docker_run("crosbymichael/build-essential", "sleep 1000"); // cout << "docker_id: " << docker_id << endl; docker_cp(docker_id, bin_dir+compile_and_run, compile_and_run); docker_cp(docker_id, program, program); docker_exec(docker_id, { "chmod", "700", compile_and_run }); docker_exec(docker_id, { "./"+compile_and_run, program}); //docker_oldexec(docker_id, "./"+compile_and_run+" "+program); docker_rm(docker_id); cout.flush(); return 0; }