daemon.c revision 231910
182547Smike/*- 282547Smike * Copyright (c) 1999 Berkeley Software Design, Inc. All rights reserved. 382547Smike * 482547Smike * Redistribution and use in source and binary forms, with or without 582547Smike * modification, are permitted provided that the following conditions 682547Smike * are met: 782547Smike * 1. Redistributions of source code must retain the above copyright 882547Smike * notice, this list of conditions and the following disclaimer. 982547Smike * 2. Redistributions in binary form must reproduce the above copyright 1082547Smike * notice, this list of conditions and the following disclaimer in the 1182547Smike * documentation and/or other materials provided with the distribution. 1282547Smike * 3. Berkeley Software Design Inc's name may not be used to endorse or 1382547Smike * promote products derived from this software without specific prior 1482547Smike * written permission. 1582547Smike * 1682547Smike * THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN INC ``AS IS'' AND 1782547Smike * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1882547Smike * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1982547Smike * ARE DISCLAIMED. IN NO EVENT SHALL BERKELEY SOFTWARE DESIGN INC BE LIABLE 2082547Smike * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2182547Smike * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2282547Smike * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2382547Smike * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2482547Smike * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2582547Smike * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2682547Smike * SUCH DAMAGE. 2782547Smike * 2882547Smike * From BSDI: daemon.c,v 1.2 1996/08/15 01:11:09 jch Exp 2982547Smike */ 3082547Smike 31117280Scharnier#include <sys/cdefs.h> 32117280Scharnier__FBSDID("$FreeBSD: head/usr.sbin/daemon/daemon.c 231910 2012-02-19 10:23:51Z trociny $"); 33117280Scharnier 34149424Spjd#include <sys/param.h> 35231909Strociny#include <sys/wait.h> 3682547Smike 3782547Smike#include <err.h> 38129983Sphk#include <errno.h> 39149424Spjd#include <libutil.h> 40167700Strhodes#include <login_cap.h> 41231910Strociny#include <pwd.h> 42231910Strociny#include <signal.h> 4382547Smike#include <stdio.h> 4482547Smike#include <stdlib.h> 4582547Smike#include <unistd.h> 4682547Smike 47231910Strocinystatic void dummy_sighandler(int); 48167700Strhodesstatic void restrict_process(const char *); 49231910Strocinystatic void wait_child(pid_t pid, sigset_t *mask); 5082547Smikestatic void usage(void); 5182547Smike 5282547Smikeint 5382547Smikemain(int argc, char *argv[]) 5482547Smike{ 55167357Strhodes struct pidfh *pfh = NULL; 56231910Strociny sigset_t mask, oldmask; 57231909Strociny int ch, nochdir, noclose; 58167700Strhodes const char *pidfile, *user; 59231909Strociny pid_t otherpid, pid; 6082547Smike 6182547Smike nochdir = noclose = 1; 62167700Strhodes pidfile = user = NULL; 63168868Speter while ((ch = getopt(argc, argv, "-cfp:u:")) != -1) { 6482547Smike switch (ch) { 6582547Smike case 'c': 6682547Smike nochdir = 0; 6782547Smike break; 6882547Smike case 'f': 6982547Smike noclose = 0; 7082547Smike break; 71167700Strhodes case 'p': 72167700Strhodes pidfile = optarg; 73167700Strhodes break; 74167356Strhodes case 'u': 75167356Strhodes user = optarg; 76167356Strhodes break; 7782547Smike default: 7882547Smike usage(); 7982547Smike } 8082547Smike } 8182547Smike argc -= optind; 8282547Smike argv += optind; 8382547Smike 8482547Smike if (argc == 0) 8582547Smike usage(); 86167356Strhodes 87231909Strociny pfh = NULL; 88129983Sphk /* 89129983Sphk * Try to open the pidfile before calling daemon(3), 90129983Sphk * to be able to report the error intelligently 91129983Sphk */ 92231909Strociny if (pidfile != NULL) { 93149424Spjd pfh = pidfile_open(pidfile, 0600, &otherpid); 94149424Spjd if (pfh == NULL) { 95149424Spjd if (errno == EEXIST) { 96149424Spjd errx(3, "process already running, pid: %d", 97149424Spjd otherpid); 98149424Spjd } 99129983Sphk err(2, "pidfile ``%s''", pidfile); 100149424Spjd } 101129983Sphk } 102129983Sphk 10382547Smike if (daemon(nochdir, noclose) == -1) 10482547Smike err(1, NULL); 105129983Sphk 106231910Strociny /* 107231910Strociny * If the pidfile option is specified the daemon executes the 108231910Strociny * command in a forked process and wait on child exit to 109231910Strociny * remove the pidfile. Normally we don't want the monitoring 110231910Strociny * daemon to be terminated leaving the running process and the 111231910Strociny * stale pidfile, so we catch SIGTERM and pass it to the 112231910Strociny * children expecting to get SIGCHLD eventually. 113231910Strociny */ 114231910Strociny pid = -1; 115231909Strociny if (pidfile != NULL) { 116231909Strociny /* 117231910Strociny * Restore default action for SIGTERM in case the 118231910Strociny * parent process decided to ignore it. 119231910Strociny */ 120231910Strociny if (signal(SIGTERM, SIG_DFL) == SIG_ERR) 121231910Strociny err(1, "signal"); 122231910Strociny /* 123231910Strociny * Because SIGCHLD is ignored by default, setup dummy handler 124231910Strociny * for it, so we can mask it. 125231910Strociny */ 126231910Strociny if (signal(SIGCHLD, dummy_sighandler) == SIG_ERR) 127231910Strociny err(1, "signal"); 128231910Strociny /* 129231910Strociny * Block interesting signals. 130231910Strociny */ 131231910Strociny sigemptyset(&mask); 132231910Strociny sigaddset(&mask, SIGTERM); 133231910Strociny sigaddset(&mask, SIGCHLD); 134231910Strociny if (sigprocmask(SIG_SETMASK, &mask, &oldmask) == -1) 135231910Strociny err(1, "sigprocmask"); 136231910Strociny /* 137231909Strociny * Spawn a child to exec the command, so in the parent 138231909Strociny * we could wait for it to exit and remove pidfile. 139231909Strociny */ 140231909Strociny pid = fork(); 141231909Strociny if (pid == -1) { 142231909Strociny pidfile_remove(pfh); 143231909Strociny err(1, "fork"); 144231909Strociny } 145231909Strociny } 146231910Strociny if (pid <= 0) { 147231910Strociny if (pid == 0) { 148231910Strociny /* Restore old sigmask in the child. */ 149231910Strociny if (sigprocmask(SIG_SETMASK, &oldmask, NULL) == -1) 150231910Strociny err(1, "sigprocmask"); 151231910Strociny } 152231909Strociny /* Now that we are the child, write out the pid. */ 153149424Spjd pidfile_write(pfh); 154129983Sphk 155231909Strociny if (user != NULL) 156231909Strociny restrict_process(user); 15782547Smike 158231909Strociny execvp(argv[0], argv); 159129983Sphk 160231909Strociny /* 161231909Strociny * execvp() failed -- report the error. The child is 162231909Strociny * now running, so the exit status doesn't matter. 163231909Strociny */ 164231909Strociny err(1, "%s", argv[0]); 165231909Strociny } 166231909Strociny setproctitle("%s[%d]", argv[0], pid); 167231910Strociny wait_child(pid, &mask); 168231909Strociny pidfile_remove(pfh); 169231909Strociny exit(0); /* Exit status does not matter. */ 17082547Smike} 17182547Smike 17282547Smikestatic void 173231910Strocinydummy_sighandler(int sig __unused) 174231910Strociny{ 175231910Strociny /* Nothing to do. */ 176231910Strociny} 177231910Strociny 178231910Strocinystatic void 179167700Strhodesrestrict_process(const char *user) 180167356Strhodes{ 181167356Strhodes struct passwd *pw = NULL; 182167356Strhodes 183167700Strhodes pw = getpwnam(user); 184167700Strhodes if (pw == NULL) 185167700Strhodes errx(1, "unknown user: %s", user); 186167356Strhodes 187167700Strhodes if (setusercontext(NULL, pw, pw->pw_uid, LOGIN_SETALL) != 0) 188167700Strhodes errx(1, "failed to set user environment"); 189167356Strhodes} 190167356Strhodes 191167356Strhodesstatic void 192231910Strocinywait_child(pid_t pid, sigset_t *mask) 193231909Strociny{ 194231910Strociny int signo; 195231909Strociny 196231910Strociny for (;;) { 197231910Strociny if (sigwait(mask, &signo) == -1) { 198231910Strociny warn("sigwaitinfo"); 199231910Strociny return; 200231909Strociny } 201231910Strociny switch (signo) { 202231910Strociny case SIGCHLD: 203231910Strociny return; 204231910Strociny case SIGTERM: 205231910Strociny if (kill(pid, signo) == -1) { 206231910Strociny warn("kill"); 207231910Strociny return; 208231910Strociny } 209231910Strociny continue; 210231910Strociny default: 211231910Strociny warnx("sigwaitinfo: invalid signal: %d", signo); 212231910Strociny return; 213231910Strociny } 214231909Strociny } 215231909Strociny} 216231909Strociny 217231909Strocinystatic void 21882547Smikeusage(void) 21982547Smike{ 220129983Sphk (void)fprintf(stderr, 221167700Strhodes "usage: daemon [-cf] [-p pidfile] [-u user] command " 222167356Strhodes "arguments ...\n"); 22382547Smike exit(1); 22482547Smike} 225