From d5e86b62a229b3bf4f38c4c0d1a9ca1eef47f3c5 Mon Sep 17 00:00:00 2001 From: trociny Date: Thu, 3 Oct 2013 18:48:43 +0000 Subject: [PATCH] MFC r255521, r255526, r255707: r255521 (jmg): add support for writing the pid of the daemon program to a pid file so that daemon can be used w/ rc.subr and ports can use the additional functionality, such as keeping the ldap daemon up and running, and have the proper program to signal to exit.. PR: bin/181341 Submitted by: feld r255526 (joel): mdoc: remove EOL whitespace. r255707: 1. Properly clean pid files in the case of the error. 2. Write the supervisor pid before the restart loop, so we don't uselessly rewrite it after every child restart. 3. Remove duplicate ppfh and pfh initialization. git-svn-id: svn://svn.freebsd.org/base/stable/9@256025 ccf9f872-aa2e-dd11-9fc8-001c23d0bc1f --- usr.sbin/daemon/daemon.8 | 64 ++++++++++++++++++++++++++++++------- usr.sbin/daemon/daemon.c | 68 +++++++++++++++++++++++++++++----------- 2 files changed, 101 insertions(+), 31 deletions(-) diff --git a/usr.sbin/daemon/daemon.8 b/usr.sbin/daemon/daemon.8 index 14b134af6..87cfd980a 100644 --- a/usr.sbin/daemon/daemon.8 +++ b/usr.sbin/daemon/daemon.8 @@ -26,7 +26,7 @@ .\" .\" $FreeBSD$ .\" -.Dd June 4, 2012 +.Dd September 13, 2013 .Dt DAEMON 8 .Os .Sh NAME @@ -35,7 +35,8 @@ .Sh SYNOPSIS .Nm .Op Fl cfr -.Op Fl p Ar pidfile +.Op Fl p Ar child_pidfile +.Op Fl P Ar supervisor_pidfile .Op Fl u Ar user .Ar command arguments ... .Sh DESCRIPTION @@ -53,19 +54,39 @@ Change the current working directory to the root .It Fl f Redirect standard input, standard output and standard error to .Pa /dev/null . -.It Fl p Ar file +.It Fl p Ar child_pidfile Write the ID of the created process into the -.Ar file +.Ar child_pidfile using the .Xr pidfile 3 functionality. The program is executed in a spawned child process while the .Nm waits until it terminates to keep the -.Ar file +.Ar child_pidfile locked and removes it after the process exits. The -.Ar file +.Ar child_pidfile +owner is the user who runs the +.Nm +regardless of whether the +.Fl u +option is used or not. +.It Fl P Ar supervisor_pidfile +Write the ID of the +.Nm +process into the +.Ar supervisor_pidfile +using the +.Xr pidfile 3 +functionality. +The program is executed in a spawned child process while the +.Nm +waits until it terminates to keep the +.Ar supervisor_pidfile +locked and removes it after the process exits. +The +.Ar supervisor_pidfile owner is the user who runs the .Nm regardless of whether the @@ -79,27 +100,46 @@ Requires adequate superuser privileges. .El .Pp If the -.Fl p +.Fl p , +.Fl P or .Fl r option is specified the program is executed in a spawned child process. The .Nm -waits until it terminates to keep the pid file locked and removes it +waits until it terminates to keep the pid file(s) locked and removes them after the process exits or restarts the program. In this case 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. +Normally it will cause the child to exit, remove the pidfile(s) +and then terminate. +.Pp +The +.Fl P +option is useful combined with the +.Fl r +option as +.Ar supervisor_pidfile +contains the ID of the supervisor +not the child. This is especially important if you use +.Fl r +in an rc script as the +.Fl p +option will give you the child's ID to signal when you attempt to +stop the service, causing +.Nm +to restart the child. .Sh EXIT STATUS The .Nm utility exits 1 if an error is returned by the .Xr daemon 3 -library routine, 2 if the -.Ar pidfile +library routine, 2 if +.Ar child_pidfile +or +.Ar supervisor_pidfile is requested, but cannot be opened, 3 if process is already running (pidfile exists and is locked), otherwise 0. diff --git a/usr.sbin/daemon/daemon.c b/usr.sbin/daemon/daemon.c index b012c882e..322c0d496 100644 --- a/usr.sbin/daemon/daemon.c +++ b/usr.sbin/daemon/daemon.c @@ -53,16 +53,16 @@ static void usage(void); int main(int argc, char *argv[]) { - struct pidfh *pfh = NULL; + struct pidfh *ppfh, *pfh; sigset_t mask, oldmask; - int ch, nochdir, noclose, restart; - const char *pidfile, *user; + int ch, nochdir, noclose, restart, serrno; + const char *pidfile, *ppidfile, *user; pid_t otherpid, pid; nochdir = noclose = 1; restart = 0; - pidfile = user = NULL; - while ((ch = getopt(argc, argv, "cfp:ru:")) != -1) { + ppidfile = pidfile = user = NULL; + while ((ch = getopt(argc, argv, "cfp:P:ru:")) != -1) { switch (ch) { case 'c': nochdir = 0; @@ -73,6 +73,9 @@ main(int argc, char *argv[]) case 'p': pidfile = optarg; break; + case 'P': + ppidfile = optarg; + break; case 'r': restart = 1; break; @@ -89,7 +92,7 @@ main(int argc, char *argv[]) if (argc == 0) usage(); - pfh = NULL; + ppfh = pfh = NULL; /* * Try to open the pidfile before calling daemon(3), * to be able to report the error intelligently @@ -104,9 +107,27 @@ main(int argc, char *argv[]) err(2, "pidfile ``%s''", pidfile); } } + /* Do the same for actual daemon process. */ + if (ppidfile != NULL) { + ppfh = pidfile_open(ppidfile, 0600, &otherpid); + if (ppfh == NULL) { + serrno = errno; + pidfile_remove(pfh); + errno = serrno; + if (errno == EEXIST) { + errx(3, "process already running, pid: %d", + otherpid); + } + err(2, "ppidfile ``%s''", ppidfile); + } + } - if (daemon(nochdir, noclose) == -1) - err(1, NULL); + if (daemon(nochdir, noclose) == -1) { + warn("daemon"); + goto exit; + } + /* Write out parent pidfile if needed. */ + pidfile_write(ppfh); /* * If the pidfile or restart option is specified the daemon @@ -123,22 +144,28 @@ main(int argc, char *argv[]) * Restore default action for SIGTERM in case the * parent process decided to ignore it. */ - if (signal(SIGTERM, SIG_DFL) == SIG_ERR) - err(1, "signal"); + if (signal(SIGTERM, SIG_DFL) == SIG_ERR) { + warn("signal"); + goto exit; + } /* * 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"); + if (signal(SIGCHLD, dummy_sighandler) == SIG_ERR) { + warn("signal"); + goto exit; + } /* * Block interesting signals. */ sigemptyset(&mask); sigaddset(&mask, SIGTERM); sigaddset(&mask, SIGCHLD); - if (sigprocmask(SIG_SETMASK, &mask, &oldmask) == -1) - err(1, "sigprocmask"); + if (sigprocmask(SIG_SETMASK, &mask, &oldmask) == -1) { + warn("sigprocmask"); + goto exit; + } /* * Try to protect against pageout kill. Ignore the * error, madvise(2) will fail only if a process does @@ -152,8 +179,8 @@ restart: */ pid = fork(); if (pid == -1) { - pidfile_remove(pfh); - err(1, "fork"); + warn("fork"); + goto exit; } } if (pid <= 0) { @@ -176,13 +203,16 @@ restart: */ err(1, "%s", argv[0]); } + setproctitle("%s[%d]", argv[0], pid); if (wait_child(pid, &mask) == 0 && restart) { sleep(1); goto restart; } +exit: pidfile_remove(pfh); - exit(0); /* Exit status does not matter. */ + pidfile_remove(ppfh); + exit(1); /* If daemon(3) succeeded exit status does not matter. */ } static void @@ -240,7 +270,7 @@ static void usage(void) { (void)fprintf(stderr, - "usage: daemon [-cfr] [-p pidfile] [-u user] command " - "arguments ...\n"); + "usage: daemon [-cfr] [-p child_pidfile] [-P supervisor_pidfile] " + "[-u user]\n command arguments ...\n"); exit(1); } -- 2.45.0