Skip to content
Snippets Groups Projects
docker-compile-and-run.cpp 3.47 KiB
Newer Older
  • Learn to ignore specific revisions
  • #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;
    }