From 1a9fcf925ed1aac7c5ac4786c7c48388ffdcf926 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= <nthiery@users.sf.net>
Date: Mon, 23 Nov 2015 12:53:12 +0100
Subject: [PATCH] =?UTF-8?q?Debarasse=20de=20popen=20en=20gerant=20la=20red?=
 =?UTF-8?q?irection=20=C3=A0=20la=20main?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../docker-compile-and-run.cpp                | 101 ++++++++++++------
 1 file changed, 66 insertions(+), 35 deletions(-)

diff --git a/test~coding~readingCppPrograms.fr/docker-compile-and-run.cpp b/test~coding~readingCppPrograms.fr/docker-compile-and-run.cpp
index bc0fde9..fe588f6 100644
--- a/test~coding~readingCppPrograms.fr/docker-compile-and-run.cpp
+++ b/test~coding~readingCppPrograms.fr/docker-compile-and-run.cpp
@@ -33,18 +33,26 @@ int system(string command) {
     std::system(command.c_str());
 }
 
-int exec(string cmd, const vector<string> args, const string in, const string out, const string err) {
-    cerr << "Running (exec): "+cmd;
+void report(string comment, string cmd, vector<string> args) {
+    cerr << comment;
+    cerr << cmd;
     for (auto arg: args)
         cerr << " " << arg;
     cerr << endl;
+}
+
+int cpp_exec(string cmd, const vector<string> args) {
     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());
+    return execv(cmd.c_str(), (char * const*)argv.data());
+}
+
+int exec(string cmd, const vector<string> args, const string in, const string out, const string err) {
+    report("exec: ", cmd, args);
 
     // Taken from man waitpid
     int status;
@@ -60,26 +68,20 @@ int exec(string cmd, const vector<string> args, const string in, const string ou
             dup2(fileno(f), STDIN_FILENO);
             fclose(f);
         }
-        execv(cmd.c_str(), (char * const*)argv.data());
-    }
-    do {
-        // TODO: this could be simplified for our purposes
-        w = waitpid(cpid, &status, WUNTRACED | WCONTINUED);
-        if (w == -1) {
-            perror("waitpid");
-            exit(EXIT_FAILURE);
-        }
-
-        if (WIFEXITED(status)) {
-            cerr << "exited, status=" << WEXITSTATUS(status) << endl;
-        } else if (WIFSIGNALED(status)) {
-            cerr << "killed by signal=" << WTERMSIG(status) << endl;
-        } else if (WIFSTOPPED(status)) {
-            cerr << "stopped by signal " << WSTOPSIG(status) << endl;
-        } else if (WIFCONTINUED(status)) {
-            cerr << "continued" << endl;
+        if ( out != "" ) {
+            FILE* f = fopen(in.c_str(), "w");
+            dup2(fileno(f), STDOUT_FILENO);
+            fclose(f);
         }
-    } while (!WIFEXITED(status) && !WIFSIGNALED(status));
+        cpp_exec(cmd, args);
+        perror("exec");
+        exit(EXIT_FAILURE);
+    }
+    w = waitpid(cpid, &status, 0);
+    if (w == -1) {
+        perror("waitpid");
+        exit(EXIT_FAILURE);
+    }
     return EXIT_SUCCESS;
 }
 
@@ -87,22 +89,49 @@ int exec(string cmd, const vector<string> args) {
     return exec(cmd, args, "", "", "");
 }
 
-std::string pexec(const string cmd) {
-    cerr << "Running (pexec): "+cmd << endl;
-    FILE* pipe = popen(cmd.c_str(), "r");
-    if (!pipe) return "ERROR";
+std::string pexec(const string cmd, vector<string> args) {
+    report("pexec: ", cmd, args);
+
+    int pipefd[2];
+    pid_t cpid;
+
+    if (pipe(pipefd) == -1) {
+        perror("pipe");
+        exit(EXIT_FAILURE);
+    }
+
+    cpid = fork();
+    if (cpid == -1) {
+        perror("fork");
+        exit(EXIT_FAILURE);
+    }
+
+    if (cpid == 0) {    /* Child writes to pipe */
+        close(pipefd[0]);          /* Close unused read end */
+        dup2(pipefd[1], STDOUT_FILENO);
+        cpp_exec(cmd, args);
+        perror("exec");
+        exit(EXIT_FAILURE);
+    }
+
+    close(pipefd[1]);          /* Close unused write end */
+
     char buffer[128];
     std::string result = "";
-    while (!feof(pipe)) {
-        if (fgets(buffer, 128, pipe) != NULL)
-            result += buffer;
+    int n;
+    while ((n = read(pipefd[0], buffer, sizeof(buffer))) > 0) {
+        buffer[n] = 0;
+        result += buffer;
     }
-    pclose(pipe);
+    wait(NULL);                /* Wait for child */
     return result;
 }
 
-string docker_run(string container, string command) {
-    string ID = pexec(docker + " run -d "+container+" "+command);
+string docker_run(string container, string cmd, vector<string> args) {
+    vector<string> docker_args = {"run", "-d", container, cmd};
+    for (auto arg: args)
+        docker_args.push_back(arg);
+    string ID = pexec(docker, docker_args);
     // 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;
@@ -124,10 +153,12 @@ void docker_cp(string docker_id, string source, string target) {
 }
 
 void docker_rm(string docker_id) {
-    exec(docker, {"rm", "-f", docker_id});
+    exec(docker, {"rm", "-f", docker_id}, "", "/dev/null", "");
 }
 
 int main(int argc, char **argv) {
+    //cout << pexec("/usr/bin/id", {}) << "|" << endl;
+
     //printf("egid: %d\n", getegid());
 
     //exec("/usr/bin/id", {});
@@ -140,8 +171,8 @@ int main(int argc, char **argv) {
 
     string program=argv[1];
 
-    string docker_id = docker_run("crosbymichael/build-essential", "sleep 1000");
-    // cout << "docker_id: " << docker_id << endl;
+    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 });
-- 
GitLab