X-Git-Url: http://git.ozlabs.org/?a=blobdiff_plain;f=lib%2Fsystem%2Fsystem.c;h=528e134127f307f17d9dcfaa70b2b1ef60eb7a52;hb=a70807730ef59efc4116556ecabe1b9f70ce605b;hp=380ddedadcd8a94de678e86e0af9da4a21fd7718;hpb=b3e1a66f23b7338d88e0668b8cf10ffe139a9a03;p=petitboot diff --git a/lib/system/system.c b/lib/system/system.c index 380dded..528e134 100644 --- a/lib/system/system.c +++ b/lib/system/system.c @@ -3,6 +3,7 @@ #include "config.h" #endif +#include #include #include #include @@ -16,13 +17,17 @@ #include "system.h" const struct pb_system_apps pb_system_apps = { - .cp = "/bin/cp", - .kexec = "/sbin/kexec", - .mount = "/bin/mount", - .sftp = "/usr/bin/sftp", - .tftp = "/usr/bin/tftp", - .umount = "/bin/umount", - .wget = "/usr/bin/wget", + .prefix = PREFIX, + .cp = HOST_PROG_CP, + .kexec = HOST_PROG_KEXEC, + .mount = HOST_PROG_MOUNT, + .shutdown = HOST_PROG_SHUTDOWN, + .sftp = HOST_PROG_SFTP, + .tftp = HOST_PROG_TFTP, + .umount = HOST_PROG_UMOUNT, + .wget = HOST_PROG_WGET, + .ip = HOST_PROG_IP, + .udhcpc = HOST_PROG_UDHCPC, }; int pb_mkdir_recursive(const char *dir) @@ -97,45 +102,135 @@ 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. + * @wait: Wait for the child process to complete before returning. + * @dry_run: Don't actually fork and exec. */ -int pb_run_cmd(const char *const *cmd_argv) +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) { - int status; - pid_t pid; #if defined(DEBUG) enum {do_debug = 1}; #else enum {do_debug = 0}; #endif + int status, pipefd[2]; + pid_t pid; + + assert(!stdout_buf || wait); + assert(!stdout_buf || ctx); + assert(!stdout_buf || stdout_buf_len); if (do_debug) { const char *const *p = cmd_argv; - pb_log("%s: ", __func__); + pb_log("%s: %s", __func__, (dry_run ? "(dry-run) " : "")); + while (*p) { pb_log("%s ", *p); p++; } pb_log("\n"); } else - pb_log("%s: %s\n", __func__, cmd_argv[0]); + 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) { pb_log("%s: fork failed: %s\n", __func__, strerror(errno)); return -1; } + if (pid == 0) { + int log = fileno(pb_log_get_stream()); + + /* Redirect child output to log. */ + + if (stdout_buf) { + status = dup2(pipefd[1], STDOUT_FILENO); + } else { + status = dup2(log, STDOUT_FILENO); + } + assert(status != -1); + + status = dup2(log, STDERR_FILENO); + assert(status != -1); + execvp(cmd_argv[0], (char *const *)cmd_argv); pb_log("%s: exec failed: %s\n", __func__, strerror(errno)); exit(EXIT_FAILURE); } + 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));