summaryrefslogtreecommitdiffstats
path: root/lib/system
diff options
context:
space:
mode:
authorJeremy Kerr <jk@ozlabs.org>2013-06-20 13:27:16 +0800
committerJeremy Kerr <jk@ozlabs.org>2013-06-24 13:07:58 +0800
commitc20a0460f3c9057aa920949414f8c3bd6529f927 (patch)
tree9fa41a7f92482b7441049afcdb4528bcd0aef221 /lib/system
parent974853d86dd6328ec2aaf6b9ff5b56398942a902 (diff)
downloadtalos-petitboot-c20a0460f3c9057aa920949414f8c3bd6529f927.tar.gz
talos-petitboot-c20a0460f3c9057aa920949414f8c3bd6529f927.zip
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 <jk@ozlabs.org>
Diffstat (limited to 'lib/system')
-rw-r--r--lib/system/system.c73
-rw-r--r--lib/system/system.h2
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.
@@ -111,14 +145,24 @@ 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);
OpenPOWER on IntegriCloud