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