diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c index b27c6fda6f..72f0e81e67 100644 --- a/daemon/libvirtd.c +++ b/daemon/libvirtd.c @@ -1,7 +1,7 @@ /* * libvirtd.c: daemon start of day, guest process & i/o management * - * Copyright (C) 2006-2012 Red Hat, Inc. + * Copyright (C) 2006-2014 Red Hat, Inc. * Copyright (C) 2006 Daniel P. Berrange * * This library is free software; you can redistribute it and/or @@ -206,7 +206,7 @@ static int daemonForkIntoBackground(const char *argv0) VIR_FORCE_CLOSE(statuspipe[1]); /* We wait to make sure the first child forked successfully */ - if (virProcessWait(pid, NULL) < 0) + if (virProcessWait(pid, NULL, false) < 0) goto error; /* If we get here, then the grandchild was spawned, so we diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c index 71548043eb..f2440ff92b 100644 --- a/src/lxc/lxc_container.c +++ b/src/lxc/lxc_container.c @@ -173,11 +173,11 @@ int lxcContainerHasReboot(void) virReportSystemError(errno, "%s", _("Unable to clone to check reboot support")); return -1; - } else if (virProcessWait(cpid, &status) < 0) { + } else if (virProcessWait(cpid, &status, false) < 0) { return -1; } - if (WEXITSTATUS(status) != 1) { + if (status != 1) { VIR_DEBUG("Containerized reboot support is missing " "(kernel probably too old < 3.4)"); return 0; @@ -2075,7 +2075,7 @@ int lxcContainerAvailable(int features) VIR_DEBUG("clone call returned %s, container support is not enabled", virStrerror(errno, ebuf, sizeof(ebuf))); return -1; - } else if (virProcessWait(cpid, NULL) < 0) { + } else if (virProcessWait(cpid, NULL, false) < 0) { return -1; } diff --git a/src/util/vircommand.c b/src/util/vircommand.c index b9e5f3748a..a4397b4c90 100644 --- a/src/util/vircommand.c +++ b/src/util/vircommand.c @@ -2372,7 +2372,7 @@ virCommandWait(virCommandPtr cmd, int *exitstatus) * message is not as detailed as what we can provide. So, we * guarantee that virProcessWait only fails due to failure to wait, * and repeat the exitstatus check code ourselves. */ - ret = virProcessWait(cmd->pid, exitstatus ? exitstatus : &status); + ret = virProcessWait(cmd->pid, exitstatus ? exitstatus : &status, true); if (cmd->flags & VIR_EXEC_ASYNC_IO) { cmd->flags &= ~VIR_EXEC_ASYNC_IO; virThreadJoin(cmd->asyncioThread); diff --git a/src/util/virfile.c b/src/util/virfile.c index 96f078dfd3..6fb7d6fcb6 100644 --- a/src/util/virfile.c +++ b/src/util/virfile.c @@ -1,7 +1,7 @@ /* * virfile.c: safer file handling * - * Copyright (C) 2010-2013 Red Hat, Inc. + * Copyright (C) 2010-2014 Red Hat, Inc. * Copyright (C) 2010 IBM Corporation * Copyright (C) 2010 Stefan Berger * Copyright (C) 2010 Eric Blake @@ -1739,19 +1739,13 @@ virFileAccessibleAs(const char *path, int mode, if (pid) { /* parent */ VIR_FREE(groups); - if (virProcessWait(pid, &status) < 0) { - /* virProcessWait() already - * reported error */ - return -1; - } - - if (!WIFEXITED(status)) { - errno = EINTR; + if (virProcessWait(pid, &status, false) < 0) { + /* virProcessWait() already reported error */ return -1; } if (status) { - errno = WEXITSTATUS(status); + errno = status; return -1; } diff --git a/src/util/virprocess.c b/src/util/virprocess.c index bd406db306..72e995026d 100644 --- a/src/util/virprocess.c +++ b/src/util/virprocess.c @@ -155,15 +155,21 @@ virProcessAbort(pid_t pid) * virProcessWait: * @pid: child to wait on * @exitstatus: optional status collection + * @raw: whether to pass non-normal status back to caller * - * Wait for a child process to complete. - * Return -1 on any error waiting for - * completion. Returns 0 if the command - * finished with the exit status set. If @exitstatus is NULL, then the - * child must exit with status 0 for this to succeed. + * Wait for a child process to complete. If @exitstatus is NULL, then the + * child must exit normally with status 0. Otherwise, if @raw is false, + * the child must exit normally, and @exitstatus will contain the final + * exit status (no need for the caller to use WEXITSTATUS()). If @raw is + * true, then the result of wait() is returned in @exitstatus, and the + * caller must use WIFEXITED() and friends to decipher the child's status. + * + * Returns 0 on a successful wait. Returns -1 on any error waiting for + * completion, or if the command completed with a status that cannot be + * reflected via the choice of @exitstatus and @raw. */ int -virProcessWait(pid_t pid, int *exitstatus) +virProcessWait(pid_t pid, int *exitstatus, bool raw) { int ret; int status; @@ -185,19 +191,27 @@ virProcessWait(pid_t pid, int *exitstatus) } if (exitstatus == NULL) { - if (status != 0) { - char *st = virProcessTranslateStatus(status); - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Child process (%lld) unexpected %s"), - (long long) pid, NULLSTR(st)); - VIR_FREE(st); - return -1; - } - } else { + if (status != 0) + goto error; + } else if (raw) { *exitstatus = status; + } else if (WIFEXITED(status)) { + *exitstatus = WEXITSTATUS(status); + } else { + goto error; } return 0; + +error: + { + char *st = virProcessTranslateStatus(status); + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Child process (%lld) unexpected %s"), + (long long) pid, NULLSTR(st)); + VIR_FREE(st); + } + return -1; } @@ -965,7 +979,7 @@ virProcessRunInMountNamespace(pid_t pid, VIR_FORCE_CLOSE(errfd[1]); ignore_value(virFileReadHeaderFD(errfd[0], 1024, &buf)); - ret = virProcessWait(child, &status); + ret = virProcessWait(child, &status, false); if (!ret) ret = status == EXIT_CANCELED ? -1 : status; VIR_FREE(buf); diff --git a/src/util/virprocess.h b/src/util/virprocess.h index abe3635bc9..bcaede58a9 100644 --- a/src/util/virprocess.h +++ b/src/util/virprocess.h @@ -36,7 +36,7 @@ virProcessAbort(pid_t pid); void virProcessExitWithStatus(int status) ATTRIBUTE_NORETURN; int -virProcessWait(pid_t pid, int *exitstatus) +virProcessWait(pid_t pid, int *exitstatus, bool raw) ATTRIBUTE_RETURN_CHECK; int virProcessKill(pid_t pid, int sig); diff --git a/tests/commandtest.c b/tests/commandtest.c index fcda5e6140..c0391a5e1e 100644 --- a/tests/commandtest.c +++ b/tests/commandtest.c @@ -958,13 +958,13 @@ test23(const void *unused ATTRIBUTE_UNUSED) _exit(EXIT_FAILURE); if (pid == 0) _exit(42); - if (virProcessWait(pid, &status) < 0) + if (virProcessWait(pid, &status, true) < 0) _exit(EXIT_FAILURE); virProcessExitWithStatus(status); _exit(EXIT_FAILURE); } - if (virProcessWait(pid, &status) < 0) + if (virProcessWait(pid, &status, true) < 0) goto cleanup; if (!WIFEXITED(status) || WEXITSTATUS(status) != 42) { printf("Unexpected status %d\n", status); @@ -982,13 +982,13 @@ test23(const void *unused ATTRIBUTE_UNUSED) raise(SIGKILL); _exit(EXIT_FAILURE); } - if (virProcessWait(pid, &status) < 0) + if (virProcessWait(pid, &status, true) < 0) _exit(EXIT_FAILURE); virProcessExitWithStatus(status); _exit(EXIT_FAILURE); } - if (virProcessWait(pid, &status) < 0) + if (virProcessWait(pid, &status, true) < 0) goto cleanup; if (!WIFSIGNALED(status) || WTERMSIG(status) != SIGKILL) { printf("Unexpected status %d\n", status); diff --git a/tests/testutils.c b/tests/testutils.c index 97d5b50cdc..ede623924e 100644 --- a/tests/testutils.c +++ b/tests/testutils.c @@ -1,7 +1,7 @@ /* * testutils.c: basic test utils * - * Copyright (C) 2005-2013 Red Hat, Inc. + * Copyright (C) 2005-2014 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -427,7 +427,7 @@ virtTestCaptureProgramOutput(const char *const argv[], char **buf, int maxlen) VIR_FORCE_CLOSE(pipefd[1]); len = virFileReadLimFD(pipefd[0], maxlen, buf); VIR_FORCE_CLOSE(pipefd[0]); - if (virProcessWait(pid, NULL) < 0) + if (virProcessWait(pid, NULL, false) < 0) return -1; return len; diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index 6df18a33ea..520c0eda5c 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -8206,7 +8206,7 @@ cmdLxcEnterNamespace(vshControl *ctl, const vshCmd *cmd) execv(cmdargv[0], cmdargv); _exit(255); } else { - if (virProcessWait(pid, NULL) < 0) + if (virProcessWait(pid, NULL, false) < 0) _exit(255); } _exit(0); @@ -8214,7 +8214,7 @@ cmdLxcEnterNamespace(vshControl *ctl, const vshCmd *cmd) for (i = 0; i < nfdlist; i++) VIR_FORCE_CLOSE(fdlist[i]); VIR_FREE(fdlist); - if (virProcessWait(pid, NULL) < 0) + if (virProcessWait(pid, NULL, false) < 0) goto cleanup; } diff --git a/tools/virt-login-shell.c b/tools/virt-login-shell.c index 5b85d15383..819cc5c752 100644 --- a/tools/virt-login-shell.c +++ b/tools/virt-login-shell.c @@ -369,9 +369,9 @@ main(int argc, char **argv) return EXIT_FAILURE; } } - return virProcessWait(ccpid, &status2); + return virProcessWait(ccpid, &status2, true); } - ret = virProcessWait(cpid, &status); + ret = virProcessWait(cpid, &status, true); cleanup: virConfFree(conf);