From: "Daniel P. Berrange" <berrange@xxxxxxxxxx> Continue consolidation of process functions by moving some helpers out of command.{c,h} into virprocess.{c,h} Signed-off-by: Daniel P. Berrange <berrange@xxxxxxxxxx> (cherry picked from commit 9467ab6074d02bd90248b5710b1c83856fefe9b4) Signed-off-by: Eric Blake <eblake@xxxxxxxxxx> Conflicts: src/lxc/lxc_controller.c src/util/command.c src/util/virprocess.c tests/testutils.c --- daemon/libvirtd.c | 1 + daemon/remote.c | 1 + po/POTFILES.in | 1 + src/libvirt_private.syms | 7 ++- src/lxc/lxc_container.c | 1 + src/lxc/lxc_controller.c | 1 + src/rpc/virnetsocket.c | 1 + src/util/command.c | 143 +----------------------------------------- src/util/command.h | 8 --- src/util/util.c | 1 + src/util/virprocess.c | 157 +++++++++++++++++++++++++++++++++++++++++++++++ src/util/virprocess.h | 11 ++++ tests/testutils.c | 1 + 13 files changed, 181 insertions(+), 153 deletions(-) diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c index e9db433..49faece 100644 --- a/daemon/libvirtd.c +++ b/daemon/libvirtd.c @@ -36,6 +36,7 @@ #include "virterror_internal.h" #include "virfile.h" #include "virpidfile.h" +#include "virprocess.h" #define VIR_FROM_THIS VIR_FROM_QEMU diff --git a/daemon/remote.c b/daemon/remote.c index 24553f0..435f663 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -46,6 +46,7 @@ #include "virfile.h" #include "virtypedparam.h" #include "virdbus.h" +#include "virprocess.h" #include "remote_protocol.h" #include "qemu_protocol.h" diff --git a/po/POTFILES.in b/po/POTFILES.in index 4ea544b..7f1997c 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -141,6 +141,7 @@ src/util/virnetdevvportprofile.c src/util/virnetlink.c src/util/virnodesuspend.c src/util/virpidfile.c +src/util/virprocess.c src/util/virrandom.c src/util/virsocketaddr.c src/util/virterror.c diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 95f2543..f35fd63 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -140,12 +140,9 @@ virCommandSetPreExecHook; virCommandSetWorkingDirectory; virCommandToString; virCommandTransferFD; -virProcessTranslateStatus; virCommandWait; virCommandWriteArgLog; virFork; -virProcessAbort; -virProcessWait; virRun; @@ -1454,7 +1451,11 @@ virPidFileDeletePath; # virprocess.h +virProcessAbort; virProcessKill; +virProcessTranslateStatus; +virProcessWait; + # virrandom.h virRandomBits; diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c index 442aa24..b0bd7a2 100644 --- a/src/lxc/lxc_container.c +++ b/src/lxc/lxc_container.c @@ -64,6 +64,7 @@ #include "virfile.h" #include "command.h" #include "virnetdev.h" +#include "virprocess.h" #define VIR_FROM_THIS VIR_FROM_LXC diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c index b5cec3d..e6a2917 100644 --- a/src/lxc/lxc_controller.c +++ b/src/lxc/lxc_controller.c @@ -71,6 +71,7 @@ #include "command.h" #include "processinfo.h" #include "nodeinfo.h" +#include "virprocess.h" #define VIR_FROM_THIS VIR_FROM_LXC diff --git a/src/rpc/virnetsocket.c b/src/rpc/virnetsocket.c index 040090e..e82f375 100644 --- a/src/rpc/virnetsocket.c +++ b/src/rpc/virnetsocket.c @@ -43,6 +43,7 @@ #include "virfile.h" #include "event.h" #include "threads.h" +#include "virprocess.h" #include "passfd.h" diff --git a/src/util/command.c b/src/util/command.c index 02432fa..be10131 100644 --- a/src/util/command.c +++ b/src/util/command.c @@ -40,6 +40,7 @@ #include "logging.h" #include "virfile.h" #include "virpidfile.h" +#include "virprocess.h" #include "buf.h" #include "ignore-value.h" @@ -1647,31 +1648,6 @@ virCommandToString(virCommandPtr cmd) } -/** - * virProcessTranslateStatus: - * @status: child exit status to translate - * - * Translate an exit status into a malloc'd string. Generic helper - * for virCommandRun(), virCommandWait(), virRun(), and virProcessWait() - * status argument, as well as raw waitpid(). - */ -char * -virProcessTranslateStatus(int status) -{ - char *buf; - if (WIFEXITED(status)) { - ignore_value(virAsprintf(&buf, _("exit status %d"), - WEXITSTATUS(status))); - } else if (WIFSIGNALED(status)) { - ignore_value(virAsprintf(&buf, _("fatal signal %d"), - WTERMSIG(status))); - } else { - ignore_value(virAsprintf(&buf, _("invalid value %d"), status)); - } - return buf; -} - - /* * Manage input and output to the child process. */ @@ -2207,55 +2183,6 @@ virCommandRunAsync(virCommandPtr cmd, pid_t *pid) /** - * virProcessWait: - * @pid: child to wait on - * @exitstatus: optional status collection - * - * 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. - */ -int -virProcessWait(pid_t pid, int *exitstatus) -{ - int ret; - int status; - - if (pid <= 0) { - virReportSystemError(EINVAL, _("unable to wait for process %lld"), - (long long) pid); - return -1; - } - - /* Wait for intermediate process to exit */ - while ((ret = waitpid(pid, &status, 0)) == -1 && - errno == EINTR); - - if (ret == -1) { - virReportSystemError(errno, _("unable to wait for process %lld"), - (long long) pid); - return -1; - } - - if (exitstatus == NULL) { - if (status != 0) { - char *st = virProcessTranslateStatus(status); - virCommandError(VIR_ERR_INTERNAL_ERROR, - _("Child process (%lld) status unexpected: %s"), - (long long) pid, NULLSTR(st)); - VIR_FREE(st); - return -1; - } - } else { - *exitstatus = status; - } - - return 0; -} - -/** * virCommandWait: * @cmd: command to wait on * @exitstatus: optional status collection @@ -2320,67 +2247,6 @@ virCommandWait(virCommandPtr cmd, int *exitstatus) #ifndef WIN32 /** - * virProcessAbort: - * @pid: child process to kill - * - * Abort a child process if PID is positive and that child is still - * running, without issuing any errors or affecting errno. Designed - * for error paths where some but not all paths to the cleanup code - * might have started the child process. If @pid is 0 or negative, - * this does nothing. - */ -void -virProcessAbort(pid_t pid) -{ - int saved_errno; - int ret; - int status; - char *tmp = NULL; - - if (pid <= 0) - return; - - /* See if intermediate process has exited; if not, try a nice - * SIGTERM followed by a more severe SIGKILL. - */ - saved_errno = errno; - VIR_DEBUG("aborting child process %d", pid); - while ((ret = waitpid(pid, &status, WNOHANG)) == -1 && - errno == EINTR); - if (ret == pid) { - tmp = virProcessTranslateStatus(status); - VIR_DEBUG("process has ended: %s", tmp); - goto cleanup; - } else if (ret == 0) { - VIR_DEBUG("trying SIGTERM to child process %d", pid); - kill(pid, SIGTERM); - usleep(10 * 1000); - while ((ret = waitpid(pid, &status, WNOHANG)) == -1 && - errno == EINTR); - if (ret == pid) { - tmp = virProcessTranslateStatus(status); - VIR_DEBUG("process has ended: %s", tmp); - goto cleanup; - } else if (ret == 0) { - VIR_DEBUG("trying SIGKILL to child process %d", pid); - kill(pid, SIGKILL); - while ((ret = waitpid(pid, &status, 0)) == -1 && - errno == EINTR); - if (ret == pid) { - tmp = virProcessTranslateStatus(status); - VIR_DEBUG("process has ended: %s", tmp); - goto cleanup; - } - } - } - VIR_DEBUG("failed to reap child %lld, abandoning it", (long long) pid); - -cleanup: - VIR_FREE(tmp); - errno = saved_errno; -} - -/** * virCommandAbort: * @cmd: command to abort * @@ -2400,13 +2266,6 @@ virCommandAbort(virCommandPtr cmd) } #else /* WIN32 */ void -virProcessAbort(pid_t pid) -{ - /* Not yet ported to mingw. Any volunteers? */ - VIR_DEBUG("failed to reap child %lld, abandoning it", (long long)pid); -} - -void virCommandAbort(virCommandPtr cmd ATTRIBUTE_UNUSED) { /* Mingw lacks WNOHANG and kill(). But since we haven't ported diff --git a/src/util/command.h b/src/util/command.h index 5cd85e5..cf4b041 100644 --- a/src/util/command.h +++ b/src/util/command.h @@ -137,9 +137,6 @@ void virCommandWriteArgLog(virCommandPtr cmd, char *virCommandToString(virCommandPtr cmd) ATTRIBUTE_RETURN_CHECK; - -char *virProcessTranslateStatus(int exitstatus) ATTRIBUTE_RETURN_CHECK; - int virCommandExec(virCommandPtr cmd) ATTRIBUTE_RETURN_CHECK; int virCommandRun(virCommandPtr cmd, @@ -148,9 +145,6 @@ int virCommandRun(virCommandPtr cmd, int virCommandRunAsync(virCommandPtr cmd, pid_t *pid) ATTRIBUTE_RETURN_CHECK; -int virProcessWait(pid_t pid, - int *exitstatus) ATTRIBUTE_RETURN_CHECK; - int virCommandWait(virCommandPtr cmd, int *exitstatus) ATTRIBUTE_RETURN_CHECK; @@ -162,8 +156,6 @@ int virCommandHandshakeWait(virCommandPtr cmd) int virCommandHandshakeNotify(virCommandPtr cmd) ATTRIBUTE_RETURN_CHECK; -void virProcessAbort(pid_t pid); - void virCommandAbort(virCommandPtr cmd); void virCommandFree(virCommandPtr cmd); diff --git a/src/util/util.c b/src/util/util.c index b807c5a..1b32bcc 100644 --- a/src/util/util.c +++ b/src/util/util.c @@ -78,6 +78,7 @@ #include "command.h" #include "nonblocking.h" #include "passfd.h" +#include "virprocess.h" #ifndef NSIG # define NSIG 32 diff --git a/src/util/virprocess.c b/src/util/virprocess.c index e7db68f..ac78f1d 100644 --- a/src/util/virprocess.c +++ b/src/util/virprocess.c @@ -24,8 +24,165 @@ #include <signal.h> #include <errno.h> +#include <sys/wait.h> #include "virprocess.h" +#include "virterror_internal.h" +#include "memory.h" +#include "logging.h" +#include "util.h" +#include "ignore-value.h" +#define virReportError(code, ...) \ + virReportErrorHelper(VIR_FROM_NONE, code, __FILE__, \ + __FUNCTION__, __LINE__, __VA_ARGS__) + +#define VIR_FROM_THIS VIR_FROM_NONE + +/** + * virProcessTranslateStatus: + * @status: child exit status to translate + * + * Translate an exit status into a malloc'd string. Generic helper + * for virCommandRun(), virCommandWait(), virRun(), and virProcessWait() + * status argument, as well as raw waitpid(). + */ +char * +virProcessTranslateStatus(int status) +{ + char *buf; + if (WIFEXITED(status)) { + ignore_value(virAsprintf(&buf, _("exit status %d"), + WEXITSTATUS(status))); + } else if (WIFSIGNALED(status)) { + ignore_value(virAsprintf(&buf, _("fatal signal %d"), + WTERMSIG(status))); + } else { + ignore_value(virAsprintf(&buf, _("invalid value %d"), status)); + } + return buf; +} + + +#ifndef WIN32 +/** + * virProcessAbort: + * @pid: child process to kill + * + * Abort a child process if PID is positive and that child is still + * running, without issuing any errors or affecting errno. Designed + * for error paths where some but not all paths to the cleanup code + * might have started the child process. If @pid is 0 or negative, + * this does nothing. + */ +void +virProcessAbort(pid_t pid) +{ + int saved_errno; + int ret; + int status; + char *tmp = NULL; + + if (pid <= 0) + return; + + /* See if intermediate process has exited; if not, try a nice + * SIGTERM followed by a more severe SIGKILL. + */ + saved_errno = errno; + VIR_DEBUG("aborting child process %d", pid); + while ((ret = waitpid(pid, &status, WNOHANG)) == -1 && + errno == EINTR); + if (ret == pid) { + tmp = virProcessTranslateStatus(status); + VIR_DEBUG("process has ended: %s", tmp); + goto cleanup; + } else if (ret == 0) { + VIR_DEBUG("trying SIGTERM to child process %d", pid); + kill(pid, SIGTERM); + usleep(10 * 1000); + while ((ret = waitpid(pid, &status, WNOHANG)) == -1 && + errno == EINTR); + if (ret == pid) { + tmp = virProcessTranslateStatus(status); + VIR_DEBUG("process has ended: %s", tmp); + goto cleanup; + } else if (ret == 0) { + VIR_DEBUG("trying SIGKILL to child process %d", pid); + kill(pid, SIGKILL); + while ((ret = waitpid(pid, &status, 0)) == -1 && + errno == EINTR); + if (ret == pid) { + tmp = virProcessTranslateStatus(status); + VIR_DEBUG("process has ended: %s", tmp); + goto cleanup; + } + } + } + VIR_DEBUG("failed to reap child %lld, abandoning it", (long long) pid); + +cleanup: + VIR_FREE(tmp); + errno = saved_errno; +} +#else +void +virProcessAbort(pid_t pid) +{ + /* Not yet ported to mingw. Any volunteers? */ + VIR_DEBUG("failed to reap child %lld, abandoning it", (long long)pid); +} +#endif + + +/** + * virProcessWait: + * @pid: child to wait on + * @exitstatus: optional status collection + * + * 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. + */ +int +virProcessWait(pid_t pid, int *exitstatus) +{ + int ret; + int status; + + if (pid <= 0) { + virReportSystemError(EINVAL, _("unable to wait for process %lld"), + (long long) pid); + return -1; + } + + /* Wait for intermediate process to exit */ + while ((ret = waitpid(pid, &status, 0)) == -1 && + errno == EINTR); + + if (ret == -1) { + virReportSystemError(errno, _("unable to wait for process %lld"), + (long long) pid); + return -1; + } + + 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 { + *exitstatus = status; + } + + return 0; +} + /* send signal to a single process */ int virProcessKill(pid_t pid, int sig) diff --git a/src/util/virprocess.h b/src/util/virprocess.h index b1000c6..048a73c 100644 --- a/src/util/virprocess.h +++ b/src/util/virprocess.h @@ -26,6 +26,17 @@ # include "internal.h" +char * +virProcessTranslateStatus(int status); + +void +virProcessAbort(pid_t pid); + +int +virProcessWait(pid_t pid, int *exitstatus) + ATTRIBUTE_RETURN_CHECK; + int virProcessKill(pid_t pid, int sig); + #endif /* __VIR_PROCESS_H__ */ diff --git a/tests/testutils.c b/tests/testutils.c index 63bec52..2c38115 100644 --- a/tests/testutils.c +++ b/tests/testutils.c @@ -35,6 +35,7 @@ #include "logging.h" #include "command.h" #include "virrandom.h" +#include "virprocess.h" #if TEST_OOM_TRACE # include <execinfo.h> -- 1.8.3.1 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list