Index: head/usr.sbin/daemon/daemon.8 =================================================================== --- head/usr.sbin/daemon/daemon.8 (revision 296320) +++ head/usr.sbin/daemon/daemon.8 (revision 296321) @@ -1,163 +1,167 @@ .\" Copyright (c) 1999 Berkeley Software Design, 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: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. 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. .\" 3. Berkeley Software Design Inc's name may not be used to endorse or .\" promote products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN INC ``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 BERKELEY SOFTWARE DESIGN INC 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. .\" .\" $FreeBSD$ .\" -.Dd September 13, 2013 +.Dd March 2, 2016 .Dt DAEMON 8 .Os .Sh NAME .Nm daemon .Nd run detached from the controlling terminal .Sh SYNOPSIS .Nm .Op Fl cfr .Op Fl p Ar child_pidfile .Op Fl P Ar supervisor_pidfile +.Op Fl t Ar title .Op Fl u Ar user .Ar command arguments ... .Sh DESCRIPTION The .Nm utility detaches itself from the controlling terminal and executes the program specified by its arguments. Privileges may be lowered to the specified user. .Pp The options are as follows: .Bl -tag -width indent .It Fl c Change the current working directory to the root .Pq Dq Pa / . .It Fl f Redirect standard input, standard output and standard error to .Pa /dev/null . .It Fl p Ar child_pidfile Write the ID of the created process into the .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 child_pidfile locked and removes it after the process exits. The .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 .Fl u option is used or not. .It Fl r Supervise and restart the program if it has been terminated. +.It Fl t Ar title +Process title for the daemon to make it easily identifiable. .It Fl u Ar user Login name of the user to execute the program under. Requires adequate superuser privileges. .El .Pp If the .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(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, 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 +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 .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. .Sh DIAGNOSTICS If the command cannot be executed, an error message is displayed on standard error unless the .Fl f flag is specified. .Sh SEE ALSO .Xr setregid 2 , .Xr setreuid 2 , .Xr daemon 3 , .Xr exec 3 , .Xr pidfile 3 , .Xr termios 4 , .Xr tty 4 .Sh HISTORY The .Nm utility first appeared in .Fx 4.7 . Index: head/usr.sbin/daemon/daemon.c =================================================================== --- head/usr.sbin/daemon/daemon.c (revision 296320) +++ head/usr.sbin/daemon/daemon.c (revision 296321) @@ -1,276 +1,282 @@ /*- * Copyright (c) 1999 Berkeley Software Design, 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: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. 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. * 3. Berkeley Software Design Inc's name may not be used to endorse or * promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN INC ``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 BERKELEY SOFTWARE DESIGN INC 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. * * From BSDI: daemon.c,v 1.2 1996/08/15 01:11:09 jch Exp */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include static void dummy_sighandler(int); static void restrict_process(const char *); static int wait_child(pid_t pid, sigset_t *mask); static void usage(void); int main(int argc, char *argv[]) { struct pidfh *ppfh, *pfh; sigset_t mask, oldmask; int ch, nochdir, noclose, restart, serrno; - const char *pidfile, *ppidfile, *user; + const char *pidfile, *ppidfile, *title, *user; pid_t otherpid, pid; nochdir = noclose = 1; restart = 0; - ppidfile = pidfile = user = NULL; - while ((ch = getopt(argc, argv, "cfp:P:ru:")) != -1) { + ppidfile = pidfile = title = user = NULL; + while ((ch = getopt(argc, argv, "cfp:P:rt:u:")) != -1) { switch (ch) { case 'c': nochdir = 0; break; case 'f': noclose = 0; break; case 'p': pidfile = optarg; break; case 'P': ppidfile = optarg; break; case 'r': restart = 1; break; + case 't': + title = optarg; + break; case 'u': user = optarg; break; default: usage(); } } argc -= optind; argv += optind; if (argc == 0) usage(); ppfh = pfh = NULL; /* * Try to open the pidfile before calling daemon(3), * to be able to report the error intelligently */ if (pidfile != NULL) { pfh = pidfile_open(pidfile, 0600, &otherpid); if (pfh == NULL) { if (errno == EEXIST) { errx(3, "process already running, pid: %d", otherpid); } 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) { warn("daemon"); goto exit; } /* Write out parent pidfile if needed. */ pidfile_write(ppfh); /* * If the pidfile or restart option is specified the daemon * executes the command in a forked process and wait on child * exit to remove the pidfile or restart the command. Normally * we don't want the monitoring daemon to be terminated * leaving the running process and the stale pidfile, so we * catch SIGTERM and forward it to the children expecting to * get SIGCHLD eventually. */ pid = -1; if (pidfile != NULL || ppidfile != NULL || restart) { /* * Restore default action for SIGTERM in case the * parent process decided to ignore it. */ 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) { warn("signal"); goto exit; } /* * Block interesting signals. */ sigemptyset(&mask); sigaddset(&mask, SIGTERM); sigaddset(&mask, SIGCHLD); 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 * not have superuser privileges. */ (void)madvise(NULL, 0, MADV_PROTECT); restart: /* * Spawn a child to exec the command, so in the parent * we could wait for it to exit and remove pidfile. */ pid = fork(); if (pid == -1) { warn("fork"); goto exit; } } 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); if (user != NULL) restrict_process(user); execvp(argv[0], argv); /* * execvp() failed -- report the error. The child is * now running, so the exit status doesn't matter. */ err(1, "%s", argv[0]); } - setproctitle("%s[%d]", argv[0], pid); + if (title != NULL) + setproctitle("%s[%d]", title, pid); + else + setproctitle("%s[%d]", argv[0], pid); if (wait_child(pid, &mask) == 0 && restart) { sleep(1); goto restart; } exit: pidfile_remove(pfh); pidfile_remove(ppfh); exit(1); /* If daemon(3) succeeded 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; pw = getpwnam(user); if (pw == NULL) errx(1, "unknown user: %s", user); if (setusercontext(NULL, pw, pw->pw_uid, LOGIN_SETALL) != 0) errx(1, "failed to set user environment"); } static int wait_child(pid_t pid, sigset_t *mask) { int terminate, signo; terminate = 0; for (;;) { if (sigwait(mask, &signo) == -1) { warn("sigwaitinfo"); return (-1); } switch (signo) { case SIGCHLD: if (waitpid(pid, NULL, WNOHANG) == -1) { warn("waitpid"); return (-1); } return (terminate); case SIGTERM: terminate = 1; if (kill(pid, signo) == -1) { warn("kill"); return (-1); } continue; default: warnx("sigwaitinfo: invalid signal: %d", signo); return (-1); } } } static void usage(void) { (void)fprintf(stderr, "usage: daemon [-cfr] [-p child_pidfile] [-P supervisor_pidfile] " "[-u user]\n command arguments ...\n"); exit(1); }