From c20a0460f3c9057aa920949414f8c3bd6529f927 Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Thu, 20 Jun 2013 13:27:16 +0800 Subject: [PATCH] lib/system: Add pb_run_cmd_pipe Add a function to run a command and capture the output into a buffer. Signed-off-by: Jeremy Kerr --- lib/system/system.c | 73 +++++++++++++++++++++++++++++++++++++++++++-- lib/system/system.h | 2 ++ 2 files changed, 73 insertions(+), 2 deletions(-) diff --git a/lib/system/system.c b/lib/system/system.c index dbdef46..7bb4997 100644 --- a/lib/system/system.c +++ b/lib/system/system.c @@ -102,6 +102,40 @@ int pb_rmdir_recursive(const char *base, const char *dir) return 0; } +static int read_pipe(void *ctx, int fd, char **bufp, int *lenp) +{ + int rc, len, alloc_len; + char *buf; + + alloc_len = 4096; + len = 0; + + buf = talloc_array(ctx, char, alloc_len); + + for (;;) { + rc = read(fd, buf, alloc_len - len - 1); + if (rc <= 0) + break; + + len += rc; + if (len == alloc_len - 1) { + alloc_len *= 2; + buf = talloc_realloc(ctx, buf, char, alloc_len); + } + } + + if (rc < 0) { + talloc_free(buf); + return rc; + } + + buf[len] = '\0'; + *bufp = buf; + *lenp = len; + + return 0; +} + /** * pb_run_cmd - Run the supplied command. * @cmd_argv: An argument list array for execv. @@ -110,15 +144,25 @@ int pb_rmdir_recursive(const char *base, const char *dir) */ int pb_run_cmd(const char *const *cmd_argv, int wait, int dry_run) +{ + return pb_run_cmd_pipe(cmd_argv, wait, dry_run, NULL, NULL, NULL); +} + +int pb_run_cmd_pipe(const char *const *cmd_argv, int wait, int dry_run, + void *ctx, char **stdout_buf, int *stdout_buf_len) { #if defined(DEBUG) enum {do_debug = 1}; #else enum {do_debug = 0}; #endif - int status; + int status, pipefd[2]; pid_t pid; + assert(!wait && stdout_buf); + assert(!!ctx != !!stdout_buf); + assert(!!stdout_buf != !!stdout_buf_len); + if (do_debug) { const char *const *p = cmd_argv; @@ -133,9 +177,22 @@ int pb_run_cmd(const char *const *cmd_argv, int wait, int dry_run) pb_log("%s: %s%s\n", __func__, (dry_run ? "(dry-run) " : ""), cmd_argv[0]); + if (stdout_buf) { + *stdout_buf = NULL; + *stdout_buf_len = 0; + } + if (dry_run) return 0; + if (stdout_buf) { + status = pipe(pipefd); + if (status) { + pb_log("pipe failed"); + return -1; + } + } + pid = fork(); if (pid == -1) { @@ -143,12 +200,17 @@ int pb_run_cmd(const char *const *cmd_argv, int wait, int dry_run) return -1; } + if (pid == 0) { int log = fileno(pb_log_get_stream()); /* Redirect child output to log. */ - status = dup2(log, STDOUT_FILENO); + if (stdout_buf) { + status = dup2(pipefd[1], STDOUT_FILENO); + } else { + status = dup2(log, STDOUT_FILENO); + } assert(status != -1); status = dup2(log, STDERR_FILENO); @@ -162,6 +224,13 @@ int pb_run_cmd(const char *const *cmd_argv, int wait, int dry_run) if (!wait && !waitpid(pid, &status, WNOHANG)) return 0; + if (stdout_buf) { + close(pipefd[1]); + status = read_pipe(ctx, pipefd[0], stdout_buf, stdout_buf_len); + if (status) + return -1; + } + if (waitpid(pid, &status, 0) == -1) { pb_log("%s: waitpid failed: %s\n", __func__, strerror(errno)); diff --git a/lib/system/system.h b/lib/system/system.h index 271c435..a7a1a12 100644 --- a/lib/system/system.h +++ b/lib/system/system.h @@ -18,6 +18,8 @@ struct pb_system_apps { extern const struct pb_system_apps pb_system_apps; int pb_run_cmd(const char *const *cmd_argv, int wait, int dry_run); +int pb_run_cmd_pipe(const char *const *cmd_argv, int wait, int dry_run, + void *ctx, char **buf, int *buf_len); int pb_mkdir_recursive(const char *dir); int pb_rmdir_recursive(const char *base, const char *dir); -- 2.39.2