]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
utils: add run_command
authorChristian Brauner <christian.brauner@ubuntu.com>
Mon, 29 May 2017 02:30:50 +0000 (04:30 +0200)
committerChristian Brauner <christian.brauner@ubuntu.com>
Tue, 30 May 2017 07:11:47 +0000 (09:11 +0200)
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
src/lxc/utils.c
src/lxc/utils.h

index cc7e800201854cb074b2a99d6aa993598df1d158..ca7d768583a995979cb1a86d7f99e1c6540376af 100644 (file)
@@ -2246,3 +2246,65 @@ pop_stack:
 
        return umounts;
 }
+
+int run_command(char *buf, size_t buf_size, int (*child_fn)(void *), void *args)
+{
+       pid_t child;
+       int ret, fret, pipefd[2];
+       ssize_t bytes;
+
+       /* Make sure our callers do not receive unitialized memory. */
+       if (buf_size > 0 && buf)
+               buf[0] = '\0';
+
+       if (pipe(pipefd) < 0) {
+               SYSERROR("failed to create pipe");
+               return -1;
+       }
+
+       child = fork();
+       if (child < 0) {
+               close(pipefd[0]);
+               close(pipefd[1]);
+               SYSERROR("failed to create new process");
+               return -1;
+       }
+
+       if (child == 0) {
+               /* Close the read-end of the pipe. */
+               close(pipefd[0]);
+
+               /* Redirect std{err,out} to write-end of the
+                * pipe.
+                */
+               ret = dup2(pipefd[1], STDOUT_FILENO);
+               if (ret >= 0)
+                       ret = dup2(pipefd[1], STDERR_FILENO);
+
+               /* Close the write-end of the pipe. */
+               close(pipefd[1]);
+
+               if (ret < 0) {
+                       SYSERROR("failed to duplicate std{err,out} file descriptor");
+                       exit(EXIT_FAILURE);
+               }
+
+               /* Does not return. */
+               child_fn(args);
+               ERROR("failed to exec command");
+               exit(EXIT_FAILURE);
+       }
+
+       /* close the write-end of the pipe */
+       close(pipefd[1]);
+
+       bytes = read(pipefd[0], buf, (buf_size > 0) ? (buf_size - 1) : 0);
+       if (bytes > 0)
+               buf[bytes - 1] = '\0';
+
+       fret = wait_for_pid(child);
+       /* close the read-end of the pipe */
+       close(pipefd[0]);
+
+       return fret;
+}
index 320aa6bf7e9e459dc34519919e478008f836fcea..d59abb5bc7b68d00bbca2f602ad5907593b2ec81 100644 (file)
@@ -355,4 +355,18 @@ int lxc_prepare_loop_dev(const char *source, char *loop_dev, int flags);
  */
 int lxc_unstack_mountpoint(const char *path, bool lazy);
 
+/*
+ * run_command runs a command and collect it's std{err,out} output in buf.
+ *
+ * @param[out] buf     The buffer where the commands std{err,out] output will be
+ *                     read into. If no output was produced, buf will be memset
+ *                     to 0.
+ * @param[in] buf_size The size of buf. This function will reserve one byte for
+ *                     \0-termination.
+ * @param[in] child_fn The function to be run in the child process. This
+ *                     function must exec.
+ * @param[in] args     Arguments to be passed to child_fn.
+ */
+int run_command(char *buf, size_t buf_size, int (*child_fn)(void *), void *args);
+
 #endif /* __LXC_UTILS_H */