svn commit: r231910 - head/usr.sbin/daemon

Mikolaj Golub trociny at FreeBSD.org
Sun Feb 19 10:23:51 UTC 2012


Author: trociny
Date: Sun Feb 19 10:23:51 2012
New Revision: 231910
URL: http://svn.freebsd.org/changeset/base/231910

Log:
  If the supervising process receives SIGTERM, forward it to the spawned
  process.  Normally it will cause the child to exit followed by the
  termination of the supervisor after removing the pidfile.
  
  This looks like desirable behavior, because termination of a
  supervisor usually supposes termination of its charge. Also it will
  fix the issue with stale pid files after reboot due to init kills a
  supervisor before its child exits.
  
  MFC after:	2 weeks

Modified:
  head/usr.sbin/daemon/daemon.8
  head/usr.sbin/daemon/daemon.c

Modified: head/usr.sbin/daemon/daemon.8
==============================================================================
--- head/usr.sbin/daemon/daemon.8	Sun Feb 19 10:20:37 2012	(r231909)
+++ head/usr.sbin/daemon/daemon.8	Sun Feb 19 10:23:51 2012	(r231910)
@@ -71,6 +71,12 @@ owner is the user who runs the
 regardless of whether the
 .Fl u
 option is used or not.
+If the monitoring
+.Nm
+receives software termination signal (SIGTERM) it forwards it to the
+spawned process.
+Normally it will cause the child to exit followed by the termination
+of the supervising process after removing the pidfile.
 .It Fl u Ar user
 Login name of the user to execute the program under.
 Requires adequate superuser privileges.

Modified: head/usr.sbin/daemon/daemon.c
==============================================================================
--- head/usr.sbin/daemon/daemon.c	Sun Feb 19 10:20:37 2012	(r231909)
+++ head/usr.sbin/daemon/daemon.c	Sun Feb 19 10:23:51 2012	(r231910)
@@ -36,21 +36,24 @@ __FBSDID("$FreeBSD$");
 
 #include <err.h>
 #include <errno.h>
-#include <pwd.h>
 #include <libutil.h>
 #include <login_cap.h>
+#include <pwd.h>
+#include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 
+static void dummy_sighandler(int);
 static void restrict_process(const char *);
-static void wait_child(pid_t pid);
+static void wait_child(pid_t pid, sigset_t *mask);
 static void usage(void);
 
 int
 main(int argc, char *argv[])
 {
 	struct pidfh *pfh = NULL;
+	sigset_t mask, oldmask;
 	int ch, nochdir, noclose;
 	const char *pidfile, *user;
 	pid_t otherpid, pid;
@@ -100,9 +103,37 @@ main(int argc, char *argv[])
 	if (daemon(nochdir, noclose) == -1)
 		err(1, NULL);
 
-	pid = 0;
+	/*
+	 * If the pidfile option is specified the daemon executes the
+	 * command in a forked process and wait on child exit to
+	 * remove the pidfile. Normally we don't want the monitoring
+	 * daemon to be terminated leaving the running process and the
+	 * stale pidfile, so we catch SIGTERM and pass it to the
+	 * children expecting to get SIGCHLD eventually.
+	 */
+	pid = -1;
 	if (pidfile != NULL) {
 		/*
+		 * Restore default action for SIGTERM in case the
+		 * parent process decided to ignore it.
+		 */
+		if (signal(SIGTERM, SIG_DFL) == SIG_ERR)
+			err(1, "signal");
+		/*
+		 * Because SIGCHLD is ignored by default, setup dummy handler
+		 * for it, so we can mask it.
+		 */
+		if (signal(SIGCHLD, dummy_sighandler) == SIG_ERR)
+			err(1, "signal");
+		/*
+		 * Block interesting signals.
+		 */
+		sigemptyset(&mask);
+		sigaddset(&mask, SIGTERM);
+		sigaddset(&mask, SIGCHLD);
+		if (sigprocmask(SIG_SETMASK, &mask, &oldmask) == -1)
+			err(1, "sigprocmask");
+		/*
 		 * Spawn a child to exec the command, so in the parent
 		 * we could wait for it to exit and remove pidfile.
 		 */
@@ -112,7 +143,12 @@ main(int argc, char *argv[])
 			err(1, "fork");
 		}
 	}
-	if (pid == 0) {
+	if (pid <= 0) {
+		if (pid == 0) {
+			/* Restore old sigmask in the child. */
+			if (sigprocmask(SIG_SETMASK, &oldmask, NULL) == -1)
+				err(1, "sigprocmask");
+		}
 		/* Now that we are the child, write out the pid. */
 		pidfile_write(pfh);
 
@@ -128,12 +164,18 @@ main(int argc, char *argv[])
 		err(1, "%s", argv[0]);
 	}
 	setproctitle("%s[%d]", argv[0], pid);
-	wait_child(pid);
+	wait_child(pid, &mask);
 	pidfile_remove(pfh);
 	exit(0); /* Exit status does not matter. */
 }
 
 static void
+dummy_sighandler(int sig __unused)
+{
+	/* Nothing to do. */
+}
+
+static void
 restrict_process(const char *user)
 {
 	struct passwd *pw = NULL;
@@ -147,14 +189,27 @@ restrict_process(const char *user)
 }
 
 static void
-wait_child(pid_t pid)
+wait_child(pid_t pid, sigset_t *mask)
 {
-	int status;
+	int signo;
 
-	while (waitpid(pid, &status, 0) == -1) {
-		if (errno != EINTR) {
-			warn("waitpid");
-			break;
+	for (;;) {
+		if (sigwait(mask, &signo) == -1) {
+			warn("sigwaitinfo");
+			return;
+		}
+		switch (signo) {
+		case SIGCHLD:
+			return;
+		case SIGTERM:
+			if (kill(pid, signo) == -1) {
+				warn("kill");
+				return;
+			}
+			continue;
+		default:
+			warnx("sigwaitinfo: invalid signal: %d", signo);
+			return;
 		}
 	}
 }


More information about the svn-src-all mailing list