See also: https://www.freebsd.org/cgi/man.cgi?query=procctl&sektion=2 --- common/include/Makefile.am | 5 +- common/include/exit-with-parent.h | 80 +++++++++++++++++++++++++++++++ configure.ac | 2 +- docs/nbdkit-captive.pod | 12 +++-- src/Makefile.am | 3 +- src/main.c | 13 ++--- tests/Makefile.am | 9 +++- tests/test-exit-with-parent.c | 7 +-- tests/test-layers.c | 7 +-- 9 files changed, 109 insertions(+), 29 deletions(-) diff --git a/common/include/Makefile.am b/common/include/Makefile.am index 4ce1723..a882ff9 100644 --- a/common/include/Makefile.am +++ b/common/include/Makefile.am @@ -32,8 +32,9 @@ include $(top_srcdir)/common-rules.mk -# These headers contain only common code shared by plugins and -# filters. They are not installed. +# These headers contain only common code shared by the core server, +# plugins and/or filters. They are not installed. EXTRA_DIST = \ + exit-with-parent.h \ ispowerof2.h \ iszero.h diff --git a/common/include/exit-with-parent.h b/common/include/exit-with-parent.h new file mode 100644 index 0000000..cb4bc9b --- /dev/null +++ b/common/include/exit-with-parent.h @@ -0,0 +1,80 @@ +/* nbdkit + * Copyright (C) 2013-2018 Red Hat Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of Red Hat nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* Implement the --exit-with-parent feature on operating systems which + * support it. + */ + +#ifndef NBDKIT_EXIT_WITH_PARENT_H +#define NBDKIT_EXIT_WITH_PARENT_H + +#include <config.h> + +#include <signal.h> + +#ifdef HAVE_SYS_PRCTL_H +#include <sys/prctl.h> +#endif + +#ifdef HAVE_SYS_PROCCTL_H +#include <sys/procctl.h> +#endif + +#if defined(HAVE_SYS_PRCTL_H) && defined(PR_SET_PDEATHSIG) + +/* For Linux >= 2.1.57. */ + +static inline int +set_exit_with_parent (void) +{ + return prctl (PR_SET_PDEATHSIG, SIGTERM); +} + +#define HAVE_EXIT_WITH_PARENT 1 + +#elif defined(HAVE_SYS_PROCCTL_H) && defined(PROC_PDEATHSIG_CTL) + +/* For FreeBSD >= 11.2 */ + +static inline int +set_exit_with_parent (void) +{ + const int sig = SIGTERM; + return procctl (P_PID, 0, PROC_PDEATHSIG_CTL, (void*) &sig); +} + +#define HAVE_EXIT_WITH_PARENT 1 + +#endif + +#endif /* NBDKIT_INTERNAL_H */ diff --git a/configure.ac b/configure.ac index 91473e8..b9bb220 100644 --- a/configure.ac +++ b/configure.ac @@ -129,7 +129,7 @@ dnl restore CFLAGS CFLAGS="${acx_nbdkit_save_CFLAGS}" dnl Check for other headers, all optional. -AC_CHECK_HEADERS([selinux/selinux.h sys/prctl.h]) +AC_CHECK_HEADERS([selinux/selinux.h sys/prctl.h sys/procctl.h]) dnl Check support for setsockcreatecon_raw (part of SELinux). AC_CHECK_LIB([selinux], [setsockcreatecon_raw], [], [:]) diff --git a/docs/nbdkit-captive.pod b/docs/nbdkit-captive.pod index 5b7eff0..6db9520 100644 --- a/docs/nbdkit-captive.pod +++ b/docs/nbdkit-captive.pod @@ -103,20 +103,22 @@ I<--exit-with-parent> is incompatible with forking into the background (because when we fork into the background we lose track of the parent process). Therefore I<-f> / I<--foreground> is implied. -This is currently implemented using a feature of the Linux kernel, so -it requires a Linux build of nbdkit and won't work on other operating -systems (patches welcome to make it work). +This is currently implemented using a non-POSIX feature available in +S<Linux ≥ 2.1.57> and S<FreeBSD ≥ 11.2>, so it won't work on other +operating systems (patches welcome to make it work). If the parent application is multithreaded, then (in the Linux implementation) if the parent I<thread> exits, that will cause nbdkit to exit. Thus in multithreaded applications you usually want to run C<nbdkit --exit-with-parent> only from the main thread (unless you actually want nbdkit to exit with the thread, but that may not work -reliably if we extend the implementation to other operating systems). +reliably on all operating systems). =head1 SEE ALSO -L<nbdkit(1)>. +L<nbdkit(1)>, +L<prctl(2)> (on Linux), +L<procctl(2)> (on FreeBSD). =head1 AUTHORS diff --git a/src/Makefile.am b/src/Makefile.am index 84ef477..ae7dcc3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -62,7 +62,8 @@ nbdkit_CPPFLAGS = \ -Dfilterdir=\"$(filterdir)\" \ -Dsbindir=\"$(sbindir)\" \ -Dsysconfdir=\"$(sysconfdir)\" \ - -I$(top_srcdir)/include + -I$(top_srcdir)/include \ + -I$(top_srcdir)/common/include nbdkit_CFLAGS = \ -pthread \ $(WARNINGS_CFLAGS) \ diff --git a/src/main.c b/src/main.c index 4d8a92b..c6f0878 100644 --- a/src/main.c +++ b/src/main.c @@ -50,15 +50,12 @@ #include <assert.h> #include <syslog.h> -#ifdef HAVE_SYS_PRCTL_H -#include <sys/prctl.h> -#endif - #include <pthread.h> #include <dlfcn.h> #include "internal.h" +#include "exit-with-parent.h" #define FIRST_SOCKET_ACTIVATION_FD 3 /* defined by systemd ABI */ @@ -266,7 +263,7 @@ main (int argc, char *argv[]) break; case EXIT_WITH_PARENT_OPTION: -#ifdef PR_SET_PDEATHSIG +#ifdef HAVE_EXIT_WITH_PARENT exit_with_parent = 1; foreground = 1; break; @@ -539,10 +536,10 @@ main (int argc, char *argv[]) /* Implement --exit-with-parent early in case plugin initialization * takes a long time and the parent exits during that time. */ -#ifdef PR_SET_PDEATHSIG +#ifdef HAVE_EXIT_WITH_PARENT if (exit_with_parent) { - if (prctl (PR_SET_PDEATHSIG, SIGTERM) == -1) { - perror ("prctl: PR_SET_PDEATHSIG"); + if (set_exit_with_parent () == -1) { + perror ("nbdkit: --exit-with-parent"); exit (EXIT_FAILURE); } } diff --git a/tests/Makefile.am b/tests/Makefile.am index 86bef71..e4a28d5 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -175,8 +175,12 @@ endif HAVE_CXX check_PROGRAMS += test-exit-with-parent TESTS += test-exit-with-parent -test_exit_with_parent_SOURCES = test-exit-with-parent.c test.h -test_exit_with_parent_CFLAGS = $(WARNINGS_CFLAGS) $(LIBGUESTFS_CFLAGS) +test_exit_with_parent_SOURCES = \ + test-exit-with-parent.c test.h +test_exit_with_parent_CPPFLAGS = \ + -I$(top_srcdir)/common/include +test_exit_with_parent_CFLAGS = \ + $(WARNINGS_CFLAGS) $(LIBGUESTFS_CFLAGS) # PKI files for the TLS tests. check_DATA += pki/.stamp @@ -530,6 +534,7 @@ test_layers_SOURCES = \ test-layers.c \ $(top_srcdir)/src/protocol.h test_layers_CPPFLAGS = \ + -I$(top_srcdir)/common/include \ -I$(top_srcdir)/src test_layers_CFLAGS = \ $(WARNINGS_CFLAGS) \ diff --git a/tests/test-exit-with-parent.c b/tests/test-exit-with-parent.c index 358d64f..d364884 100644 --- a/tests/test-exit-with-parent.c +++ b/tests/test-exit-with-parent.c @@ -43,10 +43,7 @@ #include <sys/wait.h> #include <errno.h> -#ifdef HAVE_SYS_PRCTL_H -#include <sys/prctl.h> -#endif - +#include "exit-with-parent.h" #include "test.h" static char pidpath[] = "/tmp/nbdkitpidXXXXXX"; @@ -56,7 +53,7 @@ static void run_test (void); int main (int argc, char *argv[]) { -#ifndef PR_SET_PDEATHSIG +#ifndef HAVE_EXIT_WITH_PARENT printf ("--exit-with-parent is not implemented on this platform, skipping\n"); exit (77); #else diff --git a/tests/test-layers.c b/tests/test-layers.c index b83fad6..ee425ea 100644 --- a/tests/test-layers.c +++ b/tests/test-layers.c @@ -57,12 +57,9 @@ #include <sys/socket.h> #include <sys/wait.h> -#ifdef HAVE_SYS_PRCTL_H -#include <sys/prctl.h> -#endif - #include <pthread.h> +#include "exit-with-parent.h" #include "protocol.h" /* From nbdkit core. */ /* Declare program_name. */ @@ -97,7 +94,7 @@ main (int argc, char *argv[]) struct reply reply; char data[512]; -#ifndef PR_SET_PDEATHSIG +#ifndef HAVE_EXIT_WITH_PARENT printf ("%s: this test requires --exit-with-parent functionality\n", program_name); exit (77); -- 2.18.0