daemon.c revision 255707
189051Sjake/*- 289051Sjake * Copyright (c) 1999 Berkeley Software Design, Inc. All rights reserved. 389051Sjake * 489051Sjake * Redistribution and use in source and binary forms, with or without 589051Sjake * modification, are permitted provided that the following conditions 689051Sjake * are met: 789051Sjake * 1. Redistributions of source code must retain the above copyright 889051Sjake * notice, this list of conditions and the following disclaimer. 989051Sjake * 2. Redistributions in binary form must reproduce the above copyright 1089051Sjake * notice, this list of conditions and the following disclaimer in the 1189051Sjake * documentation and/or other materials provided with the distribution. 1289051Sjake * 3. Berkeley Software Design Inc's name may not be used to endorse or 1389051Sjake * promote products derived from this software without specific prior 1489051Sjake * written permission. 1589051Sjake * 1689051Sjake * THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN INC ``AS IS'' AND 1789051Sjake * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1889051Sjake * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1989051Sjake * ARE DISCLAIMED. IN NO EVENT SHALL BERKELEY SOFTWARE DESIGN INC BE LIABLE 2089051Sjake * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2189051Sjake * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2289051Sjake * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2389051Sjake * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2489051Sjake * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2589051Sjake * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2689051Sjake * SUCH DAMAGE. 2789051Sjake * 2889051Sjake * From BSDI: daemon.c,v 1.2 1996/08/15 01:11:09 jch Exp 2989051Sjake */ 3089051Sjake 3189051Sjake#include <sys/cdefs.h> 3289051Sjake__FBSDID("$FreeBSD: head/usr.sbin/daemon/daemon.c 255707 2013-09-19 18:00:05Z trociny $"); 3389051Sjake 3489051Sjake#include <sys/param.h> 3589051Sjake#include <sys/mman.h> 3689051Sjake#include <sys/wait.h> 3789051Sjake 3889051Sjake#include <err.h> 3989051Sjake#include <errno.h> 4089051Sjake#include <libutil.h> 4189051Sjake#include <login_cap.h> 4289051Sjake#include <pwd.h> 4389051Sjake#include <signal.h> 4489051Sjake#include <stdio.h> 4589051Sjake#include <stdlib.h> 4689051Sjake#include <unistd.h> 4789051Sjake 4889051Sjakestatic void dummy_sighandler(int); 4989051Sjakestatic void restrict_process(const char *); 5089051Sjakestatic int wait_child(pid_t pid, sigset_t *mask); 5189051Sjakestatic void usage(void); 5289051Sjake 5389051Sjakeint 5489051Sjakemain(int argc, char *argv[]) 5589051Sjake{ 5689051Sjake struct pidfh *ppfh, *pfh; 5789051Sjake sigset_t mask, oldmask; 58107103Sjhb int ch, nochdir, noclose, restart, serrno; 59107103Sjhb const char *pidfile, *ppidfile, *user; 6089051Sjake pid_t otherpid, pid; 6189051Sjake 6289051Sjake nochdir = noclose = 1; 6389051Sjake restart = 0; 6489051Sjake ppidfile = pidfile = user = NULL; 6589051Sjake while ((ch = getopt(argc, argv, "cfp:P:ru:")) != -1) { 6689051Sjake switch (ch) { 6789051Sjake case 'c': 6889051Sjake nochdir = 0; 6989051Sjake break; 7089051Sjake case 'f': 7189051Sjake noclose = 0; 7289051Sjake break; 7389051Sjake case 'p': 7489051Sjake pidfile = optarg; 7589051Sjake break; 7689051Sjake case 'P': 7789051Sjake ppidfile = optarg; 7889051Sjake break; 7992205Sjake case 'r': 8092205Sjake restart = 1; 8189051Sjake break; 8292205Sjake case 'u': 83119696Smarcel user = optarg; 8489051Sjake break; 8597511Sjake default: 8692205Sjake usage(); 8789051Sjake } 8895132Sjake } 8991617Sjake argc -= optind; 9089051Sjake argv += optind; 9189051Sjake 9289051Sjake if (argc == 0) 9389051Sjake usage(); 9489051Sjake 9589051Sjake ppfh = pfh = NULL; 9689051Sjake /* 9789051Sjake * Try to open the pidfile before calling daemon(3), 9889051Sjake * to be able to report the error intelligently 9989051Sjake */ 10089051Sjake if (pidfile != NULL) { 10191783Sjake pfh = pidfile_open(pidfile, 0600, &otherpid); 10297001Sjake if (pfh == NULL) { 10391783Sjake if (errno == EEXIST) { 10489051Sjake errx(3, "process already running, pid: %d", 105108187Sjake otherpid); 106108187Sjake } 10791617Sjake err(2, "pidfile ``%s''", pidfile); 10891617Sjake } 10989051Sjake } 11089051Sjake /* Do the same for actual daemon process. */ 11192205Sjake if (ppidfile != NULL) { 11292205Sjake ppfh = pidfile_open(ppidfile, 0600, &otherpid); 11391617Sjake if (ppfh == NULL) { 11491617Sjake serrno = errno; 11591617Sjake pidfile_remove(pfh); 11691617Sjake errno = serrno; 11791617Sjake if (errno == EEXIST) { 11891617Sjake errx(3, "process already running, pid: %d", 11991617Sjake otherpid); 12091617Sjake } 12191617Sjake err(2, "ppidfile ``%s''", ppidfile); 12291617Sjake } 12391617Sjake } 12491617Sjake 12591617Sjake if (daemon(nochdir, noclose) == -1) { 12691617Sjake warn("daemon"); 12791617Sjake goto exit; 12891617Sjake } 12991617Sjake /* Write out parent pidfile if needed. */ 13097511Sjake pidfile_write(ppfh); 131102042Sjake 13297511Sjake /* 13397511Sjake * If the pidfile or restart option is specified the daemon 13497511Sjake * executes the command in a forked process and wait on child 13591617Sjake * exit to remove the pidfile or restart the command. Normally 13691617Sjake * we don't want the monitoring daemon to be terminated 13791617Sjake * leaving the running process and the stale pidfile, so we 13891617Sjake * catch SIGTERM and forward it to the children expecting to 13991617Sjake * get SIGCHLD eventually. 14089051Sjake */ 14189051Sjake pid = -1; 14289051Sjake if (pidfile != NULL || restart) { 143122947Sjhb /* 144122947Sjhb * Restore default action for SIGTERM in case the 14589051Sjake * parent process decided to ignore it. 14689051Sjake */ 14789051Sjake if (signal(SIGTERM, SIG_DFL) == SIG_ERR) { 14889051Sjake warn("signal"); 14989051Sjake goto exit; 15089051Sjake } 15189051Sjake /* 15289051Sjake * Because SIGCHLD is ignored by default, setup dummy handler 15389051Sjake * for it, so we can mask it. 15489051Sjake */ 15589051Sjake if (signal(SIGCHLD, dummy_sighandler) == SIG_ERR) { 15689051Sjake warn("signal"); 15789051Sjake goto exit; 15889051Sjake } 15989051Sjake /* 16089051Sjake * Block interesting signals. 16189051Sjake */ 16293683Stmm sigemptyset(&mask); 16389051Sjake sigaddset(&mask, SIGTERM); 16489051Sjake sigaddset(&mask, SIGCHLD); 165122947Sjhb if (sigprocmask(SIG_SETMASK, &mask, &oldmask) == -1) { 166122947Sjhb warn("sigprocmask"); 167122947Sjhb goto exit; 168122947Sjhb } 169122947Sjhb /* 170122947Sjhb * Try to protect against pageout kill. Ignore the 171122947Sjhb * error, madvise(2) will fail only if a process does 17291617Sjake * not have superuser privileges. 17391617Sjake */ 17491617Sjake (void)madvise(NULL, 0, MADV_PROTECT); 17591617Sjakerestart: 17691617Sjake /* 17791617Sjake * Spawn a child to exec the command, so in the parent 17891617Sjake * we could wait for it to exit and remove pidfile. 17991617Sjake */ 18091617Sjake pid = fork(); 18191617Sjake if (pid == -1) { 18291617Sjake warn("fork"); 18391617Sjake goto exit; 18491617Sjake } 18591617Sjake } 18691617Sjake if (pid <= 0) { 18791617Sjake if (pid == 0) { 18891617Sjake /* Restore old sigmask in the child. */ 18991617Sjake if (sigprocmask(SIG_SETMASK, &oldmask, NULL) == -1) 19091617Sjake err(1, "sigprocmask"); 19191617Sjake } 19291617Sjake /* Now that we are the child, write out the pid. */ 19391617Sjake pidfile_write(pfh); 19491617Sjake 19591617Sjake if (user != NULL) 19691617Sjake restrict_process(user); 19789051Sjake 19892205Sjake execvp(argv[0], argv); 19992205Sjake 20092205Sjake /* 20192205Sjake * execvp() failed -- report the error. The child is 20292205Sjake * now running, so the exit status doesn't matter. 20392205Sjake */ 20492205Sjake err(1, "%s", argv[0]); 20592205Sjake } 20692205Sjake 20792205Sjake setproctitle("%s[%d]", argv[0], pid); 20892205Sjake if (wait_child(pid, &mask) == 0 && restart) { 20992205Sjake sleep(1); 21092205Sjake goto restart; 21192205Sjake } 21292205Sjakeexit: 21392205Sjake pidfile_remove(pfh); 21492205Sjake pidfile_remove(ppfh); 21592205Sjake exit(1); /* If daemon(3) succeeded exit status does not matter. */ 21692205Sjake} 21792205Sjake 21889051Sjakestatic void 21989051Sjakedummy_sighandler(int sig __unused) 22089051Sjake{ 22189051Sjake /* Nothing to do. */ 22289051Sjake} 22389051Sjake 22489051Sjakestatic void 22589051Sjakerestrict_process(const char *user) 22689051Sjake{ 22789051Sjake struct passwd *pw = NULL; 22889051Sjake 22991617Sjake pw = getpwnam(user); 23091617Sjake if (pw == NULL) 23189051Sjake errx(1, "unknown user: %s", user); 23291617Sjake 23389051Sjake if (setusercontext(NULL, pw, pw->pw_uid, LOGIN_SETALL) != 0) 234108187Sjake errx(1, "failed to set user environment"); 23589051Sjake} 23689051Sjake 23789051Sjakestatic int 23889051Sjakewait_child(pid_t pid, sigset_t *mask) 23989051Sjake{ 24089051Sjake int terminate, signo; 24189051Sjake 24289051Sjake terminate = 0; 24389051Sjake for (;;) { 24489051Sjake if (sigwait(mask, &signo) == -1) { 24589051Sjake warn("sigwaitinfo"); 24689051Sjake return (-1); 24799936Sjake } 24899936Sjake switch (signo) { 24989051Sjake case SIGCHLD: 25089051Sjake if (waitpid(pid, NULL, WNOHANG) == -1) { 25189051Sjake warn("waitpid"); 25291617Sjake return (-1); 25391617Sjake } 25491617Sjake return (terminate); 25589051Sjake case SIGTERM: 25691617Sjake terminate = 1; 25791617Sjake if (kill(pid, signo) == -1) { 25891617Sjake warn("kill"); 25991617Sjake return (-1); 26091617Sjake } 26191617Sjake continue; 26291617Sjake default: 26391617Sjake warnx("sigwaitinfo: invalid signal: %d", signo); 26491617Sjake return (-1); 26591617Sjake } 26691617Sjake } 26791617Sjake} 26889051Sjake 26991617Sjakestatic void 27091617Sjakeusage(void) 27191617Sjake{ 27291617Sjake (void)fprintf(stderr, 27389051Sjake "usage: daemon [-cfr] [-p child_pidfile] [-P supervisor_pidfile] " 27491617Sjake "[-u user]\n command arguments ...\n"); 27589051Sjake exit(1); 276101898Sjake} 27789051Sjake