From: Christian Brauner Date: Mon, 29 May 2017 02:30:50 +0000 (+0200) Subject: utils: add run_command X-Git-Tag: lxc-2.1.0~108^2~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ea3a694fe1a64b3da0e20ff656e7389b3b568974;p=thirdparty%2Flxc.git utils: add run_command Signed-off-by: Christian Brauner --- diff --git a/src/lxc/utils.c b/src/lxc/utils.c index cc7e80020..ca7d76858 100644 --- a/src/lxc/utils.c +++ b/src/lxc/utils.c @@ -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; +} diff --git a/src/lxc/utils.h b/src/lxc/utils.h index 320aa6bf7..d59abb5bc 100644 --- a/src/lxc/utils.h +++ b/src/lxc/utils.h @@ -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 */