mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-22 13:45:38 +00:00
util: make it easier to reflect child exit status
Thanks to namespaces, we have a couple of places in the code base that want to reflect a child exit status, including the ability to detect death by a signal, back to a grandparent. Best to make it a reusable function. * src/util/virprocess.h (virProcessExitWithStatus): New prototype. * src/libvirt_private.syms (util/virprocess.h): Export it. * src/util/virprocess.c (virProcessExitWithStatus): New function. * tests/commandtest.c (test23): Test it. Signed-off-by: Eric Blake <eblake@redhat.com>
This commit is contained in:
parent
631923e7f2
commit
2b4f162eb4
@ -1679,6 +1679,7 @@ virPortAllocatorRelease;
|
|||||||
|
|
||||||
# util/virprocess.h
|
# util/virprocess.h
|
||||||
virProcessAbort;
|
virProcessAbort;
|
||||||
|
virProcessExitWithStatus;
|
||||||
virProcessGetAffinity;
|
virProcessGetAffinity;
|
||||||
virProcessGetNamespaces;
|
virProcessGetNamespaces;
|
||||||
virProcessGetStartTime;
|
virProcessGetStartTime;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* virprocess.c: interaction with processes
|
* virprocess.c: interaction with processes
|
||||||
*
|
*
|
||||||
* Copyright (C) 2010-2013 Red Hat, Inc.
|
* Copyright (C) 2010-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
|
||||||
@ -25,6 +25,7 @@
|
|||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#if HAVE_SETRLIMIT
|
#if HAVE_SETRLIMIT
|
||||||
# include <sys/time.h>
|
# include <sys/time.h>
|
||||||
@ -983,3 +984,41 @@ virProcessRunInMountNamespace(pid_t pid ATTRIBUTE_UNUSED,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* virProcessExitWithStatus:
|
||||||
|
* @status: raw status to be reproduced when this process dies
|
||||||
|
*
|
||||||
|
* Given a raw status obtained by waitpid() or similar, attempt to
|
||||||
|
* make this process exit in the same manner. If the child died by
|
||||||
|
* signal, reset that signal handler to default and raise the same
|
||||||
|
* signal; if that doesn't kill this process, then exit with 128 +
|
||||||
|
* signal number. If @status can't be deciphered, use
|
||||||
|
* EXIT_CANNOT_INVOKE.
|
||||||
|
*
|
||||||
|
* Never returns.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
virProcessExitWithStatus(int status)
|
||||||
|
{
|
||||||
|
int value = EXIT_CANNOT_INVOKE;
|
||||||
|
|
||||||
|
if (WIFEXITED(status)) {
|
||||||
|
value = WEXITSTATUS(status);
|
||||||
|
} else if (WIFSIGNALED(status)) {
|
||||||
|
struct sigaction act;
|
||||||
|
sigset_t sigs;
|
||||||
|
|
||||||
|
if (sigemptyset(&sigs) == 0 &&
|
||||||
|
sigaddset(&sigs, WTERMSIG(status)) == 0)
|
||||||
|
sigprocmask(SIG_UNBLOCK, &sigs, NULL);
|
||||||
|
memset(&act, 0, sizeof(act));
|
||||||
|
act.sa_handler = SIG_DFL;
|
||||||
|
sigfillset(&act.sa_mask);
|
||||||
|
sigaction(WTERMSIG(status), &act, NULL);
|
||||||
|
raise(WTERMSIG(status));
|
||||||
|
value = 128 + WTERMSIG(status);
|
||||||
|
}
|
||||||
|
exit(value);
|
||||||
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* virprocess.h: interaction with processes
|
* virprocess.h: interaction with processes
|
||||||
*
|
*
|
||||||
* Copyright (C) 2010-2013 Red Hat, Inc.
|
* Copyright (C) 2010-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
|
||||||
@ -33,6 +33,8 @@ virProcessTranslateStatus(int status);
|
|||||||
void
|
void
|
||||||
virProcessAbort(pid_t pid);
|
virProcessAbort(pid_t pid);
|
||||||
|
|
||||||
|
void virProcessExitWithStatus(int status) ATTRIBUTE_NORETURN;
|
||||||
|
|
||||||
int
|
int
|
||||||
virProcessWait(pid_t pid, int *exitstatus)
|
virProcessWait(pid_t pid, int *exitstatus)
|
||||||
ATTRIBUTE_RETURN_CHECK;
|
ATTRIBUTE_RETURN_CHECK;
|
||||||
|
@ -38,6 +38,7 @@
|
|||||||
#include "virerror.h"
|
#include "virerror.h"
|
||||||
#include "virthread.h"
|
#include "virthread.h"
|
||||||
#include "virstring.h"
|
#include "virstring.h"
|
||||||
|
#include "virprocess.h"
|
||||||
|
|
||||||
#define VIR_FROM_THIS VIR_FROM_NONE
|
#define VIR_FROM_THIS VIR_FROM_NONE
|
||||||
|
|
||||||
@ -937,6 +938,68 @@ cleanup:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
test23(const void *unused ATTRIBUTE_UNUSED)
|
||||||
|
{
|
||||||
|
/* Not strictly a virCommand test, but this is the easiest place
|
||||||
|
* to test this lower-level interface. It takes a double fork to
|
||||||
|
* test virProcessExitWithStatus. */
|
||||||
|
int ret = -1;
|
||||||
|
int status = -1;
|
||||||
|
pid_t pid;
|
||||||
|
|
||||||
|
if (virFork(&pid) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
if (pid < 0)
|
||||||
|
goto cleanup;
|
||||||
|
if (pid == 0) {
|
||||||
|
if (virFork(&pid) < 0)
|
||||||
|
_exit(EXIT_FAILURE);
|
||||||
|
if (pid == 0)
|
||||||
|
_exit(42);
|
||||||
|
if (virProcessWait(pid, &status) < 0)
|
||||||
|
_exit(EXIT_FAILURE);
|
||||||
|
virProcessExitWithStatus(status);
|
||||||
|
_exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (virProcessWait(pid, &status) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
if (!WIFEXITED(status) || WEXITSTATUS(status) != 42) {
|
||||||
|
printf("Unexpected status %d\n", status);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (virFork(&pid) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
if (pid < 0)
|
||||||
|
goto cleanup;
|
||||||
|
if (pid == 0) {
|
||||||
|
if (virFork(&pid) < 0)
|
||||||
|
_exit(EXIT_FAILURE);
|
||||||
|
if (pid == 0) {
|
||||||
|
raise(SIGKILL);
|
||||||
|
_exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
if (virProcessWait(pid, &status) < 0)
|
||||||
|
_exit(EXIT_FAILURE);
|
||||||
|
virProcessExitWithStatus(status);
|
||||||
|
_exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (virProcessWait(pid, &status) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
if (!WIFSIGNALED(status) || WTERMSIG(status) != SIGKILL) {
|
||||||
|
printf("Unexpected status %d\n", status);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
cleanup:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static void virCommandThreadWorker(void *opaque)
|
static void virCommandThreadWorker(void *opaque)
|
||||||
{
|
{
|
||||||
virCommandTestDataPtr test = opaque;
|
virCommandTestDataPtr test = opaque;
|
||||||
@ -1085,6 +1148,7 @@ mymain(void)
|
|||||||
DO_TEST(test20);
|
DO_TEST(test20);
|
||||||
DO_TEST(test21);
|
DO_TEST(test21);
|
||||||
DO_TEST(test22);
|
DO_TEST(test22);
|
||||||
|
DO_TEST(test23);
|
||||||
|
|
||||||
virMutexLock(&test->lock);
|
virMutexLock(&test->lock);
|
||||||
if (test->running) {
|
if (test->running) {
|
||||||
|
Loading…
Reference in New Issue
Block a user