You are viewing a plain text version of this content. The canonical link for it is here.
Posted to common-commits@hadoop.apache.org by jl...@apache.org on 2018/05/08 20:37:11 UTC

[1/2] hadoop git commit: YARN-8207. Docker container launch use popen have risk of shell expansion. Contributed by Eric Yang.

Repository: hadoop
Updated Branches:
  refs/heads/trunk 6b96a73bb -> a2ea75642


http://git-wip-us.apache.org/repos/asf/hadoop/blob/a2ea7564/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/test/utils/test_docker_util.cc
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/test/utils/test_docker_util.cc b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/test/utils/test_docker_util.cc
index 35b7873..1096935 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/test/utils/test_docker_util.cc
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/test/utils/test_docker_util.cc
@@ -94,45 +94,68 @@ namespace ContainerExecutor {
       write_file(docker_command_file, contents);
     }
 
+    char* flatten(args *args) {
+      size_t string_len = 0;
+      size_t current_len = 0;
+      char *buffer = (char *) malloc(8192 * sizeof(char));
+      for (int i = 0; i < args->length; i++) {
+        string_len = strlen(args->data[i]);
+        if (string_len != 0) {
+          strncpy(buffer + current_len, args->data[i], string_len);
+          current_len = current_len + string_len;
+          if (args->length - 1 != i) {
+            strncpy(buffer + current_len, " ", 1);
+            current_len++;
+          }
+        }
+      }
+      buffer[current_len] = '\0';
+      return buffer;
+    }
+
     void run_docker_command_test(const std::vector<std::pair<std::string, std::string> > &file_cmd_vec,
                                  const std::vector<std::pair<std::string, int> > &bad_file_cmd_vec,
-                                 int (*docker_func)(const char *, const struct configuration *, char *, const size_t)) {
-      char tmp[8192];
+                                 int (*docker_func)(const char *, const struct configuration *, args *)) {
+      struct args tmp = ARGS_INITIAL_VALUE;
       std::vector<std::pair<std::string, std::string> >::const_iterator itr;
       for (itr = file_cmd_vec.begin(); itr != file_cmd_vec.end(); ++itr) {
-        memset(tmp, 0, 8192);
+        reset_args(&tmp);
         write_command_file(itr->first);
-        int ret = (*docker_func)(docker_command_file.c_str(), &container_executor_cfg, tmp, 8192);
+        int ret = (*docker_func)(docker_command_file.c_str(), &container_executor_cfg, &tmp);
         ASSERT_EQ(0, ret) << "error message: " << get_docker_error_message(ret) << " for input " << itr->first;
-        ASSERT_STREQ(itr->second.c_str(), tmp);
+        char *actual = flatten(&tmp);
+        ASSERT_STREQ(itr->second.c_str(), actual);
+        free(actual);
       }
 
       std::vector<std::pair<std::string, int> >::const_iterator itr2;
       for (itr2 = bad_file_cmd_vec.begin(); itr2 != bad_file_cmd_vec.end(); ++itr2) {
-        memset(tmp, 0, 8192);
+        reset_args(&tmp);
         write_command_file(itr2->first);
-        int ret = (*docker_func)(docker_command_file.c_str(), &container_executor_cfg, tmp, 8192);
+        int ret = (*docker_func)(docker_command_file.c_str(), &container_executor_cfg, &tmp);
         ASSERT_EQ(itr2->second, ret) << " for " << itr2->first << std::endl;
-        ASSERT_EQ(0, strlen(tmp));
       }
-      int ret = (*docker_func)("unknown-file", &container_executor_cfg, tmp, 8192);
+      reset_args(&tmp);
+      int ret = (*docker_func)("unknown-file", &container_executor_cfg, &tmp);
       ASSERT_EQ(static_cast<int>(INVALID_COMMAND_FILE), ret);
+      reset_args(&tmp);
     }
 
     void run_docker_run_helper_function(const std::vector<std::pair<std::string, std::string> > &file_cmd_vec,
-                                        int (*helper_func)(const struct configuration *, char *, const size_t)) {
+                                        int (*helper_func)(const struct configuration *, args *)) {
       std::vector<std::pair<std::string, std::string> >::const_iterator itr;
       for(itr = file_cmd_vec.begin(); itr != file_cmd_vec.end(); ++itr) {
         struct configuration cfg;
-        const int buff_len = 1024;
-        char buff[buff_len];
-        memset(buff, 0, buff_len);
+        struct args buff = ARGS_INITIAL_VALUE;
+        reset_args(&buff);
         write_command_file(itr->first);
         int ret = read_config(docker_command_file.c_str(), &cfg);
         if(ret == 0) {
-          ret = (*helper_func)(&cfg, buff, buff_len);
+          ret = (*helper_func)(&cfg, &buff);
+          char *actual = flatten(&buff);
           ASSERT_EQ(0, ret);
-          ASSERT_STREQ(itr->second.c_str(), buff);
+          ASSERT_STREQ(itr->second.c_str(), actual);
+          free(actual);
         }
       }
     }
@@ -142,12 +165,12 @@ namespace ContainerExecutor {
     std::vector<std::pair<std::string, std::string> > file_cmd_vec;
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
         "[docker-command-execution]\n  docker-command=inspect\n  format={{.State.Status}}\n  name=container_e1_12312_11111_02_000001",
-        "inspect --format={{.State.Status}} container_e1_12312_11111_02_000001"));
+        "/usr/bin/docker inspect --format={{.State.Status}} container_e1_12312_11111_02_000001"));
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
         "[docker-command-execution]\n  docker-command=inspect\n"
             "  format={{range(.NetworkSettings.Networks)}}{{.IPAddress}},{{end}}{{.Config.Hostname}}\n"
             "  name=container_e1_12312_11111_02_000001",
-        "inspect --format={{range(.NetworkSettings.Networks)}}{{.IPAddress}},{{end}}{{.Config.Hostname}} container_e1_12312_11111_02_000001"));
+        "/usr/bin/docker inspect --format={{range(.NetworkSettings.Networks)}}{{.IPAddress}},{{end}}{{.Config.Hostname}} container_e1_12312_11111_02_000001"));
 
     std::vector<std::pair<std::string, int> > bad_file_cmd_vec;
     bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
@@ -179,7 +202,7 @@ namespace ContainerExecutor {
     std::vector<std::pair<std::string, std::string> > file_cmd_vec;
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
         "[docker-command-execution]\n  docker-command=load\n  image=image-id",
-        "load --i='image-id' "));
+        "/usr/bin/docker load --i=image-id"));
 
     std::vector<std::pair<std::string, int> > bad_file_cmd_vec;
     bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
@@ -249,7 +272,7 @@ namespace ContainerExecutor {
     std::vector<std::pair<std::string, std::string> > file_cmd_vec;
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
         "[docker-command-execution]\n  docker-command=pull\n  image=image-id",
-        "pull 'image-id' "));
+        "/usr/bin/docker pull image-id"));
 
     std::vector<std::pair<std::string, int> > bad_file_cmd_vec;
     bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
@@ -269,7 +292,7 @@ namespace ContainerExecutor {
     file_cmd_vec.push_back(
         std::make_pair<std::string, std::string>(
             "[docker-command-execution]\n  docker-command=rm\n  name=container_e1_12312_11111_02_000001",
-            "rm container_e1_12312_11111_02_000001"));
+            "/usr/bin/docker rm container_e1_12312_11111_02_000001"));
 
     std::vector<std::pair<std::string, int> > bad_file_cmd_vec;
     bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
@@ -289,10 +312,10 @@ namespace ContainerExecutor {
     std::vector<std::pair<std::string, std::string> > file_cmd_vec;
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
         "[docker-command-execution]\n  docker-command=stop\n  name=container_e1_12312_11111_02_000001",
-        "stop container_e1_12312_11111_02_000001"));
+        "/usr/bin/docker stop container_e1_12312_11111_02_000001"));
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
         "[docker-command-execution]\n  docker-command=stop\n  name=container_e1_12312_11111_02_000001\ntime=25",
-        "stop --time=25 container_e1_12312_11111_02_000001"));
+        "/usr/bin/docker stop --time=25 container_e1_12312_11111_02_000001"));
 
     std::vector<std::pair<std::string, int> > bad_file_cmd_vec;
     bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
@@ -316,10 +339,10 @@ namespace ContainerExecutor {
     std::vector<std::pair<std::string, std::string> > file_cmd_vec;
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
         "[docker-command-execution]\n  docker-command=kill\n  name=container_e1_12312_11111_02_000001",
-        "kill container_e1_12312_11111_02_000001"));
+        "/usr/bin/docker kill container_e1_12312_11111_02_000001"));
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
         "[docker-command-execution]\n  docker-command=kill\n  name=container_e1_12312_11111_02_000001\nsignal=SIGQUIT",
-        "kill --signal=SIGQUIT container_e1_12312_11111_02_000001"));
+        "/usr/bin/docker kill --signal=SIGQUIT container_e1_12312_11111_02_000001"));
 
     std::vector<std::pair<std::string, int> > bad_file_cmd_vec;
     bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
@@ -361,7 +384,7 @@ namespace ContainerExecutor {
   TEST_F(TestDockerUtil, test_detach_container) {
     std::vector<std::pair<std::string, std::string> > file_cmd_vec;
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
-        "[docker-command-execution]\n  docker-command=run\n  detach=true", "-d "));
+        "[docker-command-execution]\n  docker-command=run\n  detach=true", "-d"));
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
         "[docker-command-execution]\n  docker-command=run", ""));
 
@@ -371,7 +394,7 @@ namespace ContainerExecutor {
   TEST_F(TestDockerUtil, test_rm_container) {
     std::vector<std::pair<std::string, std::string> > file_cmd_vec;
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
-        "[docker-command-execution]\n  docker-command=run\n  rm=true", "--rm "));
+        "[docker-command-execution]\n  docker-command=run\n  rm=true", "--rm"));
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
         "[docker-command-execution]\n  docker-command=run", ""));
 
@@ -381,7 +404,7 @@ namespace ContainerExecutor {
   TEST_F(TestDockerUtil, test_set_container_workdir) {
     std::vector<std::pair<std::string, std::string> > file_cmd_vec;
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
-        "[docker-command-execution]\n  docker-command=run\n  workdir=/tmp/test", "--workdir='/tmp/test' "));
+        "[docker-command-execution]\n  docker-command=run\n  workdir=/tmp/test", "--workdir=/tmp/test"));
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
         "[docker-command-execution]\n  docker-command=run", ""));
 
@@ -392,7 +415,7 @@ namespace ContainerExecutor {
     std::vector<std::pair<std::string, std::string> > file_cmd_vec;
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
         "[docker-command-execution]\n  docker-command=run\n  cgroup-parent=/sys/fs/cgroup/yarn",
-        "--cgroup-parent='/sys/fs/cgroup/yarn' "));
+        "--cgroup-parent=/sys/fs/cgroup/yarn"));
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
         "[docker-command-execution]\n  docker-command=run", ""));
 
@@ -402,7 +425,7 @@ namespace ContainerExecutor {
   TEST_F(TestDockerUtil, test_set_hostname) {
     std::vector<std::pair<std::string, std::string> > file_cmd_vec;
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
-        "[docker-command-execution]\n  docker-command=run\n  hostname=ctr-id", "--hostname='ctr-id' "));
+        "[docker-command-execution]\n  docker-command=run\n  hostname=ctr-id", "--hostname=ctr-id"));
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
         "[docker-command-execution]\n  docker-command=run", ""));
 
@@ -412,7 +435,7 @@ namespace ContainerExecutor {
   TEST_F(TestDockerUtil, test_set_group_add) {
     std::vector<std::pair<std::string, std::string> > file_cmd_vec;
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
-        "[docker-command-execution]\n  docker-command=run\n  group-add=1000,1001", "--group-add '1000' --group-add '1001' "));
+        "[docker-command-execution]\n  docker-command=run\n  group-add=1000,1001", "--group-add 1000 --group-add 1001"));
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
         "[docker-command-execution]\n  docker-command=run", ""));
 
@@ -421,15 +444,15 @@ namespace ContainerExecutor {
 
   TEST_F(TestDockerUtil, test_set_network) {
     struct configuration container_cfg;
-    const int buff_len = 1024;
-    char buff[buff_len];
+    struct args buff = ARGS_INITIAL_VALUE;
+    reset_args(&buff);
     int ret = 0;
     std::string container_executor_cfg_contents = "[docker]\n  docker.allowed.networks=sdn1,bridge";
     std::vector<std::pair<std::string, std::string> > file_cmd_vec;
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
-        "[docker-command-execution]\n  docker-command=run\n  net=bridge", "--net='bridge' "));
+        "[docker-command-execution]\n  docker-command=run\n  net=bridge", "--net=bridge"));
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
-        "[docker-command-execution]\n  docker-command=run\n  net=sdn1", "--net='sdn1' "));
+        "[docker-command-execution]\n  docker-command=run\n  net=sdn1", "--net=sdn1"));
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
         "[docker-command-execution]\n  docker-command=run", ""));
     write_container_executor_cfg(container_executor_cfg_contents);
@@ -441,15 +464,17 @@ namespace ContainerExecutor {
     }
     for (itr = file_cmd_vec.begin(); itr != file_cmd_vec.end(); ++itr) {
       struct configuration cmd_cfg;
-      memset(buff, 0, buff_len);
+      reset_args(&buff);
       write_command_file(itr->first);
       ret = read_config(docker_command_file.c_str(), &cmd_cfg);
       if (ret != 0) {
         FAIL();
       }
-      ret = set_network(&cmd_cfg, &container_cfg, buff, buff_len);
+      ret = set_network(&cmd_cfg, &container_cfg, &buff);
+      char *actual = flatten(&buff);
       ASSERT_EQ(0, ret);
-      ASSERT_STREQ(itr->second.c_str(), buff);
+      ASSERT_STREQ(itr->second.c_str(), actual);
+      free(actual);
     }
     struct configuration cmd_cfg_1;
     write_command_file("[docker-command-execution]\n  docker-command=run\n  net=sdn2");
@@ -457,10 +482,10 @@ namespace ContainerExecutor {
     if (ret != 0) {
       FAIL();
     }
-    strcpy(buff, "test string");
-    ret = set_network(&cmd_cfg_1, &container_cfg, buff, buff_len);
+    reset_args(&buff);
+    ret = set_network(&cmd_cfg_1, &container_cfg, &buff);
     ASSERT_EQ(INVALID_DOCKER_NETWORK, ret);
-    ASSERT_EQ(0, strlen(buff));
+    ASSERT_EQ(0, buff.length);
 
     container_executor_cfg_contents = "[docker]\n";
     write_container_executor_cfg(container_executor_cfg_contents);
@@ -468,16 +493,15 @@ namespace ContainerExecutor {
     if (ret != 0) {
       FAIL();
     }
-    strcpy(buff, "test string");
-    ret = set_network(&cmd_cfg_1, &container_cfg, buff, buff_len);
+    reset_args(&buff);
+    ret = set_network(&cmd_cfg_1, &container_cfg, &buff);
     ASSERT_EQ(INVALID_DOCKER_NETWORK, ret);
-    ASSERT_EQ(0, strlen(buff));
+    ASSERT_EQ(0, buff.length);
   }
 
   TEST_F(TestDockerUtil, test_set_pid_namespace) {
     struct configuration container_cfg, cmd_cfg;
-    const int buff_len = 1024;
-    char buff[buff_len];
+    struct args buff = ARGS_INITIAL_VALUE;
     int ret = 0;
     std::string container_executor_cfg_contents[] = {"[docker]\n  docker.host-pid-namespace.enabled=1",
                                                      "[docker]\n  docker.host-pid-namespace.enabled=true",
@@ -490,7 +514,7 @@ namespace ContainerExecutor {
     std::vector<std::pair<std::string, std::string> >::const_iterator itr;
     std::vector<std::pair<std::string, int> >::const_iterator itr2;
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
-        "[docker-command-execution]\n  docker-command=run\n  pid=host", "--pid='host' "));
+        "[docker-command-execution]\n  docker-command=run\n  pid=host", "--pid='host'"));
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
         "[docker-command-execution]\n  docker-command=run", ""));
     bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
@@ -505,26 +529,28 @@ namespace ContainerExecutor {
         FAIL();
       }
       for (itr = file_cmd_vec.begin(); itr != file_cmd_vec.end(); ++itr) {
-        memset(buff, 0, buff_len);
+        reset_args(&buff);
         write_command_file(itr->first);
         ret = read_config(docker_command_file.c_str(), &cmd_cfg);
         if (ret != 0) {
           FAIL();
         }
-        ret = set_pid_namespace(&cmd_cfg, &container_cfg, buff, buff_len);
+        ret = set_pid_namespace(&cmd_cfg, &container_cfg, &buff);
+        char *actual = flatten(&buff);
         ASSERT_EQ(0, ret);
-        ASSERT_STREQ(itr->second.c_str(), buff);
+        ASSERT_STREQ(itr->second.c_str(), actual);
+        free(actual);
       }
       for (itr2 = bad_file_cmd_vec.begin(); itr2 != bad_file_cmd_vec.end(); ++itr2) {
-        memset(buff, 0, buff_len);
+        reset_args(&buff);
         write_command_file(itr2->first);
         ret = read_config(docker_command_file.c_str(), &cmd_cfg);
         if (ret != 0) {
           FAIL();
         }
-        ret = set_pid_namespace(&cmd_cfg, &container_cfg, buff, buff_len);
+        ret = set_pid_namespace(&cmd_cfg, &container_cfg, &buff);
         ASSERT_EQ(itr2->second, ret);
-        ASSERT_EQ(0, strlen(buff));
+        ASSERT_EQ(0, buff.length);
       }
     }
 
@@ -539,15 +565,16 @@ namespace ContainerExecutor {
       file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
           "[docker-command-execution]\n  docker-command=run", ""));
       for (itr = file_cmd_vec.begin(); itr != file_cmd_vec.end(); ++itr) {
-        memset(buff, 0, buff_len);
         write_command_file(itr->first);
         ret = read_config(docker_command_file.c_str(), &cmd_cfg);
         if (ret != 0) {
           FAIL();
         }
-        ret = set_pid_namespace(&cmd_cfg, &container_cfg, buff, buff_len);
+        ret = set_pid_namespace(&cmd_cfg, &container_cfg, &buff);
+        char *actual = flatten(&buff);
         ASSERT_EQ(0, ret);
-        ASSERT_STREQ(itr->second.c_str(), buff);
+        ASSERT_STREQ(itr->second.c_str(), actual);
+        free(actual);
       }
       bad_file_cmd_vec.clear();
       bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
@@ -557,15 +584,15 @@ namespace ContainerExecutor {
         "[docker-command-execution]\n  docker-command=run\n pid=host",
         static_cast<int>(PID_HOST_DISABLED)));
       for (itr2 = bad_file_cmd_vec.begin(); itr2 != bad_file_cmd_vec.end(); ++itr2) {
-        memset(buff, 0, buff_len);
+        reset_args(&buff);
         write_command_file(itr2->first);
         ret = read_config(docker_command_file.c_str(), &cmd_cfg);
         if (ret != 0) {
           FAIL();
         }
-        ret = set_pid_namespace(&cmd_cfg, &container_cfg, buff, buff_len);
+        ret = set_pid_namespace(&cmd_cfg, &container_cfg, &buff);
         ASSERT_EQ(itr2->second, ret);
-        ASSERT_EQ(0, strlen(buff));
+        ASSERT_EQ(0, buff.length);
       }
     }
   }
@@ -610,8 +637,7 @@ namespace ContainerExecutor {
 
   TEST_F(TestDockerUtil, test_set_privileged) {
     struct configuration container_cfg, cmd_cfg;
-    const int buff_len = 1024;
-    char buff[buff_len];
+    struct args buff = ARGS_INITIAL_VALUE;
     int ret = 0;
     std::string container_executor_cfg_contents[] = {"[docker]\n  docker.privileged-containers.enabled=1\n  docker.privileged-containers.registries=hadoop",
                                                      "[docker]\n  docker.privileged-containers.enabled=true\n  docker.privileged-containers.registries=hadoop",
@@ -639,24 +665,25 @@ namespace ContainerExecutor {
         FAIL();
       }
       for (itr = file_cmd_vec.begin(); itr != file_cmd_vec.end(); ++itr) {
-        memset(buff, 0, buff_len);
+        reset_args(&buff);
         write_command_file(itr->first);
         ret = read_config(docker_command_file.c_str(), &cmd_cfg);
         if (ret != 0) {
           FAIL();
         }
-        ret = set_privileged(&cmd_cfg, &container_cfg, buff, buff_len);
+        ret = set_privileged(&cmd_cfg, &container_cfg, &buff);
         ASSERT_EQ(6, ret);
-        ASSERT_EQ(0, strlen(buff));
+        ASSERT_EQ(0, buff.length);
       }
       write_command_file("[docker-command-execution]\n docker-command=run\n  user=nobody\n privileged=true\n image=nothadoop/image");
       ret = read_config(docker_command_file.c_str(), &cmd_cfg);
       if (ret != 0) {
         FAIL();
       }
-      ret = set_privileged(&cmd_cfg, &container_cfg, buff, buff_len);
+      reset_args(&buff);
+      ret = set_privileged(&cmd_cfg, &container_cfg, &buff);
       ASSERT_EQ(PRIVILEGED_CONTAINERS_DISABLED, ret);
-      ASSERT_EQ(0, strlen(buff));
+      ASSERT_EQ(0, buff.length);
     }
 
 
@@ -671,31 +698,32 @@ namespace ContainerExecutor {
       file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
           "[docker-command-execution]\n  docker-command=run\n  user=root\n privileged=false", ""));
       for (itr = file_cmd_vec.begin(); itr != file_cmd_vec.end(); ++itr) {
-        memset(buff, 0, buff_len);
+        reset_args(&buff);
         write_command_file(itr->first);
         ret = read_config(docker_command_file.c_str(), &cmd_cfg);
         if (ret != 0) {
           FAIL();
         }
-        ret = set_privileged(&cmd_cfg, &container_cfg, buff, buff_len);
+        ret = set_privileged(&cmd_cfg, &container_cfg, &buff);
+        char *actual = flatten(&buff);
         ASSERT_EQ(0, ret);
-        ASSERT_STREQ(itr->second.c_str(), buff);
+        ASSERT_STREQ(itr->second.c_str(), actual);
+        free(actual);
       }
       write_command_file("[docker-command-execution]\n  docker-command=run\n  user=root\n privileged=true");
       ret = read_config(docker_command_file.c_str(), &cmd_cfg);
       if (ret != 0) {
         FAIL();
       }
-      ret = set_privileged(&cmd_cfg, &container_cfg, buff, buff_len);
+      ret = set_privileged(&cmd_cfg, &container_cfg, &buff);
       ASSERT_EQ(PRIVILEGED_CONTAINERS_DISABLED, ret);
-      ASSERT_EQ(0, strlen(buff));
+      ASSERT_EQ(0, buff.length);
     }
   }
 
   TEST_F(TestDockerUtil, test_set_capabilities) {
     struct configuration container_cfg, cmd_cfg;
-    const int buff_len = 1024;
-    char buff[buff_len];
+    struct args buff = ARGS_INITIAL_VALUE;
     int ret = 0;
     std::string container_executor_cfg_contents = "[docker]\n"
         "  docker.allowed.capabilities=CHROOT,MKNOD\n"
@@ -703,19 +731,19 @@ namespace ContainerExecutor {
     std::vector<std::pair<std::string, std::string> > file_cmd_vec;
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
         "[docker-command-execution]\n  docker-command=run\n  image=hadoop/docker-image\n  cap-add=CHROOT,MKNOD",
-        "--cap-drop='ALL' --cap-add='CHROOT' --cap-add='MKNOD' "));
+        "--cap-drop=ALL --cap-add=CHROOT --cap-add=MKNOD"));
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
         "[docker-command-execution]\n  docker-command=run\n image=nothadoop/docker-image\n  cap-add=CHROOT,MKNOD",
-        "--cap-drop='ALL' "));
+        "--cap-drop=ALL"));
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
         "[docker-command-execution]\n  docker-command=run\n  image=hadoop/docker-image\n  cap-add=CHROOT",
-        "--cap-drop='ALL' --cap-add='CHROOT' "));
+        "--cap-drop=ALL --cap-add=CHROOT"));
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
         "[docker-command-execution]\n  docker-command=run\n  image=hadoop/docker-image\n",
-        "--cap-drop='ALL' "));
+        "--cap-drop=ALL"));
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
         "[docker-command-execution]\n  docker-command=run\n image=nothadoop/docker-image\n",
-        "--cap-drop='ALL' "));
+        "--cap-drop=ALL"));
     write_container_executor_cfg(container_executor_cfg_contents);
     ret = read_config(container_executor_cfg_file.c_str(), &container_cfg);
 
@@ -724,25 +752,26 @@ namespace ContainerExecutor {
       FAIL();
     }
     for (itr = file_cmd_vec.begin(); itr != file_cmd_vec.end(); ++itr) {
-      memset(buff, 0, buff_len);
+      reset_args(&buff);
       write_command_file(itr->first);
       ret = read_config(docker_command_file.c_str(), &cmd_cfg);
       if (ret != 0) {
         FAIL();
       }
-      ret = set_capabilities(&cmd_cfg, &container_cfg, buff, buff_len);
+      ret = set_capabilities(&cmd_cfg, &container_cfg, &buff);
+      char *actual = flatten(&buff);
       ASSERT_EQ(0, ret);
-      ASSERT_STREQ(itr->second.c_str(), buff);
+      ASSERT_STREQ(itr->second.c_str(), actual);
+      free(actual);
     }
     write_command_file("[docker-command-execution]\n  docker-command=run\n  image=hadoop/docker-image\n  cap-add=SETGID");
     ret = read_config(docker_command_file.c_str(), &cmd_cfg);
     if (ret != 0) {
       FAIL();
     }
-    strcpy(buff, "test string");
-    ret = set_capabilities(&cmd_cfg, &container_cfg, buff, buff_len);
+    reset_args(&buff);
+    ret = set_capabilities(&cmd_cfg, &container_cfg, &buff);
     ASSERT_EQ(INVALID_DOCKER_CAPABILITY, ret);
-    ASSERT_EQ(0, strlen(buff));
 
     container_executor_cfg_contents = "[docker]\n  docker.privileged-containers.registries=hadoop\n";
     write_container_executor_cfg(container_executor_cfg_contents);
@@ -750,16 +779,15 @@ namespace ContainerExecutor {
     if (ret != 0) {
       FAIL();
     }
-    strcpy(buff, "test string");
-    ret = set_capabilities(&cmd_cfg, &container_cfg, buff, buff_len);
+    reset_args(&buff);
+    ret = set_capabilities(&cmd_cfg, &container_cfg, &buff);
     ASSERT_EQ(INVALID_DOCKER_CAPABILITY, ret);
-    ASSERT_EQ(0, strlen(buff));
   }
 
   TEST_F(TestDockerUtil, test_set_devices) {
     struct configuration container_cfg, cmd_cfg;
-    const int buff_len = 1024;
-    char buff[buff_len];
+    struct args buff = ARGS_INITIAL_VALUE;
+    reset_args(&buff);
     int ret = 0;
     std::string container_executor_cfg_contents = "[docker]\n"
         "  docker.privileged-containers.registries=hadoop\n"
@@ -767,22 +795,22 @@ namespace ContainerExecutor {
     std::vector<std::pair<std::string, std::string> > file_cmd_vec;
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
         "[docker-command-execution]\n  docker-command=run\n  image=hadoop/image\n  devices=/dev/test-device:/dev/test-device",
-        "--device='/dev/test-device:/dev/test-device' "));
+        "--device=/dev/test-device:/dev/test-device"));
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
         "[docker-command-execution]\n  docker-command=run\n  image=hadoop/image\n  devices=/dev/device2:/dev/device2",
-        "--device='/dev/device2:/dev/device2' "));
+        "--device=/dev/device2:/dev/device2"));
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
         "[docker-command-execution]\n  docker-command=run\n  image=hadoop/image\n"
             "  devices=/dev/test-device:/dev/test-device,/dev/device2:/dev/device2",
-        "--device='/dev/test-device:/dev/test-device' --device='/dev/device2:/dev/device2' "));
+        "--device=/dev/test-device:/dev/test-device --device=/dev/device2:/dev/device2"));
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
         "[docker-command-execution]\n  docker-command=run\n  image=hadoop/image\n"
             "devices=/dev/nvidiactl:/dev/nvidiactl",
-        "--device='/dev/nvidiactl:/dev/nvidiactl' "));
+        "--device=/dev/nvidiactl:/dev/nvidiactl"));
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
         "[docker-command-execution]\n  docker-command=run\n  image=hadoop/image\n"
             "devices=/dev/nvidia1:/dev/nvidia1,/dev/gpu-uvm-tools:/dev/gpu-uvm-tools",
-        "--device='/dev/nvidia1:/dev/nvidia1' --device='/dev/gpu-uvm-tools:/dev/gpu-uvm-tools' "));
+        "--device=/dev/nvidia1:/dev/nvidia1 --device=/dev/gpu-uvm-tools:/dev/gpu-uvm-tools"));
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
         "[docker-command-execution]\n  docker-command=run\n  image=hadoop/image", ""));
     write_container_executor_cfg(container_executor_cfg_contents);
@@ -793,75 +821,77 @@ namespace ContainerExecutor {
       FAIL();
     }
     for (itr = file_cmd_vec.begin(); itr != file_cmd_vec.end(); ++itr) {
-      memset(buff, 0, buff_len);
+      reset_args(&buff);
       write_command_file(itr->first);
       ret = read_config(docker_command_file.c_str(), &cmd_cfg);
       if (ret != 0) {
         FAIL();
       }
-      ret = set_devices(&cmd_cfg, &container_cfg, buff, buff_len);
+      ret = set_devices(&cmd_cfg, &container_cfg, &buff);
+      char *actual = flatten(&buff);
       ASSERT_EQ(0, ret);
-      ASSERT_STREQ(itr->second.c_str(), buff);
+      ASSERT_STREQ(itr->second.c_str(), actual);
+      free(actual);
     }
     write_command_file("[docker-command-execution]\n  docker-command=run\n image=nothadoop/image\n  devices=/dev/test-device:/dev/test-device");
     ret = read_config(docker_command_file.c_str(), &cmd_cfg);
     if (ret != 0) {
       FAIL();
     }
-    strcpy(buff, "test string");
-    ret = set_devices(&cmd_cfg, &container_cfg, buff, buff_len);
+    reset_args(&buff);
+    ret = set_devices(&cmd_cfg, &container_cfg, &buff);
     ASSERT_EQ(INVALID_DOCKER_DEVICE, ret);
-    ASSERT_EQ(0, strlen(buff));
+    ASSERT_EQ(0, buff.length);
 
     write_command_file("[docker-command-execution]\n  docker-command=run\n  image=hadoop/image\n  devices=/dev/device3:/dev/device3");
     ret = read_config(docker_command_file.c_str(), &cmd_cfg);
     if (ret != 0) {
       FAIL();
     }
-    strcpy(buff, "test string");
-    ret = set_devices(&cmd_cfg, &container_cfg, buff, buff_len);
+    reset_args(&buff);
+    ret = set_devices(&cmd_cfg, &container_cfg, &buff);
     ASSERT_EQ(INVALID_DOCKER_DEVICE, ret);
-    ASSERT_EQ(0, strlen(buff));
+    ASSERT_EQ(0, buff.length);
 
     write_command_file("[docker-command-execution]\n  docker-command=run\n  image=hadoop/image\n  devices=/dev/device1");
     ret = read_config(docker_command_file.c_str(), &cmd_cfg);
     if (ret != 0) {
       FAIL();
     }
-    strcpy(buff, "test string");
-    ret = set_devices(&cmd_cfg, &container_cfg, buff, buff_len);
+    reset_args(&buff);
+    ret = set_devices(&cmd_cfg, &container_cfg, &buff);
     ASSERT_EQ(INVALID_DOCKER_DEVICE, ret);
-    ASSERT_EQ(0, strlen(buff));
+    ASSERT_EQ(0, buff.length);
 
     write_command_file("[docker-command-execution]\n  docker-command=run\n  image=hadoop/image\n  devices=/dev/testnvidia:/dev/testnvidia");
     ret = read_config(docker_command_file.c_str(), &cmd_cfg);
     if (ret != 0) {
       FAIL();
     }
-    strcpy(buff, "test string");
-    ret = set_devices(&cmd_cfg, &container_cfg, buff, buff_len);
+    reset_args(&buff);
+    ret = set_devices(&cmd_cfg, &container_cfg, &buff);
     ASSERT_EQ(INVALID_DOCKER_DEVICE, ret);
-    ASSERT_EQ(0, strlen(buff));
+    ASSERT_EQ(0, buff.length);
 
     write_command_file("[docker-command-execution]\n  docker-command=run\n  image=hadoop/image\n  devices=/dev/gpu-nvidia-uvm:/dev/gpu-nvidia-uvm");
     ret = read_config(docker_command_file.c_str(), &cmd_cfg);
     if (ret != 0) {
       FAIL();
     }
-    strcpy(buff, "test string");
-    ret = set_devices(&cmd_cfg, &container_cfg, buff, buff_len);
+    reset_args(&buff);
+    ret = set_devices(&cmd_cfg, &container_cfg, &buff);
     ASSERT_EQ(INVALID_DOCKER_DEVICE, ret);
-    ASSERT_EQ(0, strlen(buff));
+    ASSERT_EQ(0, buff.length);
 
     write_command_file("[docker-command-execution]\n  docker-command=run\n  image=hadoop/image\n  devices=/dev/device1");
     ret = read_config(docker_command_file.c_str(), &cmd_cfg);
     if (ret != 0) {
       FAIL();
     }
-    strcpy(buff, "test string");
-    ret = set_devices(&cmd_cfg, &container_cfg, buff, buff_len);
+    reset_args(&buff);
+    ret = set_devices(&cmd_cfg, &container_cfg, &buff);
     ASSERT_EQ(INVALID_DOCKER_DEVICE, ret);
-    ASSERT_EQ(0, strlen(buff));
+    ASSERT_EQ(0, buff.length);
 
     container_executor_cfg_contents = "[docker]\n";
     write_container_executor_cfg(container_executor_cfg_contents);
@@ -869,37 +899,36 @@ namespace ContainerExecutor {
     if (ret != 0) {
       FAIL();
     }
-    strcpy(buff, "test string");
-    ret = set_devices(&cmd_cfg, &container_cfg, buff, buff_len);
+    reset_args(&buff);
+    ret = set_devices(&cmd_cfg, &container_cfg, &buff);
     ASSERT_EQ(INVALID_DOCKER_DEVICE, ret);
-    ASSERT_EQ(0, strlen(buff));
+    ASSERT_EQ(0, buff.length);
   }
 
 
   TEST_F(TestDockerUtil, test_add_rw_mounts) {
     struct configuration container_cfg, cmd_cfg;
-    const int buff_len = 1024;
-    char buff[buff_len];
+    struct args buff = ARGS_INITIAL_VALUE;
     int ret = 0;
     std::string container_executor_cfg_contents = "[docker]\n  docker.privileged-containers.registries=hadoop\n  "
-                                                              "docker.allowed.rw-mounts=/opt,/var,/usr/bin/cut,..\n  "
+                                                              "docker.allowed.rw-mounts=/opt,/var,/usr/bin/cut\n  "
                                                               "docker.allowed.ro-mounts=/etc/passwd";
     std::vector<std::pair<std::string, std::string> > file_cmd_vec;
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
-        "[docker-command-execution]\n  docker-command=run\n  image=hadoop/image\n  rw-mounts=/var:/var", "-v '/var:/var' "));
+        "[docker-command-execution]\n  docker-command=run\n  image=hadoop/image\n  rw-mounts=/var:/var", "-v /var:/var"));
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
         "[docker-command-execution]\n  docker-command=run\n image=nothadoop/image\n  rw-mounts=/var:/var", ""));
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
-        "[docker-command-execution]\n  docker-command=run\n  image=hadoop/image\n  rw-mounts=/var/:/var/", "-v '/var/:/var/' "));
+        "[docker-command-execution]\n  docker-command=run\n  image=hadoop/image\n  rw-mounts=/var/:/var/", "-v /var/:/var/"));
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
         "[docker-command-execution]\n  docker-command=run\n  image=hadoop/image\n  rw-mounts=/usr/bin/cut:/usr/bin/cut",
-        "-v '/usr/bin/cut:/usr/bin/cut' "));
+        "-v /usr/bin/cut:/usr/bin/cut"));
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
         "[docker-command-execution]\n  docker-command=run\n image=nothadoop/image\n  rw-mounts=/lib:/lib",
         ""));
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
         "[docker-command-execution]\n  docker-command=run\n  image=hadoop/image\n  rw-mounts=/opt:/mydisk1,/var/log/:/mydisk2",
-        "-v '/opt:/mydisk1' -v '/var/log/:/mydisk2' "));
+        "-v /opt:/mydisk1 -v /var/log/:/mydisk2"));
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
         "[docker-command-execution]\n  docker-command=run\n image=nothadoop/image\n  rw-mounts=/opt:/mydisk1,/var/log/:/mydisk2",
         ""));
@@ -922,15 +951,17 @@ namespace ContainerExecutor {
     std::vector<std::pair<std::string, std::string> >::const_iterator itr;
 
     for (itr = file_cmd_vec.begin(); itr != file_cmd_vec.end(); ++itr) {
-      memset(buff, 0, buff_len);
+      reset_args(&buff);
       write_command_file(itr->first);
       ret = read_config(docker_command_file.c_str(), &cmd_cfg);
       if (ret != 0) {
         FAIL();
       }
-      ret = add_rw_mounts(&cmd_cfg, &container_cfg, buff, buff_len);
+      ret = add_rw_mounts(&cmd_cfg, &container_cfg, &buff);
+      char *actual = flatten(&buff);
       ASSERT_EQ(0, ret);
-      ASSERT_STREQ(itr->second.c_str(), buff);
+      ASSERT_STREQ(itr->second.c_str(), actual);
+      free(actual);
     }
 
     std::vector<std::pair<std::string, int> > bad_file_cmds_vec;
@@ -947,16 +978,18 @@ namespace ContainerExecutor {
     std::vector<std::pair<std::string, int> >::const_iterator itr2;
 
     for (itr2 = bad_file_cmds_vec.begin(); itr2 != bad_file_cmds_vec.end(); ++itr2) {
-      memset(buff, 0, buff_len);
+      reset_args(&buff);
       write_command_file(itr2->first);
       ret = read_config(docker_command_file.c_str(), &cmd_cfg);
       if (ret != 0) {
         FAIL();
       }
-      strcpy(buff, "test string");
-      ret = add_rw_mounts(&cmd_cfg, &container_cfg, buff, buff_len);
+      reset_args(&buff);
+      ret = add_rw_mounts(&cmd_cfg, &container_cfg, &buff);
+      char *actual = flatten(&buff);
       ASSERT_EQ(itr2->second, ret);
-      ASSERT_STREQ("", buff);
+      ASSERT_STREQ("", actual);
+      free(actual);
     }
 
     // verify that you can't mount any directory in the container-executor.cfg path
@@ -964,16 +997,18 @@ namespace ContainerExecutor {
     while (strlen(ce_path) != 0) {
       std::string cmd_file_contents = "[docker-command-execution]\n  docker-command=run\n  image=hadoop/image\n  rw-mounts=";
       cmd_file_contents.append(ce_path).append(":").append("/etc/hadoop");
-      memset(buff, 0, buff_len);
+      reset_args(&buff);
       write_command_file(cmd_file_contents);
       ret = read_config(docker_command_file.c_str(), &cmd_cfg);
       if (ret != 0) {
         FAIL();
       }
-      strcpy(buff, "test string");
-      ret = add_rw_mounts(&cmd_cfg, &container_cfg, buff, buff_len);
+      reset_args(&buff);
+      ret = add_rw_mounts(&cmd_cfg, &container_cfg, &buff);
       ASSERT_EQ(INVALID_DOCKER_RW_MOUNT, ret) << " for input " << cmd_file_contents;
-      ASSERT_STREQ("", buff);
+      char *actual = flatten(&buff);
+      ASSERT_STREQ("", actual);
+      free(actual);
       char *tmp = strrchr(ce_path, '/');
       if (tmp != NULL) {
         *tmp = '\0';
@@ -989,46 +1024,45 @@ namespace ContainerExecutor {
     if (ret != 0) {
       FAIL();
     }
-    strcpy(buff, "test string");
-    ret = add_rw_mounts(&cmd_cfg, &container_cfg, buff, buff_len);
+    reset_args(&buff);
+    ret = add_rw_mounts(&cmd_cfg, &container_cfg, &buff);
+    char *actual = flatten(&buff);
     ASSERT_EQ(0, ret);
-    ASSERT_EQ(11, strlen(buff));
+    ASSERT_STREQ("", actual);
+    free(actual);
   }
 
   TEST_F(TestDockerUtil, test_add_ro_mounts) {
     struct configuration container_cfg, cmd_cfg;
-    const int buff_len = 1024;
-    char buff[buff_len];
+    struct args buff = ARGS_INITIAL_VALUE;
     int ret = 0;
 
     std::string container_executor_cfg_contents = "[docker]\n  docker.privileged-containers.registries=hadoop\n  "
-                                                              "docker.allowed.rw-mounts=/home/,/var,/usr/bin/cut,..\n  "
+                                                              "docker.allowed.rw-mounts=/home/,/var,/usr/bin/cut\n  "
                                                               "docker.allowed.ro-mounts=/etc/passwd,/etc/group";
     std::vector<std::pair<std::string, std::string> > file_cmd_vec;
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
-        "[docker-command-execution]\n  docker-command=run\n  image=hadoop/image\n  ro-mounts=/var:/var", "-v '/var:/var:ro' "));
-    file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
         "[docker-command-execution]\n  docker-command=run\n image=nothadoop/image\n  ro-mounts=/var:/var", ""));
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
         "[docker-command-execution]\n  docker-command=run\n image=nothadoop/image\n  ro-mounts=/etc:/etc", ""));
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
-        "[docker-command-execution]\n  docker-command=run\n  image=hadoop/image\n  ro-mounts=/var/:/var/", "-v '/var/:/var/:ro' "));
+        "[docker-command-execution]\n  docker-command=run\n  image=hadoop/image\n  ro-mounts=/var/:/var/", "-v /var/:/var/:ro"));
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
-        "[docker-command-execution]\n  docker-command=run\n  image=hadoop/image\n  ro-mounts=/home:/home", "-v '/home:/home:ro' "));
+        "[docker-command-execution]\n  docker-command=run\n  image=hadoop/image\n  ro-mounts=/home:/home", "-v /home:/home:ro"));
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
-        "[docker-command-execution]\n  docker-command=run\n  image=hadoop/image\n  ro-mounts=/home/:/home", "-v '/home/:/home:ro' "));
+        "[docker-command-execution]\n  docker-command=run\n  image=hadoop/image\n  ro-mounts=/home/:/home", "-v /home/:/home:ro"));
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
         "[docker-command-execution]\n  docker-command=run\n  image=hadoop/image\n  ro-mounts=/usr/bin/cut:/usr/bin/cut",
-        "-v '/usr/bin/cut:/usr/bin/cut:ro' "));
+        "-v /usr/bin/cut:/usr/bin/cut:ro"));
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
         "[docker-command-execution]\n  docker-command=run\n  image=hadoop/image\n  ro-mounts=/etc/group:/etc/group",
-        "-v '/etc/group:/etc/group:ro' "));
+        "-v /etc/group:/etc/group:ro"));
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
         "[docker-command-execution]\n  docker-command=run\n  image=hadoop/image\n  ro-mounts=/etc/passwd:/etc/passwd",
-        "-v '/etc/passwd:/etc/passwd:ro' "));
+        "-v /etc/passwd:/etc/passwd:ro"));
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
         "[docker-command-execution]\n  docker-command=run\n  image=hadoop/image\n  ro-mounts=/var/log:/mydisk1,/etc/passwd:/etc/passwd",
-        "-v '/var/log:/mydisk1:ro' -v '/etc/passwd:/etc/passwd:ro' "));
+        "-v /var/log:/mydisk1:ro -v /etc/passwd:/etc/passwd:ro"));
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
         "[docker-command-execution]\n  docker-command=run\n  image=hadoop/image\n", ""));
     write_container_executor_cfg(container_executor_cfg_contents);
@@ -1046,15 +1080,17 @@ namespace ContainerExecutor {
     std::vector<std::pair<std::string, std::string> >::const_iterator itr;
 
     for (itr = file_cmd_vec.begin(); itr != file_cmd_vec.end(); ++itr) {
-      memset(buff, 0, buff_len);
+      reset_args(&buff);
       write_command_file(itr->first);
       ret = read_config(docker_command_file.c_str(), &cmd_cfg);
       if (ret != 0) {
         FAIL();
       }
-      ret = add_ro_mounts(&cmd_cfg, &container_cfg, buff, buff_len);
+      ret = add_ro_mounts(&cmd_cfg, &container_cfg, &buff);
+      char *actual = flatten(&buff);
       ASSERT_EQ(0, ret);
-      ASSERT_STREQ(itr->second.c_str(), buff);
+      ASSERT_STREQ(itr->second.c_str(), actual);
+      free(actual);
     }
 
     std::vector<std::pair<std::string, int> > bad_file_cmds_vec;
@@ -1068,16 +1104,18 @@ namespace ContainerExecutor {
     std::vector<std::pair<std::string, int> >::const_iterator itr2;
 
     for (itr2 = bad_file_cmds_vec.begin(); itr2 != bad_file_cmds_vec.end(); ++itr2) {
-      memset(buff, 0, buff_len);
+      reset_args(&buff);
       write_command_file(itr2->first);
       ret = read_config(docker_command_file.c_str(), &cmd_cfg);
       if (ret != 0) {
         FAIL();
       }
-      strcpy(buff, "test string");
-      ret = add_ro_mounts(&cmd_cfg, &container_cfg, buff, buff_len);
+      reset_args(&buff);
+      ret = add_ro_mounts(&cmd_cfg, &container_cfg, &buff);
+      char *actual = flatten(&buff);
       ASSERT_EQ(itr2->second, ret);
-      ASSERT_STREQ("", buff);
+      ASSERT_STREQ("", actual);
+      free(actual);
     }
 
     container_executor_cfg_contents = "[docker]\n  docker.privileged-containers.registries=hadoop\n";
@@ -1087,10 +1125,10 @@ namespace ContainerExecutor {
       FAIL();
     }
     write_command_file("[docker-command-execution]\n  docker-command=run\n  image=hadoop/image\n  ro-mounts=/home:/home");
-    strcpy(buff, "test string");
-    ret = add_ro_mounts(&cmd_cfg, &container_cfg, buff, buff_len);
+    reset_args(&buff);
+    ret = add_ro_mounts(&cmd_cfg, &container_cfg, &buff);
     ASSERT_EQ(INVALID_DOCKER_RO_MOUNT, ret);
-    ASSERT_EQ(0, strlen(buff));
+    ASSERT_EQ(0, buff.length);
   }
 
   TEST_F(TestDockerUtil, test_docker_run_privileged) {
@@ -1113,14 +1151,14 @@ namespace ContainerExecutor {
     std::vector<std::pair<std::string, std::string> > file_cmd_vec;
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
         "[docker-command-execution]\n  docker-command=run\n  name=container_e1_12312_11111_02_000001\n  image=hadoop/docker-image\n  user=nobody",
-        "run --name='container_e1_12312_11111_02_000001' --user='nobody' --cap-drop='ALL' 'hadoop/docker-image' "));
+        "/usr/bin/docker run --name=container_e1_12312_11111_02_000001 --user=nobody --cap-drop=ALL hadoop/docker-image"));
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
         "[docker-command-execution]\n  docker-command=run\n name=container_e1_12312_11111_02_000001\n image=nothadoop/docker-image\n  user=nobody",
-        "run --name='container_e1_12312_11111_02_000001' --user='nobody' --cap-drop='ALL' 'nothadoop/docker-image' "));
+        "/usr/bin/docker run --name=container_e1_12312_11111_02_000001 --user=nobody --cap-drop=ALL nothadoop/docker-image"));
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
         "[docker-command-execution]\n  docker-command=run\n  name=container_e1_12312_11111_02_000001\n  image=hadoop/docker-image\n  user=nobody\n"
             "  launch-command=bash,test_script.sh,arg1,arg2",
-        "run --name='container_e1_12312_11111_02_000001' --user='nobody' --cap-drop='ALL' 'hadoop/docker-image' 'bash' 'test_script.sh' 'arg1' 'arg2' "));
+        "/usr/bin/docker run --name=container_e1_12312_11111_02_000001 --user=nobody --cap-drop=ALL hadoop/docker-image bash test_script.sh arg1 arg2"));
 
     // Test non-privileged conatiner with launch command
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
@@ -1130,10 +1168,10 @@ namespace ContainerExecutor {
             "  network=bridge\n  devices=/dev/test:/dev/test\n"
             "  cap-add=CHOWN,SETUID\n  cgroup-parent=ctr-cgroup\n  detach=true\n  rm=true\n"
             "  launch-command=bash,test_script.sh,arg1,arg2",
-        "run --name='container_e1_12312_11111_02_000001' --user='nobody' -d --rm -v '/var/log:/var/log:ro' -v '/var/lib:/lib:ro'"
-            " -v '/usr/bin/cut:/usr/bin/cut:ro' -v '/tmp:/tmp' --cgroup-parent='ctr-cgroup' --cap-drop='ALL' --cap-add='CHOWN'"
-            " --cap-add='SETUID' --hostname='host-id' --device='/dev/test:/dev/test' 'hadoop/docker-image' 'bash' "
-            "'test_script.sh' 'arg1' 'arg2' "));
+        "/usr/bin/docker run --name=container_e1_12312_11111_02_000001 --user=nobody -d --rm -v /var/log:/var/log:ro -v /var/lib:/lib:ro"
+            " -v /usr/bin/cut:/usr/bin/cut:ro -v /tmp:/tmp --cgroup-parent=ctr-cgroup --cap-drop=ALL --cap-add=CHOWN"
+            " --cap-add=SETUID --hostname=host-id --device=/dev/test:/dev/test hadoop/docker-image bash "
+            "test_script.sh arg1 arg2"));
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
         "[docker-command-execution]\n"
             "  docker-command=run\n  name=container_e1_12312_11111_02_000001\n image=nothadoop/docker-image\n  user=nobody\n  hostname=host-id\n"
@@ -1141,8 +1179,8 @@ namespace ContainerExecutor {
             "  network=bridge\n"
             "  cap-add=CHOWN,SETUID\n  cgroup-parent=ctr-cgroup\n  detach=true\n  rm=true\n"
             "  launch-command=bash,test_script.sh,arg1,arg2",
-        "run --name='container_e1_12312_11111_02_000001' --user='nobody' -d --rm"
-            " --cgroup-parent='ctr-cgroup' --cap-drop='ALL' --hostname='host-id' 'nothadoop/docker-image' "));
+        "/usr/bin/docker run --name=container_e1_12312_11111_02_000001 --user=nobody -d --rm"
+            " --cgroup-parent=ctr-cgroup --cap-drop=ALL --hostname=host-id nothadoop/docker-image"));
 
     // Test non-privileged container and drop all privileges
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
@@ -1152,10 +1190,10 @@ namespace ContainerExecutor {
             "  network=bridge\n  devices=/dev/test:/dev/test\n  net=bridge\n"
             "  cap-add=CHOWN,SETUID\n  cgroup-parent=ctr-cgroup\n  detach=true\n  rm=true\n"
             "  launch-command=bash,test_script.sh,arg1,arg2",
-        "run --name='container_e1_12312_11111_02_000001' --user='nobody' -d --rm --net='bridge' -v '/var/log:/var/log:ro' -v '/var/lib:/lib:ro'"
-            " -v '/usr/bin/cut:/usr/bin/cut:ro' -v '/tmp:/tmp' --cgroup-parent='ctr-cgroup' --cap-drop='ALL' --cap-add='CHOWN' "
-            "--cap-add='SETUID' --hostname='host-id' --device='/dev/test:/dev/test' 'hadoop/docker-image' 'bash'"
-            " 'test_script.sh' 'arg1' 'arg2' "));
+        "/usr/bin/docker run --name=container_e1_12312_11111_02_000001 --user=nobody -d --rm --net=bridge -v /var/log:/var/log:ro -v /var/lib:/lib:ro"
+            " -v /usr/bin/cut:/usr/bin/cut:ro -v /tmp:/tmp --cgroup-parent=ctr-cgroup --cap-drop=ALL --cap-add=CHOWN "
+            "--cap-add=SETUID --hostname=host-id --device=/dev/test:/dev/test hadoop/docker-image bash"
+            " test_script.sh arg1 arg2"));
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
         "[docker-command-execution]\n"
             "  docker-command=run\n  name=container_e1_12312_11111_02_000001\n image=nothadoop/docker-image\n  user=nobody\n  hostname=host-id\n"
@@ -1163,8 +1201,8 @@ namespace ContainerExecutor {
             "  network=bridge\n  net=bridge\n"
             "  cap-add=CHOWN,SETUID\n  cgroup-parent=ctr-cgroup\n  detach=true\n  rm=true\n"
             "  launch-command=bash,test_script.sh,arg1,arg2",
-        "run --name='container_e1_12312_11111_02_000001' --user='nobody' -d --rm --net='bridge'"
-            " --cgroup-parent='ctr-cgroup' --cap-drop='ALL' --hostname='host-id' 'nothadoop/docker-image' "));
+        "/usr/bin/docker run --name=container_e1_12312_11111_02_000001 --user=nobody -d --rm --net=bridge"
+            " --cgroup-parent=ctr-cgroup --cap-drop=ALL --hostname=host-id nothadoop/docker-image"));
 
     // Test privileged container
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
@@ -1174,10 +1212,10 @@ namespace ContainerExecutor {
             "  network=bridge\n  devices=/dev/test:/dev/test\n  net=bridge\n  privileged=true\n"
             "  cap-add=CHOWN,SETUID\n  cgroup-parent=ctr-cgroup\n  detach=true\n  rm=true\n"
             "  launch-command=bash,test_script.sh,arg1,arg2",
-        "run --name='container_e1_12312_11111_02_000001' -d --rm --net='bridge' -v '/var/log:/var/log:ro' -v '/var/lib:/lib:ro'"
-            " -v '/usr/bin/cut:/usr/bin/cut:ro' -v '/tmp:/tmp' --cgroup-parent='ctr-cgroup' --privileged --cap-drop='ALL' "
-            "--cap-add='CHOWN' --cap-add='SETUID' --hostname='host-id' --device='/dev/test:/dev/test' 'hadoop/docker-image' "
-            "'bash' 'test_script.sh' 'arg1' 'arg2' "));
+        "/usr/bin/docker run --name=container_e1_12312_11111_02_000001 -d --rm --net=bridge -v /var/log:/var/log:ro -v /var/lib:/lib:ro"
+            " -v /usr/bin/cut:/usr/bin/cut:ro -v /tmp:/tmp --cgroup-parent=ctr-cgroup --privileged --cap-drop=ALL "
+            "--cap-add=CHOWN --cap-add=SETUID --hostname=host-id --device=/dev/test:/dev/test hadoop/docker-image "
+            "bash test_script.sh arg1 arg2"));
 
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
         "[docker-command-execution]\n"
@@ -1186,10 +1224,10 @@ namespace ContainerExecutor {
             "  network=bridge\n  devices=/dev/test:/dev/test\n  net=bridge\n  privileged=true\n"
             "  cap-add=CHOWN,SETUID\n  cgroup-parent=ctr-cgroup\n  detach=true\n  rm=true\n  group-add=1000,1001\n"
             "  launch-command=bash,test_script.sh,arg1,arg2",
-        "run --name='container_e1_12312_11111_02_000001' -d --rm --net='bridge' -v '/var/log:/var/log:ro' -v '/var/lib:/lib:ro'"
-            " -v '/usr/bin/cut:/usr/bin/cut:ro' -v '/tmp:/tmp' --cgroup-parent='ctr-cgroup' --privileged --cap-drop='ALL' "
-            "--cap-add='CHOWN' --cap-add='SETUID' --hostname='host-id' "
-            "--device='/dev/test:/dev/test' 'hadoop/docker-image' 'bash' 'test_script.sh' 'arg1' 'arg2' "));
+        "/usr/bin/docker run --name=container_e1_12312_11111_02_000001 -d --rm --net=bridge -v /var/log:/var/log:ro -v /var/lib:/lib:ro"
+            " -v /usr/bin/cut:/usr/bin/cut:ro -v /tmp:/tmp --cgroup-parent=ctr-cgroup --privileged --cap-drop=ALL "
+            "--cap-add=CHOWN --cap-add=SETUID --hostname=host-id "
+            "--device=/dev/test:/dev/test hadoop/docker-image bash test_script.sh arg1 arg2"));
 
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
         "[docker-command-execution]\n"
@@ -1197,9 +1235,9 @@ namespace ContainerExecutor {
             "  network=bridge\n  net=bridge\n"
             "  detach=true\n  rm=true\n  group-add=1000,1001\n"
             "  launch-command=bash,test_script.sh,arg1,arg2",
-        "run --name='container_e1_12312_11111_02_000001' --user='nobody' -d --rm --net='bridge' --cap-drop='ALL' "
-            "--hostname='host-id' --group-add '1000' --group-add '1001' "
-            "'docker-image' "));
+        "/usr/bin/docker run --name=container_e1_12312_11111_02_000001 --user=nobody -d --rm --net=bridge --cap-drop=ALL "
+            "--hostname=host-id --group-add 1000 --group-add 1001 "
+            "docker-image"));
 
     std::vector<std::pair<std::string, int> > bad_file_cmd_vec;
 
@@ -1302,11 +1340,11 @@ namespace ContainerExecutor {
       std::vector<std::pair<std::string, std::string> > file_cmd_vec;
       file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
           "[docker-command-execution]\n  docker-command=run\n  name=container_e1_12312_11111_02_000001\n  image=docker-image\n  user=nobody",
-          "run --name='container_e1_12312_11111_02_000001' --user='nobody' --cap-drop='ALL' 'docker-image' "));
+          "/usr/bin/docker run --name=container_e1_12312_11111_02_000001 --user=nobody --cap-drop=ALL docker-image"));
       file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
           "[docker-command-execution]\n  docker-command=run\n  name=container_e1_12312_11111_02_000001\n  image=docker-image\n"
               "  user=nobody\n  launch-command=bash,test_script.sh,arg1,arg2",
-          "run --name='container_e1_12312_11111_02_000001' --user='nobody' --cap-drop='ALL' 'docker-image' "));
+          "/usr/bin/docker run --name=container_e1_12312_11111_02_000001 --user=nobody --cap-drop=ALL docker-image"));
 
       file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
           "[docker-command-execution]\n"
@@ -1315,10 +1353,10 @@ namespace ContainerExecutor {
               "  network=bridge\n  devices=/dev/test:/dev/test\n"
               "  cap-add=CHOWN,SETUID\n  cgroup-parent=ctr-cgroup\n  detach=true\n  rm=true\n"
               "  launch-command=bash,test_script.sh,arg1,arg2",
-          "run --name='container_e1_12312_11111_02_000001' --user='nobody' -d --rm -v '/var/log:/var/log:ro' -v '/var/lib:/lib:ro'"
-              " -v '/usr/bin/cut:/usr/bin/cut:ro' -v '/tmp:/tmp' --cgroup-parent='ctr-cgroup' --cap-drop='ALL' --cap-add='CHOWN'"
-              " --cap-add='SETUID' --hostname='host-id' --device='/dev/test:/dev/test' 'hadoop/docker-image' 'bash' "
-              "'test_script.sh' 'arg1' 'arg2' "));
+          "/usr/bin/docker run --name=container_e1_12312_11111_02_000001 --user=nobody -d --rm -v /var/log:/var/log:ro -v /var/lib:/lib:ro"
+              " -v /usr/bin/cut:/usr/bin/cut:ro -v /tmp:/tmp --cgroup-parent=ctr-cgroup --cap-drop=ALL --cap-add=CHOWN"
+              " --cap-add=SETUID --hostname=host-id --device=/dev/test:/dev/test hadoop/docker-image bash "
+              "test_script.sh arg1 arg2"));
       file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
           "[docker-command-execution]\n"
               "  docker-command=run\n  name=container_e1_12312_11111_02_000001\n image=nothadoop/docker-image\n  user=nobody\n  hostname=host-id\n"
@@ -1326,8 +1364,8 @@ namespace ContainerExecutor {
               "  network=bridge\n"
               "  cap-add=CHOWN,SETUID\n  cgroup-parent=ctr-cgroup\n  detach=true\n  rm=true\n"
               "  launch-command=bash,test_script.sh,arg1,arg2",
-          "run --name='container_e1_12312_11111_02_000001' --user='nobody' -d --rm"
-              " --cgroup-parent='ctr-cgroup' --cap-drop='ALL' --hostname='host-id' 'nothadoop/docker-image' "));
+          "/usr/bin/docker run --name=container_e1_12312_11111_02_000001 --user=nobody -d --rm"
+              " --cgroup-parent=ctr-cgroup --cap-drop=ALL --hostname=host-id nothadoop/docker-image"));
 
       file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
           "[docker-command-execution]\n"
@@ -1336,10 +1374,10 @@ namespace ContainerExecutor {
               "  network=bridge\n  devices=/dev/test:/dev/test\n  net=bridge\n"
               "  cap-add=CHOWN,SETUID\n  cgroup-parent=ctr-cgroup\n  detach=true\n  rm=true\n"
               "  launch-command=bash,test_script.sh,arg1,arg2",
-          "run --name='container_e1_12312_11111_02_000001' --user='nobody' -d --rm --net='bridge' -v '/var/log:/var/log:ro' -v '/var/lib:/lib:ro'"
-              " -v '/usr/bin/cut:/usr/bin/cut:ro' -v '/tmp:/tmp' --cgroup-parent='ctr-cgroup' --cap-drop='ALL' --cap-add='CHOWN' "
-              "--cap-add='SETUID' --hostname='host-id' --device='/dev/test:/dev/test' 'hadoop/docker-image' 'bash'"
-              " 'test_script.sh' 'arg1' 'arg2' "));
+          "/usr/bin/docker run --name=container_e1_12312_11111_02_000001 --user=nobody -d --rm --net=bridge -v /var/log:/var/log:ro -v /var/lib:/lib:ro"
+              " -v /usr/bin/cut:/usr/bin/cut:ro -v /tmp:/tmp --cgroup-parent=ctr-cgroup --cap-drop=ALL --cap-add=CHOWN "
+              "--cap-add=SETUID --hostname=host-id --device=/dev/test:/dev/test hadoop/docker-image bash"
+              " test_script.sh arg1 arg2"));
       file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
           "[docker-command-execution]\n"
               "  docker-command=run\n  name=container_e1_12312_11111_02_000001\n image=nothadoop/docker-image\n  user=nobody\n  hostname=host-id\n"
@@ -1347,8 +1385,8 @@ namespace ContainerExecutor {
               "  network=bridge\n  net=bridge\n"
               "  cap-add=CHOWN,SETUID\n  cgroup-parent=ctr-cgroup\n  detach=true\n  rm=true\n"
               "  launch-command=bash,test_script.sh,arg1,arg2",
-          "run --name='container_e1_12312_11111_02_000001' --user='nobody' -d --rm --net='bridge'"
-              " --cgroup-parent='ctr-cgroup' --cap-drop='ALL' --hostname='host-id' 'nothadoop/docker-image' "));
+          "/usr/bin/docker run --name=container_e1_12312_11111_02_000001 --user=nobody -d --rm --net=bridge"
+              " --cgroup-parent=ctr-cgroup --cap-drop=ALL --hostname=host-id nothadoop/docker-image"));
 
       std::vector<std::pair<std::string, int> > bad_file_cmd_vec;
       bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
@@ -1369,34 +1407,35 @@ namespace ContainerExecutor {
     input_output_map.push_back(std::make_pair<std::string, std::string>(
         "[docker-command-execution]\n  docker-command=inspect\n  docker-config=/my-config\n"
             "  format={{.State.Status}}\n  name=container_e1_12312_11111_02_000001",
-        "--config='/my-config' inspect --format={{.State.Status}} container_e1_12312_11111_02_000001"));
+        "/usr/bin/docker --config=/my-config inspect --format={{.State.Status}} container_e1_12312_11111_02_000001"));
     input_output_map.push_back(std::make_pair<std::string, std::string>(
         "[docker-command-execution]\n  docker-command=load\n  docker-config=/my-config\n  image=image-id",
-        "--config='/my-config' load --i='image-id' "));
+        "/usr/bin/docker --config=/my-config load --i=image-id"));
     input_output_map.push_back(std::make_pair<std::string, std::string>(
         "[docker-command-execution]\n  docker-command=pull\n  docker-config=/my-config\n  image=image-id",
-        "--config='/my-config' pull 'image-id' "));
+        "/usr/bin/docker --config=/my-config pull image-id"));
     input_output_map.push_back(std::make_pair<std::string, std::string>(
         "[docker-command-execution]\n  docker-command=rm\n  docker-config=/my-config\n  name=container_e1_12312_11111_02_000001",
-        "--config='/my-config' rm container_e1_12312_11111_02_000001"));
+        "/usr/bin/docker --config=/my-config rm container_e1_12312_11111_02_000001"));
     input_output_map.push_back(std::make_pair<std::string, std::string>(
         "[docker-command-execution]\n  docker-command=stop\n  docker-config=/my-config\n  name=container_e1_12312_11111_02_000001",
-        "--config='/my-config' stop container_e1_12312_11111_02_000001"));
+        "/usr/bin/docker --config=/my-config stop container_e1_12312_11111_02_000001"));
     input_output_map.push_back(std::make_pair<std::string, std::string>(
         "[docker-command-execution]\n  docker-command=run\n  docker-config=/my-config\n  name=container_e1_12312_11111_02_000001\n"
             "  image=docker-image\n  user=nobody",
-        "--config='/my-config' run --name='container_e1_12312_11111_02_000001' --user='nobody' --cap-drop='ALL' 'docker-image' "));
+        "/usr/bin/docker --config=/my-config run --name=container_e1_12312_11111_02_000001 --user=nobody --cap-drop=ALL docker-image"));
 
     std::vector<std::pair<std::string, std::string> >::const_iterator itr;
-    char buffer[4096];
+    struct args buffer = ARGS_INITIAL_VALUE;
     struct configuration cfg = {0, NULL};
     for (itr = input_output_map.begin(); itr != input_output_map.end(); ++itr) {
-      memset(buffer, 0, 4096);
+      reset_args(&buffer);
       write_command_file(itr->first);
-      int ret = get_docker_command(docker_command_file.c_str(), &cfg, buffer, 4096);
+      int ret = get_docker_command(docker_command_file.c_str(), &cfg, &buffer);
       ASSERT_EQ(0, ret) << "for input " << itr->first;
-      ASSERT_STREQ(itr->second.c_str(), buffer);
+      ASSERT_STREQ(itr->second.c_str(), flatten(&buffer));
     }
+    reset_args(&buffer);
   }
 
   TEST_F(TestDockerUtil, test_docker_module_enabled) {
@@ -1430,10 +1469,10 @@ namespace ContainerExecutor {
     std::vector<std::pair<std::string, std::string> > file_cmd_vec;
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
         "[docker-command-execution]\n  docker-command=volume\n  sub-command=create\n  volume=volume1 \n driver=driver1",
-        "volume create --name=volume1 --driver=driver1"));
+        "/usr/bin/docker volume create --name=volume1 --driver=driver1"));
     file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
        "[docker-command-execution]\n  docker-command=volume\n  format={{.Name}},{{.Driver}}\n  sub-command=ls",
-       "volume ls --format={{.Name}},{{.Driver}}"));
+       "/usr/bin/docker volume ls --format={{.Name}},{{.Driver}}"));
 
     std::vector<std::pair<std::string, int> > bad_file_cmd_vec;
 


---------------------------------------------------------------------
To unsubscribe, e-mail: common-commits-unsubscribe@hadoop.apache.org
For additional commands, e-mail: common-commits-help@hadoop.apache.org


[2/2] hadoop git commit: YARN-8207. Docker container launch use popen have risk of shell expansion. Contributed by Eric Yang.

Posted by jl...@apache.org.
YARN-8207. Docker container launch use popen have risk of shell expansion. Contributed by Eric Yang.


Project: http://git-wip-us.apache.org/repos/asf/hadoop/repo
Commit: http://git-wip-us.apache.org/repos/asf/hadoop/commit/a2ea7564
Tree: http://git-wip-us.apache.org/repos/asf/hadoop/tree/a2ea7564
Diff: http://git-wip-us.apache.org/repos/asf/hadoop/diff/a2ea7564

Branch: refs/heads/trunk
Commit: a2ea7564209dce896a5badee3949ee41e4bc00bf
Parents: 6b96a73
Author: Jason Lowe <jl...@apache.org>
Authored: Tue May 8 15:30:36 2018 -0500
Committer: Jason Lowe <jl...@apache.org>
Committed: Tue May 8 15:30:36 2018 -0500

----------------------------------------------------------------------
 .../impl/container-executor.c                   | 118 ++--
 .../impl/container-executor.h                   |   5 +
 .../container-executor/impl/utils/docker-util.c | 611 +++++++++----------
 .../container-executor/impl/utils/docker-util.h |  38 +-
 .../impl/utils/string-utils.c                   |  24 +
 .../impl/utils/string-utils.h                   |   4 +
 .../test/utils/test_docker_util.cc              | 463 +++++++-------
 7 files changed, 674 insertions(+), 589 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/hadoop/blob/a2ea7564/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/container-executor.c
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/container-executor.c b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/container-executor.c
index 6b4ec0c..c5adbe4 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/container-executor.c
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/container-executor.c
@@ -20,6 +20,7 @@
 #include "container-executor.h"
 #include "utils/docker-util.h"
 #include "utils/path-utils.h"
+#include "utils/string-utils.h"
 #include "util.h"
 #include "config.h"
 
@@ -737,7 +738,6 @@ static int create_container_directories(const char* user, const char *app_id,
     result = OUT_OF_MEMORY;
   } else {
     sprintf(combined_name, "%s/%s", app_id, container_id);
-
     char* const* log_dir_ptr;
     for(log_dir_ptr = log_dir; *log_dir_ptr != NULL; ++log_dir_ptr) {
       char *container_log_dir = get_app_log_directory(*log_dir_ptr, combined_name);
@@ -753,10 +753,10 @@ static int create_container_directories(const char* user, const char *app_id,
         free(combined_name);
         return OUT_OF_MEMORY;
       } else if (mkdirs(container_log_dir, perms) != 0) {
-    	free(container_log_dir);
+        free(container_log_dir);
       } else {
-    	result = 0;
-    	free(container_log_dir);
+        free(container_log_dir);
+        result = 0;
       }
     }
     free(combined_name);
@@ -799,7 +799,7 @@ static struct passwd* get_user_info(const char* user) {
         string_size, &result) != 0) {
     free(buffer);
     fprintf(LOGFILE, "Can't get user information %s - %s\n", user,
-	    strerror(errno));
+           strerror(errno));
     return NULL;
   }
   return result;
@@ -1094,7 +1094,6 @@ int initialize_user(const char *user, char* const* local_dirs) {
 }
 
 int create_log_dirs(const char *app_id, char * const * log_dirs) {
-
   char* const* log_root;
   char *any_one_app_log_dir = NULL;
   for(log_root=log_dirs; *log_root != NULL; ++log_root) {
@@ -1275,11 +1274,9 @@ int initialize_app(const char *user, const char *app_id,
   return -1;
 }
 
-char *construct_docker_command(const char *command_file) {
+char **construct_docker_command(const char *command_file) {
   int ret = 0;
-  size_t command_size = MIN(sysconf(_SC_ARG_MAX), 128*1024);
-  char *buffer = alloc_and_clear_memory(command_size, sizeof(char));
-
+  struct args buffer = ARGS_INITIAL_VALUE;
   uid_t user = geteuid();
   gid_t group = getegid();
   if (change_effective_user(nm_uid, nm_gid) != 0) {
@@ -1287,8 +1284,7 @@ char *construct_docker_command(const char *command_file) {
     fflush(ERRORFILE);
     exit(SETUID_OPER_FAILED);
   }
-
-  ret = get_docker_command(command_file, &CFG, buffer, command_size);
+  ret = get_docker_command(command_file, &CFG, &buffer);
   if (ret != 0) {
     fprintf(ERRORFILE, "Error constructing docker command, docker error code=%d, error message='%s'\n", ret,
             get_docker_error_message(ret));
@@ -1302,31 +1298,24 @@ char *construct_docker_command(const char *command_file) {
     exit(SETUID_OPER_FAILED);
   }
 
-  return buffer;
+  char** copy = extract_execv_args(&buffer);
+  return copy;
 }
 
 int run_docker(const char *command_file) {
-  char* docker_command = construct_docker_command(command_file);
+  char **args = construct_docker_command(command_file);
   char* docker_binary = get_docker_binary(&CFG);
-  size_t command_size = MIN(sysconf(_SC_ARG_MAX), 128*1024);
-
-  char* docker_command_with_binary = alloc_and_clear_memory(command_size, sizeof(char));
-  snprintf(docker_command_with_binary, command_size, "%s %s", docker_binary, docker_command);
-  fprintf(LOGFILE, "Invoking '%s'\n", docker_command_with_binary);
-  char **args = split_delimiter(docker_command_with_binary, " ");
-
   int exit_code = -1;
   if (execvp(docker_binary, args) != 0) {
     fprintf(ERRORFILE, "Couldn't execute the container launch with args %s - %s",
               docker_binary, strerror(errno));
-      fflush(LOGFILE);
-      fflush(ERRORFILE);
-      free(docker_binary);
-      free(args);
-      free(docker_command_with_binary);
-      free(docker_command);
-      exit_code = DOCKER_RUN_FAILED;
+    fflush(LOGFILE);
+    fflush(ERRORFILE);
+    free(docker_binary);
+    free_values(args);
+    exit_code = DOCKER_RUN_FAILED;
   } else {
+    free_values(args);
     exit_code = 0;
   }
   return exit_code;
@@ -1452,7 +1441,7 @@ int create_local_dirs(const char * user, const char *app_id,
 
   // Copy script file with permissions 700
   if (copy_file(container_file_source, script_name, script_file_dest,S_IRWXU) != 0) {
-    fprintf(ERRORFILE, "Could not create copy file %d %s\n", container_file_source, script_file_dest);
+    fprintf(ERRORFILE, "Could not create copy file %s %s (%d)\n", script_name, script_file_dest, container_file_source);
     fflush(ERRORFILE);
     exit_code = COULD_NOT_CREATE_SCRIPT_COPY;
     goto cleanup;
@@ -1513,25 +1502,15 @@ int launch_docker_container_as_user(const char * user, const char *app_id,
   char *cred_file_dest = NULL;
   char *exit_code_file = NULL;
   char *docker_command_with_binary = NULL;
-  char *docker_wait_command = NULL;
   char *docker_inspect_command = NULL;
-  char *docker_rm_command = NULL;
   char *docker_inspect_exitcode_command = NULL;
   int container_file_source =-1;
   int cred_file_source = -1;
 
-  size_t command_size = MIN(sysconf(_SC_ARG_MAX), 128*1024);
-
-  docker_command_with_binary = (char *) alloc_and_clear_memory(command_size, sizeof(char));
-  docker_wait_command = (char *) alloc_and_clear_memory(command_size, sizeof(char));
-  docker_inspect_command = (char *) alloc_and_clear_memory(command_size, sizeof(char));
-  docker_rm_command = (char *) alloc_and_clear_memory(command_size, sizeof(char));
-  docker_inspect_exitcode_command = (char *) alloc_and_clear_memory(command_size, sizeof(char));
-
   gid_t user_gid = getegid();
   uid_t prev_uid = geteuid();
 
-  char *docker_command = NULL;
+  char **docker_command = NULL;
   char *docker_binary = NULL;
 
   fprintf(LOGFILE, "Creating script paths...\n");
@@ -1581,21 +1560,31 @@ int launch_docker_container_as_user(const char * user, const char *app_id,
     goto cleanup;
   }
 
-  snprintf(docker_command_with_binary, command_size, "%s %s", docker_binary, docker_command);
+  docker_command_with_binary = flatten(docker_command);
 
-  fprintf(LOGFILE, "Launching docker container...\n");
-  fprintf(LOGFILE, "Docker run command: %s\n", docker_command_with_binary);
-  FILE* start_docker = popen(docker_command_with_binary, "r");
-  if (WEXITSTATUS(pclose (start_docker)) != 0)
-  {
+  // Launch container
+  pid_t child_pid = fork();
+  if (child_pid == -1) {
     fprintf (ERRORFILE,
-     "Could not invoke docker %s.\n", docker_command_with_binary);
+      "Could not invoke docker %s.\n", docker_command_with_binary);
     fflush(ERRORFILE);
     exit_code = UNABLE_TO_EXECUTE_CONTAINER_SCRIPT;
     goto cleanup;
   }
 
-  snprintf(docker_inspect_command, command_size,
+  if (child_pid == 0) {
+    execvp(docker_binary, docker_command);
+    fprintf(ERRORFILE, "failed to execute docker command! error: %s\n", strerror(errno));
+    return UNABLE_TO_EXECUTE_CONTAINER_SCRIPT;
+  } else {
+    exit_code = wait_and_get_exit_code(child_pid);
+    if (exit_code != 0) {
+      exit_code = UNABLE_TO_EXECUTE_CONTAINER_SCRIPT;
+      goto cleanup;
+    }
+  }
+
+  docker_inspect_command = make_string(
     "%s inspect --format {{.State.Pid}} %s",
     docker_binary, container_id);
 
@@ -1643,10 +1632,10 @@ int launch_docker_container_as_user(const char * user, const char *app_id,
     }
 
     fprintf(LOGFILE, "Waiting for docker container to finish.\n");
+
+    // wait for pid to finish
 #ifdef __linux
-    size_t command_size = MIN(sysconf(_SC_ARG_MAX), 128*1024);
-    char* proc_pid_path = alloc_and_clear_memory(command_size, sizeof(char));
-    snprintf(proc_pid_path, command_size, "%s/%d", PROC_PATH, pid);
+    char* proc_pid_path = make_string("%s/%d", PROC_PATH, pid);
     while (dir_exists(proc_pid_path) == 0) {
       sleep(1);
     }
@@ -1661,7 +1650,8 @@ int launch_docker_container_as_user(const char * user, const char *app_id,
 #endif
   }
 
-  sprintf(docker_inspect_exitcode_command,
+  // discover container exit code
+  docker_inspect_exitcode_command = make_string(
     "%s inspect --format {{.State.ExitCode}} %s",
   docker_binary, container_id);
   fprintf(LOGFILE, "Obtaining the exit code...\n");
@@ -1713,9 +1703,8 @@ cleanup:
   free(script_file_dest);
   free(cred_file_dest);
   free(docker_command_with_binary);
-  free(docker_wait_command);
   free(docker_inspect_command);
-  free(docker_rm_command);
+  free_values(docker_command);
   return exit_code;
 }
 
@@ -2404,3 +2393,24 @@ int traffic_control_read_stats(char *command_file) {
 struct configuration* get_cfg() {
   return &CFG;
 }
+
+/**
+ * Flatten docker launch command
+ */
+char* flatten(char **args) {
+  size_t total = 1;
+  for (int i = 0; args[i] != NULL; i++) {
+    total = total + strlen(args[i]) + 1;
+  }
+  char *buffer = (char *) malloc(total * sizeof(char));
+  char *to = NULL;
+  to = buffer;
+  for (int i = 0; args[i] != NULL; i++) {
+    to = stpcpy(to, args[i]);
+    to = stpcpy(to, " ");
+  }
+  *to = '\0';
+  return buffer;
+}
+
+

http://git-wip-us.apache.org/repos/asf/hadoop/blob/a2ea7564/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/container-executor.h
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/container-executor.h b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/container-executor.h
index 47c4221..9136606 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/container-executor.h
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/container-executor.h
@@ -284,3 +284,8 @@ int execute_regex_match(const char *regex_str, const char *input);
 int validate_docker_image_name(const char *image_name);
 
 struct configuration* get_cfg();
+
+/**
+ * Flatten docker launch command
+ */
+char* flatten(char **args);

http://git-wip-us.apache.org/repos/asf/hadoop/blob/a2ea7564/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/utils/docker-util.c
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/utils/docker-util.c b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/utils/docker-util.c
index 6795bd8..8cd59f7 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/utils/docker-util.c
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/utils/docker-util.c
@@ -47,36 +47,63 @@ static int read_and_verify_command_file(const char *command_file, const char *do
   return ret;
 }
 
-static int add_to_buffer(char *buff, const size_t bufflen, const char *string) {
-  size_t current_len = strlen(buff);
-  size_t string_len = strlen(string);
-  if (current_len + string_len < bufflen - 1) {
-    strncpy(buff + current_len, string, string_len);
-    buff[current_len + string_len] = '\0';
-    return 0;
+static int add_to_args(args *args, const char *string) {
+  if (string == NULL) {
+    return -1;
+  }
+  if (args->data == NULL || args->length >= DOCKER_ARG_MAX) {
+    return -1;
+  }
+  char *clone = strdup(string);
+  if (clone == NULL) {
+    return -1;
+  }
+  if (args->data != NULL) {
+    args->data[args->length] = clone;
+    args->length++;
+  }
+  return 0;
+}
+
+void reset_args(args *args) {
+  int i = 0;
+  if (args == NULL) {
+    return;
+  }
+  for (i = 0; i < args->length; i++) {
+    free(args->data[i]);
+  }
+  args->length = 0;
+}
+
+char** extract_execv_args(args* args) {
+  char** copy = (char**)malloc((args->length + 1) * sizeof(char*));
+  for (int i = 0; i < args->length; i++) {
+    copy[i] = args->data[i];
   }
-  return -1;
+  copy[args->length] = NULL;
+  args->length = 0;
+  return copy;
 }
 
 static int add_param_to_command(const struct configuration *command_config, const char *key, const char *param,
-                                const int with_argument, char *out, const size_t outlen) {
-  size_t tmp_buffer_size = 4096;
+                                const int with_argument, args *args) {
   int ret = 0;
-  char *tmp_buffer = (char *) alloc_and_clear_memory(tmp_buffer_size, sizeof(char));
+  char *tmp_buffer = NULL;
   char *value = get_configuration_value(key, DOCKER_COMMAND_FILE_SECTION, command_config);
   if (value != NULL) {
     if (with_argument) {
-      quote_and_append_arg(&tmp_buffer, &tmp_buffer_size, param, value);
-      ret = add_to_buffer(out, outlen, tmp_buffer);
+      tmp_buffer = make_string("%s%s", param, value);
+      ret = add_to_args(args, tmp_buffer);
+      free(tmp_buffer);
     } else if (strcmp(value, "true") == 0) {
-      ret = add_to_buffer(out, outlen, param);
+      ret = add_to_args(args, param);
     }
     free(value);
     if (ret != 0) {
       ret = BUFFER_TOO_SMALL;
     }
   }
-  free(tmp_buffer);
   return ret;
 }
 
@@ -116,8 +143,8 @@ int check_trusted_image(const struct configuration *command_config, const struct
   }
   free(image_name);
 
-  free_and_exit:
-  free(privileged_registry);
+free_and_exit:
+  free_values(privileged_registry);
   return ret;
 }
 
@@ -141,9 +168,8 @@ static int add_param_to_command_if_allowed(const struct configuration *command_c
                                            const struct configuration *executor_cfg,
                                            const char *key, const char *allowed_key, const char *param,
                                            const int multiple_values, const char prefix,
-                                           char *out, const size_t outlen) {
-  size_t tmp_buffer_size = 4096;
-  char *tmp_buffer = (char *) alloc_and_clear_memory(tmp_buffer_size, sizeof(char));
+                                           args *args) {
+  char *tmp_buffer = NULL;
   char *tmp_ptr = NULL;
   char **values = NULL;
   char **permitted_values = get_configuration_values_delimiter(allowed_key,
@@ -174,7 +200,6 @@ static int add_param_to_command_if_allowed(const struct configuration *command_c
     if (permitted_values != NULL) {
       // Values are user requested.
       for (i = 0; values[i] != NULL; ++i) {
-        memset(tmp_buffer, 0, tmp_buffer_size);
         permitted = 0;
         if(prefix != 0) {
           tmp_ptr = strchr(values[i], prefix);
@@ -195,12 +220,8 @@ static int add_param_to_command_if_allowed(const struct configuration *command_c
           } else {
             // If permitted-Values[j] is a REGEX, use REGEX to compare
             if (is_regex(permitted_values[j])) {
-              size_t offset = tmp_ptr - values[i];
-              dst = (char *) alloc_and_clear_memory(offset, sizeof(char));
-              strncpy(dst, values[i], offset);
-              dst[tmp_ptr - values[i]] = '\0';
-              pattern = (char *) alloc_and_clear_memory((size_t)(strlen(permitted_values[j]) - 6), sizeof(char));
-              strcpy(pattern, permitted_values[j] + 6);
+              dst = strndup(values[i], tmp_ptr - values[i]);
+              pattern = strdup(permitted_values[j] + 6);
               ret = execute_regex_match(pattern, dst);
             } else {
               ret = strncmp(values[i], permitted_values[j], tmp_ptr - values[i]);
@@ -214,8 +235,9 @@ static int add_param_to_command_if_allowed(const struct configuration *command_c
           }
         }
         if (permitted == 1) {
-          quote_and_append_arg(&tmp_buffer, &tmp_buffer_size, param, values[i]);
-          ret = add_to_buffer(out, outlen, tmp_buffer);
+          tmp_buffer = make_string("%s%s", param, values[i]);
+          ret = add_to_args(args, tmp_buffer);
+          free(tmp_buffer);
           if (ret != 0) {
             fprintf(ERRORFILE, "Output buffer too small\n");
             ret = BUFFER_TOO_SMALL;
@@ -238,15 +260,11 @@ static int add_param_to_command_if_allowed(const struct configuration *command_c
   free_and_exit:
   free_values(values);
   free_values(permitted_values);
-  free(tmp_buffer);
-  if (ret != 0) {
-    memset(out, 0, outlen);
-  }
   return ret;
 }
 
-static int add_docker_config_param(const struct configuration *command_config, char *out, const size_t outlen) {
-  return add_param_to_command(command_config, "docker-config", "--config=", 1, out, outlen);
+static int add_docker_config_param(const struct configuration *command_config, args *args) {
+  return add_param_to_command(command_config, "docker-config", "--config=", 1, args);
 }
 
 static int validate_volume_name(const char *volume_name) {
@@ -338,7 +356,7 @@ int docker_module_enabled(const struct configuration *conf) {
   return 0;
 }
 
-int get_docker_command(const char *command_file, const struct configuration *conf, char *out, const size_t outlen) {
+int get_docker_command(const char *command_file, const struct configuration *conf, args *args) {
   int ret = 0;
   struct configuration command_config = {0, NULL};
 
@@ -349,23 +367,23 @@ int get_docker_command(const char *command_file, const struct configuration *con
 
   char *command = get_configuration_value("docker-command", DOCKER_COMMAND_FILE_SECTION, &command_config);
   if (strcmp(DOCKER_INSPECT_COMMAND, command) == 0) {
-    return get_docker_inspect_command(command_file, conf, out, outlen);
+    return get_docker_inspect_command(command_file, conf, args);
   } else if (strcmp(DOCKER_KILL_COMMAND, command) == 0) {
-    return get_docker_kill_command(command_file, conf, out, outlen);
+    return get_docker_kill_command(command_file, conf, args);
   } else if (strcmp(DOCKER_LOAD_COMMAND, command) == 0) {
-    return get_docker_load_command(command_file, conf, out, outlen);
+    return get_docker_load_command(command_file, conf, args);
   } else if (strcmp(DOCKER_PULL_COMMAND, command) == 0) {
-    return get_docker_pull_command(command_file, conf, out, outlen);
+    return get_docker_pull_command(command_file, conf, args);
   } else if (strcmp(DOCKER_RM_COMMAND, command) == 0) {
-    return get_docker_rm_command(command_file, conf, out, outlen);
+    return get_docker_rm_command(command_file, conf, args);
   } else if (strcmp(DOCKER_RUN_COMMAND, command) == 0) {
-    return get_docker_run_command(command_file, conf, out, outlen);
+    return get_docker_run_command(command_file, conf, args);
   } else if (strcmp(DOCKER_STOP_COMMAND, command) == 0) {
-    return get_docker_stop_command(command_file, conf, out, outlen);
+    return get_docker_stop_command(command_file, conf, args);
   } else if (strcmp(DOCKER_VOLUME_COMMAND, command) == 0) {
-    return get_docker_volume_command(command_file, conf, out, outlen);
+    return get_docker_volume_command(command_file, conf, args);
   } else if (strcmp(DOCKER_START_COMMAND, command) == 0) {
-    return get_docker_start_command(command_file, conf, out, outlen);
+    return get_docker_start_command(command_file, conf, args);
   } else {
     return UNKNOWN_DOCKER_COMMAND;
   }
@@ -397,10 +415,9 @@ static int value_permitted(const struct configuration* executor_cfg,
   return found;
 }
 
-int get_docker_volume_command(const char *command_file, const struct configuration *conf, char *out,
-                               const size_t outlen) {
+int get_docker_volume_command(const char *command_file, const struct configuration *conf, args *args) {
   int ret = 0;
-  char *driver = NULL, *volume_name = NULL, *sub_command = NULL, *format = NULL;
+  char *driver = NULL, *volume_name = NULL, *sub_command = NULL, *format = NULL, *docker = NULL;
   struct configuration command_config = {0, NULL};
   ret = read_and_verify_command_file(command_file, DOCKER_VOLUME_COMMAND, &command_config);
   if (ret != 0) {
@@ -416,15 +433,20 @@ int get_docker_volume_command(const char *command_file, const struct configurati
     goto cleanup;
   }
 
-  memset(out, 0, outlen);
+  docker = get_docker_binary(conf);
+  ret = add_to_args(args, docker);
+  if (ret != 0) {
+    ret = BUFFER_TOO_SMALL;
+    goto cleanup;
+  }
 
-  ret = add_docker_config_param(&command_config, out, outlen);
+  ret = add_docker_config_param(&command_config, args);
   if (ret != 0) {
     ret = BUFFER_TOO_SMALL;
     goto cleanup;
   }
 
-  ret = add_to_buffer(out, outlen, DOCKER_VOLUME_COMMAND);
+  ret = add_to_args(args, DOCKER_VOLUME_COMMAND);
   if (ret != 0) {
     goto cleanup;
   }
@@ -443,18 +465,16 @@ int get_docker_volume_command(const char *command_file, const struct configurati
       goto cleanup;
     }
 
-    ret = add_to_buffer(out, outlen, " create");
+    ret = add_to_args(args, "create");
     if (ret != 0) {
       goto cleanup;
     }
 
-    ret = add_to_buffer(out, outlen, " --name=");
-    if (ret != 0) {
-      goto cleanup;
-    }
-
-    ret = add_to_buffer(out, outlen, volume_name);
+    char *name_buffer = make_string("--name=%s", volume_name);
+    ret = add_to_args(args, name_buffer);
+    free(name_buffer);
     if (ret != 0) {
+      ret = BUFFER_TOO_SMALL;
       goto cleanup;
     }
 
@@ -465,30 +485,26 @@ int get_docker_volume_command(const char *command_file, const struct configurati
       goto cleanup;
     }
 
-    ret = add_to_buffer(out, outlen, " --driver=");
-    if (ret != 0) {
-      goto cleanup;
-    }
-
-    ret = add_to_buffer(out, outlen, driver);
+    char *driver_buffer = make_string("--driver=%s", driver);
+    ret = add_to_args(args, driver_buffer);
+    free(driver_buffer);
     if (ret != 0) {
+      ret = BUFFER_TOO_SMALL;
       goto cleanup;
     }
   } else if (0 == strcmp(sub_command, "ls")) {
     format = get_configuration_value("format", DOCKER_COMMAND_FILE_SECTION, &command_config);
 
-    ret = add_to_buffer(out, outlen, " ls");
+    ret = add_to_args(args, "ls");
     if (ret != 0) {
       goto cleanup;
     }
-
     if (format) {
-      ret = add_to_buffer(out, outlen, " --format=");
-      if (ret != 0) {
-        goto cleanup;
-      }
-      ret = add_to_buffer(out, outlen, format);
+      char *tmp_buffer = make_string("--format=%s", format);
+      ret = add_to_args(args, tmp_buffer);
+      free(tmp_buffer);
       if (ret != 0) {
+        ret = BUFFER_TOO_SMALL;
         goto cleanup;
       }
     }
@@ -499,20 +515,15 @@ cleanup:
   free(volume_name);
   free(sub_command);
   free(format);
-
-  // clean up out buffer
-  if (ret != 0) {
-    out[0] = 0;
-  }
+  free(docker);
   return ret;
 }
 
-int get_docker_inspect_command(const char *command_file, const struct configuration *conf, char *out,
-                               const size_t outlen) {
+int get_docker_inspect_command(const char *command_file, const struct configuration *conf, args *args) {
   const char *valid_format_strings[] = { "{{.State.Status}}",
                                 "{{range(.NetworkSettings.Networks)}}{{.IPAddress}},{{end}}{{.Config.Hostname}}" };
   int ret = 0, i = 0, valid_format = 0;
-  char *format = NULL, *container_name = NULL;
+  char *format = NULL, *container_name = NULL, *tmp_buffer = NULL;
   struct configuration command_config = {0, NULL};
   ret = read_and_verify_command_file(command_file, DOCKER_INSPECT_COMMAND, &command_config);
   if (ret != 0) {
@@ -542,32 +553,30 @@ int get_docker_inspect_command(const char *command_file, const struct configurat
     return INVALID_DOCKER_INSPECT_FORMAT;
   }
 
-  memset(out, 0, outlen);
+  char *docker = get_docker_binary(conf);
+  ret = add_to_args(args, docker);
+  if (ret != 0) {
+    goto free_and_exit;
+  }
 
-  ret = add_docker_config_param(&command_config, out, outlen);
+  ret = add_docker_config_param(&command_config, args);
   if (ret != 0) {
     free(container_name);
     free(format);
     return BUFFER_TOO_SMALL;
   }
 
-  ret = add_to_buffer(out, outlen, DOCKER_INSPECT_COMMAND);
+  ret = add_to_args(args, DOCKER_INSPECT_COMMAND);
   if (ret != 0) {
     goto free_and_exit;
   }
-  ret = add_to_buffer(out, outlen, " --format=");
-  if (ret != 0) {
-    goto free_and_exit;
-  }
-  ret = add_to_buffer(out, outlen, format);
-  if (ret != 0) {
-    goto free_and_exit;
-  }
-  ret = add_to_buffer(out, outlen, " ");
+  tmp_buffer = make_string("--format=%s", format);
+  ret = add_to_args(args, tmp_buffer);
+  free(tmp_buffer);
   if (ret != 0) {
     goto free_and_exit;
   }
-  ret = add_to_buffer(out, outlen, container_name);
+  ret = add_to_args(args, container_name);
   if (ret != 0) {
     goto free_and_exit;
   }
@@ -578,14 +587,13 @@ int get_docker_inspect_command(const char *command_file, const struct configurat
   free_and_exit:
   free(format);
   free(container_name);
+  free(docker);
   return BUFFER_TOO_SMALL;
 }
 
-int get_docker_load_command(const char *command_file, const struct configuration *conf, char *out, const size_t outlen) {
+int get_docker_load_command(const char *command_file, const struct configuration *conf, args *args) {
   int ret = 0;
   char *image_name = NULL;
-  size_t tmp_buffer_size = 1024;
-  char *tmp_buffer = NULL;
   struct configuration command_config = {0, NULL};
   ret = read_and_verify_command_file(command_file, DOCKER_LOAD_COMMAND, &command_config);
   if (ret != 0) {
@@ -597,19 +605,23 @@ int get_docker_load_command(const char *command_file, const struct configuration
     return INVALID_DOCKER_IMAGE_NAME;
   }
 
-  memset(out, 0, outlen);
+  char *docker = get_docker_binary(conf);
+  ret = add_to_args(args, docker);
+  free(docker);
+  if (ret != 0) {
+    return BUFFER_TOO_SMALL;
+  }
 
-  ret = add_docker_config_param(&command_config, out, outlen);
+  ret = add_docker_config_param(&command_config, args);
   if (ret != 0) {
     free(image_name);
     return BUFFER_TOO_SMALL;
   }
 
-  ret = add_to_buffer(out, outlen, DOCKER_LOAD_COMMAND);
+  ret = add_to_args(args, DOCKER_LOAD_COMMAND);
   if (ret == 0) {
-    tmp_buffer = (char *) alloc_and_clear_memory(tmp_buffer_size, sizeof(char));
-    quote_and_append_arg(&tmp_buffer, &tmp_buffer_size, " --i=", image_name);
-    ret = add_to_buffer(out, outlen, tmp_buffer);
+    char *tmp_buffer = make_string("--i=%s", image_name);
+    ret = add_to_args(args, tmp_buffer);
     free(tmp_buffer);
     free(image_name);
     if (ret != 0) {
@@ -626,11 +638,9 @@ static int validate_docker_image_name(const char *image_name) {
   return execute_regex_match(regex_str, image_name);
 }
 
-int get_docker_pull_command(const char *command_file, const struct configuration *conf, char *out, const size_t outlen) {
+int get_docker_pull_command(const char *command_file, const struct configuration *conf, args *args) {
   int ret = 0;
   char *image_name = NULL;
-  size_t tmp_buffer_size = 1024;
-  char *tmp_buffer = NULL;
   struct configuration command_config = {0, NULL};
   ret = read_and_verify_command_file(command_file, DOCKER_PULL_COMMAND, &command_config);
   if (ret != 0) {
@@ -642,30 +652,33 @@ int get_docker_pull_command(const char *command_file, const struct configuration
     return INVALID_DOCKER_IMAGE_NAME;
   }
 
-  memset(out, 0, outlen);
+  char *docker = get_docker_binary(conf);
+  ret = add_to_args(args, docker);
+  if (ret != 0) {
+    goto free_pull;
+  }
 
-  ret = add_docker_config_param(&command_config, out, outlen);
+  ret = add_docker_config_param(&command_config, args);
   if (ret != 0) {
-    return BUFFER_TOO_SMALL;
+    goto free_pull;
   }
 
-  ret = add_to_buffer(out, outlen, DOCKER_PULL_COMMAND);
+  ret = add_to_args(args, DOCKER_PULL_COMMAND);
   if (ret == 0) {
-    tmp_buffer = (char *) alloc_and_clear_memory(tmp_buffer_size, sizeof(char));
-    quote_and_append_arg(&tmp_buffer, &tmp_buffer_size, " ", image_name);
-    ret = add_to_buffer(out, outlen, tmp_buffer);
-    free(tmp_buffer);
+    ret = add_to_args(args, image_name);
     free(image_name);
     if (ret != 0) {
-      return BUFFER_TOO_SMALL;
+      goto free_pull;
     }
     return 0;
   }
+  free_pull:
   free(image_name);
+  free(docker);
   return BUFFER_TOO_SMALL;
 }
 
-int get_docker_rm_command(const char *command_file, const struct configuration *conf, char *out, const size_t outlen) {
+int get_docker_rm_command(const char *command_file, const struct configuration *conf, args *args) {
   int ret = 0;
   char *container_name = NULL;
   struct configuration command_config = {0, NULL};
@@ -679,19 +692,21 @@ int get_docker_rm_command(const char *command_file, const struct configuration *
     return INVALID_DOCKER_CONTAINER_NAME;
   }
 
-  memset(out, 0, outlen);
+  char *docker = get_docker_binary(conf);
+  ret = add_to_args(args, docker);
+  free(docker);
+  if (ret != 0) {
+    return BUFFER_TOO_SMALL;
+  }
 
-  ret = add_docker_config_param(&command_config, out, outlen);
+  ret = add_docker_config_param(&command_config, args);
   if (ret != 0) {
     return BUFFER_TOO_SMALL;
   }
 
-  ret = add_to_buffer(out, outlen, DOCKER_RM_COMMAND);
+  ret = add_to_args(args, DOCKER_RM_COMMAND);
   if (ret == 0) {
-    ret = add_to_buffer(out, outlen, " ");
-    if (ret == 0) {
-      ret = add_to_buffer(out, outlen, container_name);
-    }
+    ret = add_to_args(args, container_name);
     free(container_name);
     if (ret != 0) {
       return BUFFER_TOO_SMALL;
@@ -703,7 +718,7 @@ int get_docker_rm_command(const char *command_file, const struct configuration *
 }
 
 int get_docker_stop_command(const char *command_file, const struct configuration *conf,
-                            char *out, const size_t outlen) {
+                            args *args) {
   int ret = 0;
   size_t len = 0, i = 0;
   char *value = NULL;
@@ -719,14 +734,19 @@ int get_docker_stop_command(const char *command_file, const struct configuration
     return INVALID_DOCKER_CONTAINER_NAME;
   }
 
-  memset(out, 0, outlen);
+  char *docker = get_docker_binary(conf);
+  ret = add_to_args(args, docker);
+  free(docker);
+  if (ret != 0) {
+    goto free_and_exit;
+  }
 
-  ret = add_docker_config_param(&command_config, out, outlen);
+  ret = add_docker_config_param(&command_config, args);
   if (ret != 0) {
-    return BUFFER_TOO_SMALL;
+    goto free_and_exit;
   }
 
-  ret = add_to_buffer(out, outlen, DOCKER_STOP_COMMAND);
+  ret = add_to_args(args, DOCKER_STOP_COMMAND);
   if (ret == 0) {
     value = get_configuration_value("time", DOCKER_COMMAND_FILE_SECTION, &command_config);
     if (value != NULL) {
@@ -734,36 +754,26 @@ int get_docker_stop_command(const char *command_file, const struct configuration
       for (i = 0; i < len; ++i) {
         if (isdigit(value[i]) == 0) {
           fprintf(ERRORFILE, "Value for time is not a number '%s'\n", value);
-          free(container_name);
-          memset(out, 0, outlen);
-          return INVALID_DOCKER_STOP_COMMAND;
+          ret = INVALID_DOCKER_STOP_COMMAND;
+          goto free_and_exit;
         }
       }
-      ret = add_to_buffer(out, outlen, " --time=");
-      if (ret == 0) {
-        ret = add_to_buffer(out, outlen, value);
-      }
+      char *time_buffer = make_string("--time=%s", value);
+      ret = add_to_args(args, time_buffer);
+      free(time_buffer);
       if (ret != 0) {
-        free(container_name);
-        return BUFFER_TOO_SMALL;
+        goto free_and_exit;
       }
     }
-    ret = add_to_buffer(out, outlen, " ");
-    if (ret == 0) {
-      ret = add_to_buffer(out, outlen, container_name);
-    }
-    free(container_name);
-    if (ret != 0) {
-      return BUFFER_TOO_SMALL;
-    }
-    return 0;
+    ret = add_to_args(args, container_name);
   }
+free_and_exit:
   free(container_name);
-  return BUFFER_TOO_SMALL;
+  return ret;
 }
 
 int get_docker_kill_command(const char *command_file, const struct configuration *conf,
-                            char *out, const size_t outlen) {
+                            args *args) {
   int ret = 0;
   size_t len = 0, i = 0;
   char *value = NULL;
@@ -779,14 +789,19 @@ int get_docker_kill_command(const char *command_file, const struct configuration
     return INVALID_DOCKER_CONTAINER_NAME;
   }
 
-  memset(out, 0, outlen);
+  char *docker = get_docker_binary(conf);
+  ret = add_to_args(args, docker);
+  free(docker);
+  if (ret != 0) {
+    return BUFFER_TOO_SMALL;
+  }
 
-  ret = add_docker_config_param(&command_config, out, outlen);
+  ret = add_docker_config_param(&command_config, args);
   if (ret != 0) {
     return BUFFER_TOO_SMALL;
   }
 
-  ret = add_to_buffer(out, outlen, DOCKER_KILL_COMMAND);
+  ret = add_to_args(args, DOCKER_KILL_COMMAND);
   if (ret == 0) {
     value = get_configuration_value("signal", DOCKER_COMMAND_FILE_SECTION, &command_config);
     if (value != NULL) {
@@ -794,35 +809,26 @@ int get_docker_kill_command(const char *command_file, const struct configuration
       for (i = 0; i < len; ++i) {
         if (isupper(value[i]) == 0) {
           fprintf(ERRORFILE, "Value for signal contains non-uppercase characters '%s'\n", value);
-          free(container_name);
-          memset(out, 0, outlen);
-          return INVALID_DOCKER_KILL_COMMAND;
+          ret = INVALID_DOCKER_KILL_COMMAND;
+          goto free_and_exit;
         }
       }
-      ret = add_to_buffer(out, outlen, " --signal=");
-      if (ret == 0) {
-        ret = add_to_buffer(out, outlen, value);
-      }
+
+      char *signal_buffer = make_string("--signal=%s", value);
+      ret = add_to_args(args, signal_buffer);
+      free(signal_buffer);
       if (ret != 0) {
-        free(container_name);
-        return BUFFER_TOO_SMALL;
+        goto free_and_exit;
       }
     }
-    ret = add_to_buffer(out, outlen, " ");
-    if (ret == 0) {
-      ret = add_to_buffer(out, outlen, container_name);
-    }
-    free(container_name);
-    if (ret != 0) {
-      return BUFFER_TOO_SMALL;
-    }
-    return 0;
+    ret = add_to_args(args, container_name);
   }
+free_and_exit:
   free(container_name);
-  return BUFFER_TOO_SMALL;
+  return ret;
 }
 
-int get_docker_start_command(const char *command_file, const struct configuration *conf, char *out, const size_t outlen) {
+int get_docker_start_command(const char *command_file, const struct configuration *conf, args *args) {
   int ret = 0;
   char *container_name = NULL;
   struct configuration command_config = {0, NULL};
@@ -836,99 +842,86 @@ int get_docker_start_command(const char *command_file, const struct configuratio
     return INVALID_DOCKER_CONTAINER_NAME;
   }
 
-  memset(out, 0, outlen);
-
-  ret = add_docker_config_param(&command_config, out, outlen);
+  ret = add_docker_config_param(&command_config, args);
   if (ret != 0) {
     return BUFFER_TOO_SMALL;
   }
 
-  ret = add_to_buffer(out, outlen, DOCKER_START_COMMAND);
-  if (ret != 0) {
-    goto free_and_exit;
-  }
-  ret = add_to_buffer(out, outlen, " ");
-  if (ret != 0) {
-    goto free_and_exit;
-  }
-  ret = add_to_buffer(out, outlen, container_name);
+  ret = add_to_args(args, DOCKER_START_COMMAND);
   if (ret != 0) {
     goto free_and_exit;
   }
+  ret = add_to_args(args, container_name);
 free_and_exit:
   free(container_name);
   return ret;
 }
 
-static int detach_container(const struct configuration *command_config, char *out, const size_t outlen) {
-  return add_param_to_command(command_config, "detach", "-d ", 0, out, outlen);
+static int detach_container(const struct configuration *command_config, args *args) {
+  return add_param_to_command(command_config, "detach", "-d", 0, args);
 }
 
-static int  rm_container_on_exit(const struct configuration *command_config, char *out, const size_t outlen) {
-  return add_param_to_command(command_config, "rm", "--rm ", 0, out, outlen);
+static int  rm_container_on_exit(const struct configuration *command_config, args *args) {
+  return add_param_to_command(command_config, "rm", "--rm", 0, args);
 }
 
-static int set_container_workdir(const struct configuration *command_config, char *out, const size_t outlen) {
-  return add_param_to_command(command_config, "workdir", "--workdir=", 1, out, outlen);
+static int set_container_workdir(const struct configuration *command_config, args *args) {
+  return add_param_to_command(command_config, "workdir", "--workdir=", 1, args);
 }
 
-static int set_cgroup_parent(const struct configuration *command_config, char *out, const size_t outlen) {
-  return add_param_to_command(command_config, "cgroup-parent", "--cgroup-parent=", 1, out, outlen);
+static int set_cgroup_parent(const struct configuration *command_config, args *args) {
+  return add_param_to_command(command_config, "cgroup-parent", "--cgroup-parent=", 1, args);
 }
 
-static int set_hostname(const struct configuration *command_config, char *out, const size_t outlen) {
-  return add_param_to_command(command_config, "hostname", "--hostname=", 1, out, outlen);
+static int set_hostname(const struct configuration *command_config, args *args) {
+  return add_param_to_command(command_config, "hostname", "--hostname=", 1, args);
 }
 
-static int set_group_add(const struct configuration *command_config, char *out, const size_t outlen) {
+static int set_group_add(const struct configuration *command_config, args *args) {
   int i = 0, ret = 0;
   char **group_add = get_configuration_values_delimiter("group-add", DOCKER_COMMAND_FILE_SECTION, command_config, ",");
-  size_t tmp_buffer_size = 4096;
-  char *tmp_buffer = NULL;
   char *privileged = NULL;
 
   privileged = get_configuration_value("privileged", DOCKER_COMMAND_FILE_SECTION, command_config);
   if (privileged != NULL && strcasecmp(privileged, "true") == 0 ) {
-    free(privileged);
-    return ret;
+    goto free_and_exit;
   }
-  free(privileged);
 
   if (group_add != NULL) {
     for (i = 0; group_add[i] != NULL; ++i) {
-      tmp_buffer = (char *) alloc_and_clear_memory(tmp_buffer_size, sizeof(char));
-      quote_and_append_arg(&tmp_buffer, &tmp_buffer_size, "--group-add ", group_add[i]);
-      ret = add_to_buffer(out, outlen, tmp_buffer);
+      ret = add_to_args(args, "--group-add");
       if (ret != 0) {
-        return BUFFER_TOO_SMALL;
+        goto free_and_exit;
+      }
+      ret = add_to_args(args, group_add[i]);
+      if (ret != 0) {
+        goto free_and_exit;
       }
     }
   }
+free_and_exit:
+  free_values(group_add);
+  free(privileged);
   return ret;
 }
 
 static int set_network(const struct configuration *command_config,
-                       const struct configuration *conf, char *out,
-                       const size_t outlen) {
+                       const struct configuration *conf, args *args) {
 
   int ret = 0;
   ret = add_param_to_command_if_allowed(command_config, conf, "net",
                                         "docker.allowed.networks", "--net=",
-                                        0, 0, out, outlen);
+                                        0, 0, args);
   if (ret != 0) {
     fprintf(ERRORFILE, "Could not find requested network in allowed networks\n");
     ret = INVALID_DOCKER_NETWORK;
-    memset(out, 0, outlen);
   }
 
   return ret;
 }
 
 static int set_pid_namespace(const struct configuration *command_config,
-                   const struct configuration *conf, char *out,
-                   const size_t outlen) {
-  size_t tmp_buffer_size = 1024;
-  char *tmp_buffer = (char *) alloc_and_clear_memory(tmp_buffer_size, sizeof(char));
+                   const struct configuration *conf, args *args) {
   char *value = get_configuration_value("pid", DOCKER_COMMAND_FILE_SECTION,
       command_config);
   char *pid_host_enabled = get_configuration_value("docker.host-pid-namespace.enabled",
@@ -940,7 +933,7 @@ static int set_pid_namespace(const struct configuration *command_config,
       if (pid_host_enabled != NULL) {
         if (strcmp(pid_host_enabled, "1") == 0 ||
             strcasecmp(pid_host_enabled, "True") == 0) {
-          ret = add_to_buffer(out, outlen, "--pid='host' ");
+          ret = add_to_args(args, "--pid='host'");
           if (ret != 0) {
             ret = BUFFER_TOO_SMALL;
           }
@@ -960,23 +953,17 @@ static int set_pid_namespace(const struct configuration *command_config,
     }
   }
 
-  free_and_exit:
-  free(tmp_buffer);
+free_and_exit:
   free(value);
   free(pid_host_enabled);
-  if (ret != 0) {
-    memset(out, 0, outlen);
-  }
   return ret;
 }
 
 static int set_capabilities(const struct configuration *command_config,
-                            const struct configuration *conf, char *out,
-                            const size_t outlen) {
-
+                            const struct configuration *conf, args *args) {
   int ret = 0;
 
-  ret = add_to_buffer(out, outlen, "--cap-drop='ALL' ");
+  ret = add_to_args(args, "--cap-drop=ALL");
   if (ret != 0) {
     return BUFFER_TOO_SMALL;
   }
@@ -984,7 +971,7 @@ static int set_capabilities(const struct configuration *command_config,
   ret = add_param_to_command_if_allowed(command_config, conf, "cap-add",
                                         "docker.allowed.capabilities",
                                         "--cap-add=", 1, 0,
-                                        out, outlen);
+                                        args);
   switch (ret) {
     case 0:
       break;
@@ -995,21 +982,18 @@ static int set_capabilities(const struct configuration *command_config,
     default:
       fprintf(ERRORFILE, "Invalid docker capability requested\n");
       ret = INVALID_DOCKER_CAPABILITY;
-      memset(out, 0, outlen);
   }
 
   return ret;
 }
 
-static int set_devices(const struct configuration *command_config, const struct configuration *conf, char *out,
-                       const size_t outlen) {
+static int set_devices(const struct configuration *command_config, const struct configuration *conf, args *args) {
   int ret = 0;
   ret = add_param_to_command_if_allowed(command_config, conf, "devices", "docker.allowed.devices", "--device=", 1, ':',
-                                        out, outlen);
+                                        args);
   if (ret != 0) {
     fprintf(ERRORFILE, "Invalid docker device requested\n");
     ret = INVALID_DOCKER_DEVICE;
-    memset(out, 0, outlen);
   }
 
   return ret;
@@ -1046,7 +1030,6 @@ static char* normalize_mount(const char* mount, int isRegexAllowed) {
       }
     }
     fprintf(ERRORFILE, "Could not determine real path of mount '%s'\n", mount);
-    free(real_mount);
     return NULL;
   }
   ret = stat(real_mount, &buff);
@@ -1054,6 +1037,7 @@ static char* normalize_mount(const char* mount, int isRegexAllowed) {
     if (S_ISDIR(buff.st_mode)) {
       size_t len = strlen(real_mount);
       if (len <= 0) {
+        free(real_mount);
         return NULL;
       }
       if (real_mount[len - 1] != '/') {
@@ -1095,10 +1079,10 @@ static int normalize_mounts(char **mounts, int isRegexAllowed) {
 static int check_mount_permitted(const char **permitted_mounts, const char *requested) {
   int i = 0, ret = 0;
   size_t permitted_mount_len = 0;
-  char *normalized_path = normalize_mount(requested, 0);
   if (permitted_mounts == NULL) {
     return 0;
   }
+  char *normalized_path = normalize_mount(requested, 0);
   if (normalized_path == NULL) {
     return -1;
   }
@@ -1124,36 +1108,31 @@ static int check_mount_permitted(const char **permitted_mounts, const char *requ
         break;
       }
     }
-
   }
   free(normalized_path);
   return ret;
 }
 
 static char* get_mount_source(const char *mount) {
-  char *src_mount = NULL;
-  const char *tmp = NULL;
-  tmp = strchr(mount, ':');
+  const char *tmp = strchr(mount, ':');
   if (tmp == NULL) {
     fprintf(ERRORFILE, "Invalid docker mount '%s'\n", mount);
     return NULL;
   }
-  src_mount = strndup(mount, tmp - mount);
-  return src_mount;
+  size_t len = tmp - mount;
+  return strndup(mount, len);
 }
 
 static int add_mounts(const struct configuration *command_config, const struct configuration *conf, const char *key,
-                      const int ro, char *out, const size_t outlen) {
-  size_t tmp_buffer_size = 1024;
+                      const int ro, args *args) {
   const char *ro_suffix = "";
   const char *tmp_path_buffer[2] = {NULL, NULL};
-  char *tmp_buffer = (char *) alloc_and_clear_memory(tmp_buffer_size, sizeof(char));
+  char *mount_src = NULL;
   char **permitted_ro_mounts = get_configuration_values_delimiter("docker.allowed.ro-mounts",
                                                                   CONTAINER_EXECUTOR_CFG_DOCKER_SECTION, conf, ",");
   char **permitted_rw_mounts = get_configuration_values_delimiter("docker.allowed.rw-mounts",
                                                                   CONTAINER_EXECUTOR_CFG_DOCKER_SECTION, conf, ",");
   char **values = get_configuration_values_delimiter(key, DOCKER_COMMAND_FILE_SECTION, command_config, ",");
-  char *tmp_buffer_2 = NULL, *mount_src = NULL;
   const char *container_executor_cfg_path = normalize_mount(get_config_path(""), 0);
   int i = 0, permitted_rw = 0, permitted_ro = 0, ret = 0;
   if (ro != 0) {
@@ -1180,10 +1159,10 @@ static int add_mounts(const struct configuration *command_config, const struct c
       ret = MOUNT_ACCESS_ERROR;
       goto free_and_exit;
     }
-    for (i = 0; values[i] != NULL; ++i) {
+    for (i = 0; values[i] != NULL; i++) {
       mount_src = get_mount_source(values[i]);
       if (mount_src == NULL) {
-        fprintf(ERRORFILE, "Invalid docker mount '%s', realpath=%s\n", values[i], mount_src);
+        fprintf(ERRORFILE, "Invalid docker mount '%s'\n", values[i]);
         ret = INVALID_DOCKER_MOUNT;
         goto free_and_exit;
       }
@@ -1221,16 +1200,16 @@ static int add_mounts(const struct configuration *command_config, const struct c
         ret = INVALID_DOCKER_RO_MOUNT;
         goto free_and_exit;
       }
-      tmp_buffer_2 = (char *) alloc_and_clear_memory(strlen(values[i]) + strlen(ro_suffix) + 1, sizeof(char));
-      strncpy(tmp_buffer_2, values[i], strlen(values[i]));
-      strncpy(tmp_buffer_2 + strlen(values[i]), ro_suffix, strlen(ro_suffix));
-      quote_and_append_arg(&tmp_buffer, &tmp_buffer_size, "-v ", tmp_buffer_2);
-      ret = add_to_buffer(out, outlen, tmp_buffer);
-      free(tmp_buffer_2);
-      free(mount_src);
-      tmp_buffer_2 = NULL;
-      mount_src = NULL;
-      memset(tmp_buffer, 0, tmp_buffer_size);
+
+      ret = add_to_args(args, "-v");
+      if (ret != 0) {
+        ret = BUFFER_TOO_SMALL;
+        goto free_and_exit;
+      }
+
+      char *tmp_buffer = make_string("%s%s", values[i], (char *) ro_suffix);
+      ret = add_to_args(args, tmp_buffer);
+      free(tmp_buffer);
       if (ret != 0) {
         ret = BUFFER_TOO_SMALL;
         goto free_and_exit;
@@ -1238,27 +1217,21 @@ static int add_mounts(const struct configuration *command_config, const struct c
     }
   }
 
-  free_and_exit:
+free_and_exit:
+  free(mount_src);
   free_values(permitted_ro_mounts);
   free_values(permitted_rw_mounts);
   free_values(values);
-  free(mount_src);
   free((void *) container_executor_cfg_path);
-  free(tmp_buffer);
-  if (ret != 0) {
-    memset(out, 0, outlen);
-  }
   return ret;
 }
 
-static int add_ro_mounts(const struct configuration *command_config, const struct configuration *conf, char *out,
-                          const size_t outlen) {
-  return add_mounts(command_config, conf, "ro-mounts", 1, out, outlen);
+static int add_ro_mounts(const struct configuration *command_config, const struct configuration *conf, args *args) {
+  return add_mounts(command_config, conf, "ro-mounts", 1, args);
 }
 
-static int  add_rw_mounts(const struct configuration *command_config, const struct configuration *conf, char *out,
-                          const size_t outlen) {
-  return add_mounts(command_config, conf, "rw-mounts", 0, out, outlen);
+static int  add_rw_mounts(const struct configuration *command_config, const struct configuration *conf, args *args) {
+  return add_mounts(command_config, conf, "rw-mounts", 0, args);
 }
 
 static int check_privileges(const char *user) {
@@ -1334,20 +1307,18 @@ static int check_privileges(const char *user) {
   return ret;
 }
 
-static int set_privileged(const struct configuration *command_config, const struct configuration *conf, char *out,
-                          const size_t outlen) {
-  size_t tmp_buffer_size = 1024;
+static int set_privileged(const struct configuration *command_config, const struct configuration *conf, args *args) {
   char *user = NULL;
-  char *tmp_buffer = (char *) alloc_and_clear_memory(tmp_buffer_size, sizeof(char));
   char *value = get_configuration_value("privileged", DOCKER_COMMAND_FILE_SECTION, command_config);
   char *privileged_container_enabled
       = get_configuration_value("docker.privileged-containers.enabled", CONTAINER_EXECUTOR_CFG_DOCKER_SECTION, conf);
   int ret = 0;
-  int allowed = 0;
+  int allowed = 1;
 
   user = get_configuration_value("user", DOCKER_COMMAND_FILE_SECTION, command_config);
   if (user == NULL) {
-    return INVALID_DOCKER_USER_NAME;
+    ret = INVALID_DOCKER_USER_NAME;
+    goto free_and_exit;
   }
 
   if (value != NULL && strcasecmp(value, "true") == 0 ) {
@@ -1362,7 +1333,7 @@ static int set_privileged(const struct configuration *command_config, const stru
         }
         allowed = check_privileges(user);
         if (allowed) {
-          ret = add_to_buffer(out, outlen, "--privileged ");
+          ret = add_to_args(args, "--privileged");
           if (ret != 0) {
             ret = BUFFER_TOO_SMALL;
           }
@@ -1384,20 +1355,15 @@ static int set_privileged(const struct configuration *command_config, const stru
   }
 
   free_and_exit:
-  free(tmp_buffer);
   free(value);
   free(privileged_container_enabled);
   free(user);
-  if (ret != 0) {
-    memset(out, 0, outlen);
-  }
   return ret;
 }
 
-int get_docker_run_command(const char *command_file, const struct configuration *conf, char *out, const size_t outlen) {
+int get_docker_run_command(const char *command_file, const struct configuration *conf, args *args) {
   int ret = 0, i = 0;
   char *container_name = NULL, *user = NULL, *image = NULL;
-  size_t tmp_buffer_size = 1024;
   char *tmp_buffer = NULL;
   char **launch_command = NULL;
   char *privileged = NULL;
@@ -1409,6 +1375,9 @@ int get_docker_run_command(const char *command_file, const struct configuration
 
   container_name = get_configuration_value("name", DOCKER_COMMAND_FILE_SECTION, &command_config);
   if (container_name == NULL || validate_container_name(container_name) != 0) {
+    if (container_name != NULL) {
+      free(container_name);
+    }
     return INVALID_DOCKER_CONTAINER_NAME;
   }
   user = get_configuration_value("user", DOCKER_COMMAND_FILE_SECTION, &command_config);
@@ -1417,127 +1386,148 @@ int get_docker_run_command(const char *command_file, const struct configuration
   }
   image = get_configuration_value("image", DOCKER_COMMAND_FILE_SECTION, &command_config);
   if (image == NULL || validate_docker_image_name(image) != 0) {
+    if (image != NULL) {
+      free(image);
+    }
     return INVALID_DOCKER_IMAGE_NAME;
   }
 
-  ret = add_docker_config_param(&command_config, out, outlen);
+  char *docker = get_docker_binary(conf);
+  ret = add_to_args(args, docker);
+  free(docker);
   if (ret != 0) {
+    reset_args(args);
     return BUFFER_TOO_SMALL;
   }
 
-  ret = add_to_buffer(out, outlen, DOCKER_RUN_COMMAND);
-  if(ret != 0) {
+  ret = add_docker_config_param(&command_config, args);
+  if (ret != 0) {
+    reset_args(args);
     return BUFFER_TOO_SMALL;
   }
 
+  ret = add_to_args(args, DOCKER_RUN_COMMAND);
+  if(ret != 0) {
+    reset_args(args);
+    return BUFFER_TOO_SMALL;
+  }
 
-  tmp_buffer = (char *) alloc_and_clear_memory(tmp_buffer_size, sizeof(char));
-
-  quote_and_append_arg(&tmp_buffer, &tmp_buffer_size, " --name=", container_name);
-  ret = add_to_buffer(out, outlen, tmp_buffer);
+  tmp_buffer = make_string("--name=%s", container_name);
+  ret = add_to_args(args, tmp_buffer);
   if (ret != 0) {
+    reset_args(args);
     return BUFFER_TOO_SMALL;
   }
-  memset(tmp_buffer, 0, tmp_buffer_size);
 
   privileged = get_configuration_value("privileged", DOCKER_COMMAND_FILE_SECTION, &command_config);
 
-  if (privileged == NULL || strcasecmp(privileged, "false") == 0) {
-      quote_and_append_arg(&tmp_buffer, &tmp_buffer_size, "--user=", user);
-      ret = add_to_buffer(out, outlen, tmp_buffer);
-      if (ret != 0) {
-        return BUFFER_TOO_SMALL;
-      }
-      memset(tmp_buffer, 0, tmp_buffer_size);
+  if (privileged == NULL || strcmp(privileged, "false") == 0) {
+    char *user_buffer = make_string("--user=%s", user);
+    ret = add_to_args(args, user_buffer);
+    free(user_buffer);
+    if (ret != 0) {
+      reset_args(args);
+      return BUFFER_TOO_SMALL;
+    }
   }
   free(privileged);
 
-  ret = detach_container(&command_config, out, outlen);
+  ret = detach_container(&command_config, args);
   if (ret != 0) {
+    reset_args(args);
     return ret;
   }
 
-  ret = rm_container_on_exit(&command_config, out, outlen);
+  ret = rm_container_on_exit(&command_config, args);
   if (ret != 0) {
+    reset_args(args);
     return ret;
   }
 
-  ret = set_container_workdir(&command_config, out, outlen);
+  ret = set_container_workdir(&command_config, args);
   if (ret != 0) {
+    reset_args(args);
     return ret;
   }
 
-  ret = set_network(&command_config, conf, out, outlen);
+  ret = set_network(&command_config, conf, args);
   if (ret != 0) {
+    reset_args(args);
     return ret;
   }
 
-  ret = set_pid_namespace(&command_config, conf, out, outlen);
+  ret = set_pid_namespace(&command_config, conf, args);
   if (ret != 0) {
+    reset_args(args);
     return ret;
   }
 
-  ret = add_ro_mounts(&command_config, conf, out, outlen);
+  ret = add_ro_mounts(&command_config, conf, args);
   if (ret != 0) {
+    reset_args(args);
     return ret;
   }
 
-  ret = add_rw_mounts(&command_config, conf, out, outlen);
+  ret = add_rw_mounts(&command_config, conf, args);
   if (ret != 0) {
+    reset_args(args);
     return ret;
   }
 
-  ret = set_cgroup_parent(&command_config, out, outlen);
+  ret = set_cgroup_parent(&command_config, args);
   if (ret != 0) {
+    reset_args(args);
     return ret;
   }
 
-  ret = set_privileged(&command_config, conf, out, outlen);
+  ret = set_privileged(&command_config, conf, args);
   if (ret != 0) {
+    reset_args(args);
     return ret;
   }
 
-  ret = set_capabilities(&command_config, conf, out, outlen);
+  ret = set_capabilities(&command_config, conf, args);
   if (ret != 0) {
+    reset_args(args);
     return ret;
   }
 
-  ret = set_hostname(&command_config, out, outlen);
+  ret = set_hostname(&command_config, args);
   if (ret != 0) {
+    reset_args(args);
     return ret;
   }
 
-  ret = set_group_add(&command_config, out, outlen);
+  ret = set_group_add(&command_config, args);
   if (ret != 0) {
+    reset_args(args);
     return ret;
   }
 
-  ret = set_devices(&command_config, conf, out, outlen);
+  ret = set_devices(&command_config, conf, args);
   if (ret != 0) {
+    reset_args(args);
     return ret;
   }
 
-  quote_and_append_arg(&tmp_buffer, &tmp_buffer_size, "", image);
-  ret = add_to_buffer(out, outlen, tmp_buffer);
+  ret = add_to_args(args, image);
   if (ret != 0) {
+    reset_args(args);
     return BUFFER_TOO_SMALL;
   }
 
   launch_command = get_configuration_values_delimiter("launch-command", DOCKER_COMMAND_FILE_SECTION, &command_config,
                                                       ",");
-
   if (check_trusted_image(&command_config, conf) != 0) {
     launch_command = NULL;
   }
 
   if (launch_command != NULL) {
     for (i = 0; launch_command[i] != NULL; ++i) {
-      memset(tmp_buffer, 0, tmp_buffer_size);
-      quote_and_append_arg(&tmp_buffer, &tmp_buffer_size, "", launch_command[i]);
-      ret = add_to_buffer(out, outlen, tmp_buffer);
+      ret = add_to_args(args, launch_command[i]);
       if (ret != 0) {
         free_values(launch_command);
-        free(tmp_buffer);
+        reset_args(args);
         return BUFFER_TOO_SMALL;
       }
     }
@@ -1546,6 +1536,3 @@ int get_docker_run_command(const char *command_file, const struct configuration
   free(tmp_buffer);
   return 0;
 }
-
-
-

http://git-wip-us.apache.org/repos/asf/hadoop/blob/a2ea7564/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/utils/docker-util.h
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/utils/docker-util.h b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/utils/docker-util.h
index c797ecd..330d722 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/utils/docker-util.h
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/utils/docker-util.h
@@ -33,7 +33,13 @@
 #define DOCKER_KILL_COMMAND "kill"
 #define DOCKER_VOLUME_COMMAND "volume"
 #define DOCKER_START_COMMAND "start"
+#define DOCKER_ARG_MAX 1024
+#define ARGS_INITIAL_VALUE { 0 };
 
+typedef struct args {
+    int length;
+    char *data[DOCKER_ARG_MAX];
+} args;
 
 enum docker_error_codes {
     INVALID_COMMAND_FILE = 1,
@@ -77,7 +83,7 @@ char *get_docker_binary(const struct configuration *conf);
  * @param outlen Size of the output buffer
  * @return Return code with 0 indicating success and non-zero codes indicating error
  */
-int get_docker_command(const char* command_file, const struct configuration* conf, char *out, const size_t outlen);
+int get_docker_command(const char* command_file, const struct configuration* conf, args *args);
 
 /**
  * Get the Docker inspect command line string. The function will verify that the params file is meant for the
@@ -88,7 +94,7 @@ int get_docker_command(const char* command_file, const struct configuration* con
  * @param outlen Size of the output buffer
  * @return Return code with 0 indicating success and non-zero codes indicating error
  */
-int get_docker_inspect_command(const char* command_file, const struct configuration* conf, char *out, const size_t outlen);
+int get_docker_inspect_command(const char* command_file, const struct configuration* conf, args *args);
 
 /**
  * Get the Docker load command line string. The function will verify that the params file is meant for the load command.
@@ -98,7 +104,7 @@ int get_docker_inspect_command(const char* command_file, const struct configurat
  * @param outlen Size of the output buffer
  * @return Return code with 0 indicating success and non-zero codes indicating error
  */
-int get_docker_load_command(const char* command_file, const struct configuration* conf, char *out, const size_t outlen);
+int get_docker_load_command(const char* command_file, const struct configuration* conf, args *args);
 
 /**
  * Get the Docker pull command line string. The function will verify that the params file is meant for the pull command.
@@ -108,7 +114,7 @@ int get_docker_load_command(const char* command_file, const struct configuration
  * @param outlen Size of the output buffer
  * @return Return code with 0 indicating success and non-zero codes indicating error
  */
-int get_docker_pull_command(const char* command_file, const struct configuration* conf, char *out, const size_t outlen);
+int get_docker_pull_command(const char* command_file, const struct configuration* conf, args *args);
 
 /**
  * Get the Docker rm command line string. The function will verify that the params file is meant for the rm command.
@@ -118,7 +124,7 @@ int get_docker_pull_command(const char* command_file, const struct configuration
  * @param outlen Size of the output buffer
  * @return Return code with 0 indicating success and non-zero codes indicating error
  */
-int get_docker_rm_command(const char* command_file, const struct configuration* conf, char *out, const size_t outlen);
+int get_docker_rm_command(const char* command_file, const struct configuration* conf, args *args);
 
 /**
  * Get the Docker run command line string. The function will verify that the params file is meant for the run command.
@@ -128,7 +134,7 @@ int get_docker_rm_command(const char* command_file, const struct configuration*
  * @param outlen Size of the output buffer
  * @return Return code with 0 indicating success and non-zero codes indicating error
  */
-int get_docker_run_command(const char* command_file, const struct configuration* conf, char *out, const size_t outlen);
+int get_docker_run_command(const char* command_file, const struct configuration* conf, args *args);
 
 /**
  * Get the Docker stop command line string. The function will verify that the params file is meant for the stop command.
@@ -138,7 +144,7 @@ int get_docker_run_command(const char* command_file, const struct configuration*
  * @param outlen Size of the output buffer
  * @return Return code with 0 indicating success and non-zero codes indicating error
  */
-int get_docker_stop_command(const char* command_file, const struct configuration* conf, char *out, const size_t outlen);
+int get_docker_stop_command(const char* command_file, const struct configuration* conf, args *args);
 
 /**
  * Get the Docker kill command line string. The function will verify that the params file is meant for the kill command.
@@ -148,7 +154,7 @@ int get_docker_stop_command(const char* command_file, const struct configuration
  * @param outlen Size of the output buffer
  * @return Return code with 0 indicating success and non-zero codes indicating error
  */
-int get_docker_kill_command(const char* command_file, const struct configuration* conf, char *out, const size_t outlen);
+int get_docker_kill_command(const char* command_file, const struct configuration* conf, args *args);
 
 /**
  * Get the Docker volume command line string. The function will verify that the
@@ -159,8 +165,7 @@ int get_docker_kill_command(const char* command_file, const struct configuration
  * @param outlen Size of the output buffer
  * @return Return code with 0 indicating success and non-zero codes indicating error
  */
-int get_docker_volume_command(const char *command_file, const struct configuration *conf, char *out,
-                               const size_t outlen);
+int get_docker_volume_command(const char *command_file, const struct configuration *conf, args *args);
 
 /**
  * Get the Docker start command line string. The function will verify that the params file is meant for the start command.
@@ -170,7 +175,7 @@ int get_docker_volume_command(const char *command_file, const struct configurati
  * @param outlen Size of the output buffer
  * @return Return code with 0 indicating success and non-zero codes indicating error
  */
-int get_docker_start_command(const char* command_file, const struct configuration* conf, char *out, const size_t outlen);
+int get_docker_start_command(const char* command_file, const struct configuration* conf, args *args);
 
 /**
  * Give an error message for the supplied error code
@@ -186,4 +191,15 @@ const char *get_docker_error_message(const int error_code);
  */
 int docker_module_enabled(const struct configuration *conf);
 
+/**
+ * Helper function to reset args data structure.
+ * @param args Pointer reference to args data structure
+ */
+void reset_args(args *args);
+
+/**
+ * Extract execv args from args data structure.
+ * @param args Pointer reference to args data structure
+ */
+char** extract_execv_args(args *args);
 #endif

http://git-wip-us.apache.org/repos/asf/hadoop/blob/a2ea7564/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/utils/string-utils.c
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/utils/string-utils.c b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/utils/string-utils.c
index 40b2c25..80511e5 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/utils/string-utils.c
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/utils/string-utils.c
@@ -22,6 +22,7 @@
 #include <strings.h>
 #include <string.h>
 #include <stdlib.h>
+#include <stdarg.h>
 
 /*
  * if all chars in the input str are numbers
@@ -156,3 +157,26 @@ cleanup:
   }
   return is_container_id;
 }
+
+/*
+ * Format string utility.
+ */
+char *make_string(const char *fmt, ...) {
+  va_list vargs;
+  va_start(vargs, fmt);
+  size_t buflen = vsnprintf(NULL, 0, fmt, vargs) + 1;
+  va_end(vargs);
+  if (buflen <= 0) {
+    return NULL;
+  }
+  char* buf = malloc(buflen);
+  if (buf != NULL) {
+    va_start(vargs, fmt);
+    int ret = vsnprintf(buf, buflen, fmt, vargs);
+    va_end(vargs);
+    if (ret < 0) {
+      buf = NULL;
+    }
+  }
+  return buf;
+}

http://git-wip-us.apache.org/repos/asf/hadoop/blob/a2ea7564/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/utils/string-utils.h
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/utils/string-utils.h b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/utils/string-utils.h
index c095eb6..affb3c3 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/utils/string-utils.h
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/utils/string-utils.h
@@ -34,4 +34,8 @@ int validate_container_id(const char* input);
  */
 int get_numbers_split_by_comma(const char* input, int** numbers, size_t* n_numbers);
 
+/*
+ * String format utility
+ */
+char *make_string(const char *fmt, ...);
 #endif


---------------------------------------------------------------------
To unsubscribe, e-mail: common-commits-unsubscribe@hadoop.apache.org
For additional commands, e-mail: common-commits-help@hadoop.apache.org