mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-03-03 15:43:51 +00:00
util: make it easier to grab only regular process exit
Right now, a caller waiting for a child process either requires the child to have status 0, or must use WIFEXITED() and friends itself. But in many cases, we want the middle ground of treating fatal signals as an error, and directly accessing the normal exit value without having to use WEXITSTATUS(), in order to easily detect an expected non-zero exit status. This adds the middle ground to the low-level virProcessWait; the next patch will add it to virCommand. * src/util/virprocess.h (virProcessWait): Alter signature. * src/util/virprocess.c (virProcessWait): Add parameter. (virProcessRunInMountNamespace): Adjust caller. * src/util/vircommand.c (virCommandWait): Likewise. * src/util/virfile.c (virFileAccessibleAs): Likewise. * src/lxc/lxc_container.c (lxcContainerHasReboot) (lxcContainerAvailable): Likewise. * daemon/libvirtd.c (daemonForkIntoBackground): Likewise. * tools/virt-login-shell.c (main): Likewise. * tools/virsh-domain.c (cmdLxcEnterNamespace): Likewise. * tests/testutils.c (virtTestCaptureProgramOutput): Likewise. * tests/commandtest.c (test23): Likewise. Signed-off-by: Eric Blake <eblake@redhat.com>
This commit is contained in:
parent
8b24a803ad
commit
c72e76c3d9
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* libvirtd.c: daemon start of day, guest process & i/o management
|
* 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
|
* Copyright (C) 2006 Daniel P. Berrange
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* 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]);
|
VIR_FORCE_CLOSE(statuspipe[1]);
|
||||||
|
|
||||||
/* We wait to make sure the first child forked successfully */
|
/* We wait to make sure the first child forked successfully */
|
||||||
if (virProcessWait(pid, NULL) < 0)
|
if (virProcessWait(pid, NULL, false) < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
/* If we get here, then the grandchild was spawned, so we
|
/* If we get here, then the grandchild was spawned, so we
|
||||||
|
@ -173,11 +173,11 @@ int lxcContainerHasReboot(void)
|
|||||||
virReportSystemError(errno, "%s",
|
virReportSystemError(errno, "%s",
|
||||||
_("Unable to clone to check reboot support"));
|
_("Unable to clone to check reboot support"));
|
||||||
return -1;
|
return -1;
|
||||||
} else if (virProcessWait(cpid, &status) < 0) {
|
} else if (virProcessWait(cpid, &status, false) < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (WEXITSTATUS(status) != 1) {
|
if (status != 1) {
|
||||||
VIR_DEBUG("Containerized reboot support is missing "
|
VIR_DEBUG("Containerized reboot support is missing "
|
||||||
"(kernel probably too old < 3.4)");
|
"(kernel probably too old < 3.4)");
|
||||||
return 0;
|
return 0;
|
||||||
@ -2075,7 +2075,7 @@ int lxcContainerAvailable(int features)
|
|||||||
VIR_DEBUG("clone call returned %s, container support is not enabled",
|
VIR_DEBUG("clone call returned %s, container support is not enabled",
|
||||||
virStrerror(errno, ebuf, sizeof(ebuf)));
|
virStrerror(errno, ebuf, sizeof(ebuf)));
|
||||||
return -1;
|
return -1;
|
||||||
} else if (virProcessWait(cpid, NULL) < 0) {
|
} else if (virProcessWait(cpid, NULL, false) < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2372,7 +2372,7 @@ virCommandWait(virCommandPtr cmd, int *exitstatus)
|
|||||||
* message is not as detailed as what we can provide. So, we
|
* message is not as detailed as what we can provide. So, we
|
||||||
* guarantee that virProcessWait only fails due to failure to wait,
|
* guarantee that virProcessWait only fails due to failure to wait,
|
||||||
* and repeat the exitstatus check code ourselves. */
|
* 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) {
|
if (cmd->flags & VIR_EXEC_ASYNC_IO) {
|
||||||
cmd->flags &= ~VIR_EXEC_ASYNC_IO;
|
cmd->flags &= ~VIR_EXEC_ASYNC_IO;
|
||||||
virThreadJoin(cmd->asyncioThread);
|
virThreadJoin(cmd->asyncioThread);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* virfile.c: safer file handling
|
* 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 IBM Corporation
|
||||||
* Copyright (C) 2010 Stefan Berger
|
* Copyright (C) 2010 Stefan Berger
|
||||||
* Copyright (C) 2010 Eric Blake
|
* Copyright (C) 2010 Eric Blake
|
||||||
@ -1739,19 +1739,13 @@ virFileAccessibleAs(const char *path, int mode,
|
|||||||
|
|
||||||
if (pid) { /* parent */
|
if (pid) { /* parent */
|
||||||
VIR_FREE(groups);
|
VIR_FREE(groups);
|
||||||
if (virProcessWait(pid, &status) < 0) {
|
if (virProcessWait(pid, &status, false) < 0) {
|
||||||
/* virProcessWait() already
|
/* virProcessWait() already reported error */
|
||||||
* reported error */
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!WIFEXITED(status)) {
|
|
||||||
errno = EINTR;
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status) {
|
if (status) {
|
||||||
errno = WEXITSTATUS(status);
|
errno = status;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,15 +155,21 @@ virProcessAbort(pid_t pid)
|
|||||||
* virProcessWait:
|
* virProcessWait:
|
||||||
* @pid: child to wait on
|
* @pid: child to wait on
|
||||||
* @exitstatus: optional status collection
|
* @exitstatus: optional status collection
|
||||||
|
* @raw: whether to pass non-normal status back to caller
|
||||||
*
|
*
|
||||||
* Wait for a child process to complete.
|
* Wait for a child process to complete. If @exitstatus is NULL, then the
|
||||||
* Return -1 on any error waiting for
|
* child must exit normally with status 0. Otherwise, if @raw is false,
|
||||||
* completion. Returns 0 if the command
|
* the child must exit normally, and @exitstatus will contain the final
|
||||||
* finished with the exit status set. If @exitstatus is NULL, then the
|
* exit status (no need for the caller to use WEXITSTATUS()). If @raw is
|
||||||
* child must exit with status 0 for this to succeed.
|
* 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
|
int
|
||||||
virProcessWait(pid_t pid, int *exitstatus)
|
virProcessWait(pid_t pid, int *exitstatus, bool raw)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
int status;
|
int status;
|
||||||
@ -185,19 +191,27 @@ virProcessWait(pid_t pid, int *exitstatus)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (exitstatus == NULL) {
|
if (exitstatus == NULL) {
|
||||||
if (status != 0) {
|
if (status != 0)
|
||||||
char *st = virProcessTranslateStatus(status);
|
goto error;
|
||||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
} else if (raw) {
|
||||||
_("Child process (%lld) unexpected %s"),
|
|
||||||
(long long) pid, NULLSTR(st));
|
|
||||||
VIR_FREE(st);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
*exitstatus = status;
|
*exitstatus = status;
|
||||||
|
} else if (WIFEXITED(status)) {
|
||||||
|
*exitstatus = WEXITSTATUS(status);
|
||||||
|
} else {
|
||||||
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
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]);
|
VIR_FORCE_CLOSE(errfd[1]);
|
||||||
ignore_value(virFileReadHeaderFD(errfd[0], 1024, &buf));
|
ignore_value(virFileReadHeaderFD(errfd[0], 1024, &buf));
|
||||||
ret = virProcessWait(child, &status);
|
ret = virProcessWait(child, &status, false);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
ret = status == EXIT_CANCELED ? -1 : status;
|
ret = status == EXIT_CANCELED ? -1 : status;
|
||||||
VIR_FREE(buf);
|
VIR_FREE(buf);
|
||||||
|
@ -36,7 +36,7 @@ virProcessAbort(pid_t pid);
|
|||||||
void virProcessExitWithStatus(int status) ATTRIBUTE_NORETURN;
|
void virProcessExitWithStatus(int status) ATTRIBUTE_NORETURN;
|
||||||
|
|
||||||
int
|
int
|
||||||
virProcessWait(pid_t pid, int *exitstatus)
|
virProcessWait(pid_t pid, int *exitstatus, bool raw)
|
||||||
ATTRIBUTE_RETURN_CHECK;
|
ATTRIBUTE_RETURN_CHECK;
|
||||||
|
|
||||||
int virProcessKill(pid_t pid, int sig);
|
int virProcessKill(pid_t pid, int sig);
|
||||||
|
@ -958,13 +958,13 @@ test23(const void *unused ATTRIBUTE_UNUSED)
|
|||||||
_exit(EXIT_FAILURE);
|
_exit(EXIT_FAILURE);
|
||||||
if (pid == 0)
|
if (pid == 0)
|
||||||
_exit(42);
|
_exit(42);
|
||||||
if (virProcessWait(pid, &status) < 0)
|
if (virProcessWait(pid, &status, true) < 0)
|
||||||
_exit(EXIT_FAILURE);
|
_exit(EXIT_FAILURE);
|
||||||
virProcessExitWithStatus(status);
|
virProcessExitWithStatus(status);
|
||||||
_exit(EXIT_FAILURE);
|
_exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (virProcessWait(pid, &status) < 0)
|
if (virProcessWait(pid, &status, true) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
if (!WIFEXITED(status) || WEXITSTATUS(status) != 42) {
|
if (!WIFEXITED(status) || WEXITSTATUS(status) != 42) {
|
||||||
printf("Unexpected status %d\n", status);
|
printf("Unexpected status %d\n", status);
|
||||||
@ -982,13 +982,13 @@ test23(const void *unused ATTRIBUTE_UNUSED)
|
|||||||
raise(SIGKILL);
|
raise(SIGKILL);
|
||||||
_exit(EXIT_FAILURE);
|
_exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
if (virProcessWait(pid, &status) < 0)
|
if (virProcessWait(pid, &status, true) < 0)
|
||||||
_exit(EXIT_FAILURE);
|
_exit(EXIT_FAILURE);
|
||||||
virProcessExitWithStatus(status);
|
virProcessExitWithStatus(status);
|
||||||
_exit(EXIT_FAILURE);
|
_exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (virProcessWait(pid, &status) < 0)
|
if (virProcessWait(pid, &status, true) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
if (!WIFSIGNALED(status) || WTERMSIG(status) != SIGKILL) {
|
if (!WIFSIGNALED(status) || WTERMSIG(status) != SIGKILL) {
|
||||||
printf("Unexpected status %d\n", status);
|
printf("Unexpected status %d\n", status);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* testutils.c: basic test utils
|
* 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
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* 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]);
|
VIR_FORCE_CLOSE(pipefd[1]);
|
||||||
len = virFileReadLimFD(pipefd[0], maxlen, buf);
|
len = virFileReadLimFD(pipefd[0], maxlen, buf);
|
||||||
VIR_FORCE_CLOSE(pipefd[0]);
|
VIR_FORCE_CLOSE(pipefd[0]);
|
||||||
if (virProcessWait(pid, NULL) < 0)
|
if (virProcessWait(pid, NULL, false) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
|
@ -8206,7 +8206,7 @@ cmdLxcEnterNamespace(vshControl *ctl, const vshCmd *cmd)
|
|||||||
execv(cmdargv[0], cmdargv);
|
execv(cmdargv[0], cmdargv);
|
||||||
_exit(255);
|
_exit(255);
|
||||||
} else {
|
} else {
|
||||||
if (virProcessWait(pid, NULL) < 0)
|
if (virProcessWait(pid, NULL, false) < 0)
|
||||||
_exit(255);
|
_exit(255);
|
||||||
}
|
}
|
||||||
_exit(0);
|
_exit(0);
|
||||||
@ -8214,7 +8214,7 @@ cmdLxcEnterNamespace(vshControl *ctl, const vshCmd *cmd)
|
|||||||
for (i = 0; i < nfdlist; i++)
|
for (i = 0; i < nfdlist; i++)
|
||||||
VIR_FORCE_CLOSE(fdlist[i]);
|
VIR_FORCE_CLOSE(fdlist[i]);
|
||||||
VIR_FREE(fdlist);
|
VIR_FREE(fdlist);
|
||||||
if (virProcessWait(pid, NULL) < 0)
|
if (virProcessWait(pid, NULL, false) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -369,9 +369,9 @@ main(int argc, char **argv)
|
|||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return virProcessWait(ccpid, &status2);
|
return virProcessWait(ccpid, &status2, true);
|
||||||
}
|
}
|
||||||
ret = virProcessWait(cpid, &status);
|
ret = virProcessWait(cpid, &status, true);
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
virConfFree(conf);
|
virConfFree(conf);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user