daemon.c revision 236551
1214501Srpaulo/*- 2214501Srpaulo * Copyright (c) 1999 Berkeley Software Design, Inc. All rights reserved. 3214501Srpaulo * 4214501Srpaulo * Redistribution and use in source and binary forms, with or without 5252726Srpaulo * modification, are permitted provided that the following conditions 6252726Srpaulo * are met: 7214501Srpaulo * 1. Redistributions of source code must retain the above copyright 8214501Srpaulo * notice, this list of conditions and the following disclaimer. 9214501Srpaulo * 2. Redistributions in binary form must reproduce the above copyright 10214501Srpaulo * notice, this list of conditions and the following disclaimer in the 11214501Srpaulo * documentation and/or other materials provided with the distribution. 12214501Srpaulo * 3. Berkeley Software Design Inc's name may not be used to endorse or 13214501Srpaulo * promote products derived from this software without specific prior 14214501Srpaulo * written permission. 15214501Srpaulo * 16214501Srpaulo * THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN INC ``AS IS'' AND 17214501Srpaulo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18214501Srpaulo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19214501Srpaulo * ARE DISCLAIMED. IN NO EVENT SHALL BERKELEY SOFTWARE DESIGN INC BE LIABLE 20214501Srpaulo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21214501Srpaulo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22214501Srpaulo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23214501Srpaulo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24214501Srpaulo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25214501Srpaulo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26214501Srpaulo * SUCH DAMAGE. 27214501Srpaulo * 28214501Srpaulo * From BSDI: daemon.c,v 1.2 1996/08/15 01:11:09 jch Exp 29214501Srpaulo */ 30214501Srpaulo 31214501Srpaulo#include <sys/cdefs.h> 32214501Srpaulo__FBSDID("$FreeBSD: head/usr.sbin/daemon/daemon.c 236551 2012-06-04 09:25:01Z trociny $"); 33214501Srpaulo 34214501Srpaulo#include <sys/param.h> 35214501Srpaulo#include <sys/mman.h> 36214501Srpaulo#include <sys/wait.h> 37214501Srpaulo 38214501Srpaulo#include <err.h> 39214501Srpaulo#include <errno.h> 40214501Srpaulo#include <libutil.h> 41214501Srpaulo#include <login_cap.h> 42214501Srpaulo#include <pwd.h> 43214501Srpaulo#include <signal.h> 44214501Srpaulo#include <stdio.h> 45214501Srpaulo#include <stdlib.h> 46214501Srpaulo#include <unistd.h> 47214501Srpaulo 48214501Srpaulostatic void dummy_sighandler(int); 49214501Srpaulostatic void restrict_process(const char *); 50214501Srpaulostatic int wait_child(pid_t pid, sigset_t *mask); 51214501Srpaulostatic void usage(void); 52214501Srpaulo 53214501Srpauloint 54214501Srpaulomain(int argc, char *argv[]) 55214501Srpaulo{ 56214501Srpaulo struct pidfh *pfh = NULL; 57214501Srpaulo sigset_t mask, oldmask; 58214501Srpaulo int ch, nochdir, noclose, restart; 59214501Srpaulo const char *pidfile, *user; 60214501Srpaulo pid_t otherpid, pid; 61214501Srpaulo 62214501Srpaulo nochdir = noclose = 1; 63214501Srpaulo restart = 0; 64214501Srpaulo pidfile = user = NULL; 65214501Srpaulo while ((ch = getopt(argc, argv, "-cfp:ru:")) != -1) { 66214501Srpaulo switch (ch) { 67214501Srpaulo case 'c': 68214501Srpaulo nochdir = 0; 69214501Srpaulo break; 70214501Srpaulo case 'f': 71214501Srpaulo noclose = 0; 72214501Srpaulo break; 73214501Srpaulo case 'p': 74214501Srpaulo pidfile = optarg; 75214501Srpaulo break; 76214501Srpaulo case 'r': 77214501Srpaulo restart = 1; 78214501Srpaulo break; 79214501Srpaulo case 'u': 80214501Srpaulo user = optarg; 81214501Srpaulo break; 82214501Srpaulo default: 83214501Srpaulo usage(); 84214501Srpaulo } 85214501Srpaulo } 86214501Srpaulo argc -= optind; 87214501Srpaulo argv += optind; 88214501Srpaulo 89214501Srpaulo if (argc == 0) 90214501Srpaulo usage(); 91214501Srpaulo 92214501Srpaulo pfh = NULL; 93214501Srpaulo /* 94214501Srpaulo * Try to open the pidfile before calling daemon(3), 95214501Srpaulo * to be able to report the error intelligently 96214501Srpaulo */ 97214501Srpaulo if (pidfile != NULL) { 98214501Srpaulo pfh = pidfile_open(pidfile, 0600, &otherpid); 99214501Srpaulo if (pfh == NULL) { 100214501Srpaulo if (errno == EEXIST) { 101214501Srpaulo errx(3, "process already running, pid: %d", 102214501Srpaulo otherpid); 103214501Srpaulo } 104214501Srpaulo err(2, "pidfile ``%s''", pidfile); 105214501Srpaulo } 106214501Srpaulo } 107214501Srpaulo 108214501Srpaulo if (daemon(nochdir, noclose) == -1) 109214501Srpaulo err(1, NULL); 110214501Srpaulo 111214501Srpaulo /* 112214501Srpaulo * If the pidfile or restart option is specified the daemon 113214501Srpaulo * executes the command in a forked process and wait on child 114214501Srpaulo * exit to remove the pidfile or restart the command. Normally 115214501Srpaulo * we don't want the monitoring daemon to be terminated 116214501Srpaulo * leaving the running process and the stale pidfile, so we 117214501Srpaulo * catch SIGTERM and forward it to the children expecting to 118214501Srpaulo * get SIGCHLD eventually. 119214501Srpaulo */ 120214501Srpaulo pid = -1; 121214501Srpaulo if (pidfile != NULL || restart) { 122214501Srpaulo /* 123214501Srpaulo * Restore default action for SIGTERM in case the 124214501Srpaulo * parent process decided to ignore it. 125214501Srpaulo */ 126214501Srpaulo if (signal(SIGTERM, SIG_DFL) == SIG_ERR) 127214501Srpaulo err(1, "signal"); 128214501Srpaulo /* 129214501Srpaulo * Because SIGCHLD is ignored by default, setup dummy handler 130214501Srpaulo * for it, so we can mask it. 131214501Srpaulo */ 132214501Srpaulo if (signal(SIGCHLD, dummy_sighandler) == SIG_ERR) 133214501Srpaulo err(1, "signal"); 134214501Srpaulo /* 135214501Srpaulo * Block interesting signals. 136214501Srpaulo */ 137214501Srpaulo sigemptyset(&mask); 138214501Srpaulo sigaddset(&mask, SIGTERM); 139214501Srpaulo sigaddset(&mask, SIGCHLD); 140214501Srpaulo if (sigprocmask(SIG_SETMASK, &mask, &oldmask) == -1) 141214501Srpaulo err(1, "sigprocmask"); 142214501Srpaulo /* 143214501Srpaulo * Try to protect against pageout kill. Ignore the 144214501Srpaulo * error, madvise(2) will fail only if a process does 145214501Srpaulo * not have superuser privileges. 146214501Srpaulo */ 147214501Srpaulo (void)madvise(NULL, 0, MADV_PROTECT); 148214501Srpaulorestart: 149214501Srpaulo /* 150214501Srpaulo * Spawn a child to exec the command, so in the parent 151214501Srpaulo * we could wait for it to exit and remove pidfile. 152214501Srpaulo */ 153214501Srpaulo pid = fork(); 154214501Srpaulo if (pid == -1) { 155214501Srpaulo pidfile_remove(pfh); 156214501Srpaulo err(1, "fork"); 157214501Srpaulo } 158214501Srpaulo } 159214501Srpaulo if (pid <= 0) { 160214501Srpaulo if (pid == 0) { 161214501Srpaulo /* Restore old sigmask in the child. */ 162214501Srpaulo if (sigprocmask(SIG_SETMASK, &oldmask, NULL) == -1) 163214501Srpaulo err(1, "sigprocmask"); 164214501Srpaulo } 165214501Srpaulo /* Now that we are the child, write out the pid. */ 166214501Srpaulo pidfile_write(pfh); 167214501Srpaulo 168214501Srpaulo if (user != NULL) 169214501Srpaulo restrict_process(user); 170214501Srpaulo 171214501Srpaulo execvp(argv[0], argv); 172214501Srpaulo 173214501Srpaulo /* 174214501Srpaulo * execvp() failed -- report the error. The child is 175214501Srpaulo * now running, so the exit status doesn't matter. 176214501Srpaulo */ 177214501Srpaulo err(1, "%s", argv[0]); 178214501Srpaulo } 179214501Srpaulo setproctitle("%s[%d]", argv[0], pid); 180214501Srpaulo if (wait_child(pid, &mask) == 0 && restart) { 181214501Srpaulo sleep(1); 182214501Srpaulo goto restart; 183214501Srpaulo } 184214501Srpaulo pidfile_remove(pfh); 185214501Srpaulo exit(0); /* Exit status does not matter. */ 186214501Srpaulo} 187214501Srpaulo 188214501Srpaulostatic void 189214501Srpaulodummy_sighandler(int sig __unused) 190214501Srpaulo{ 191214501Srpaulo /* Nothing to do. */ 192214501Srpaulo} 193214501Srpaulo 194214501Srpaulostatic void 195214501Srpaulorestrict_process(const char *user) 196214501Srpaulo{ 197214501Srpaulo struct passwd *pw = NULL; 198214501Srpaulo 199214501Srpaulo pw = getpwnam(user); 200214501Srpaulo if (pw == NULL) 201214501Srpaulo errx(1, "unknown user: %s", user); 202214501Srpaulo 203214501Srpaulo if (setusercontext(NULL, pw, pw->pw_uid, LOGIN_SETALL) != 0) 204214501Srpaulo errx(1, "failed to set user environment"); 205214501Srpaulo} 206214501Srpaulo 207214501Srpaulostatic int 208214501Srpaulowait_child(pid_t pid, sigset_t *mask) 209214501Srpaulo{ 210214501Srpaulo int terminate, signo; 211214501Srpaulo 212214501Srpaulo terminate = 0; 213214501Srpaulo for (;;) { 214214501Srpaulo if (sigwait(mask, &signo) == -1) { 215214501Srpaulo warn("sigwaitinfo"); 216214501Srpaulo return (-1); 217214501Srpaulo } 218214501Srpaulo switch (signo) { 219214501Srpaulo case SIGCHLD: 220214501Srpaulo if (waitpid(pid, NULL, WNOHANG) == -1) { 221214501Srpaulo warn("waitpid"); 222214501Srpaulo return (-1); 223214501Srpaulo } 224214501Srpaulo return (terminate); 225214501Srpaulo case SIGTERM: 226214501Srpaulo terminate = 1; 227214501Srpaulo if (kill(pid, signo) == -1) { 228214501Srpaulo warn("kill"); 229214501Srpaulo return (-1); 230214501Srpaulo } 231214501Srpaulo continue; 232214501Srpaulo default: 233214501Srpaulo warnx("sigwaitinfo: invalid signal: %d", signo); 234214501Srpaulo return (-1); 235214501Srpaulo } 236214501Srpaulo } 237214501Srpaulo} 238214501Srpaulo 239214501Srpaulostatic void 240214501Srpaulousage(void) 241214501Srpaulo{ 242214501Srpaulo (void)fprintf(stderr, 243214501Srpaulo "usage: daemon [-cfr] [-p pidfile] [-u user] command " 244214501Srpaulo "arguments ...\n"); 245214501Srpaulo exit(1); 246214501Srpaulo} 247214501Srpaulo