daemon.c revision 231909
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 231909 2012-02-19 10:20:37Z trociny $"); 33117280Scharnier 34149424Spjd#include <sys/param.h> 35231909Strociny#include <sys/wait.h> 3682547Smike 3782547Smike#include <err.h> 38129983Sphk#include <errno.h> 39167356Strhodes#include <pwd.h> 40149424Spjd#include <libutil.h> 41167700Strhodes#include <login_cap.h> 4282547Smike#include <stdio.h> 4382547Smike#include <stdlib.h> 4482547Smike#include <unistd.h> 4582547Smike 46167700Strhodesstatic void restrict_process(const char *); 47231909Strocinystatic void wait_child(pid_t pid); 4882547Smikestatic void usage(void); 4982547Smike 5082547Smikeint 5182547Smikemain(int argc, char *argv[]) 5282547Smike{ 53167357Strhodes struct pidfh *pfh = NULL; 54231909Strociny int ch, nochdir, noclose; 55167700Strhodes const char *pidfile, *user; 56231909Strociny pid_t otherpid, pid; 5782547Smike 5882547Smike nochdir = noclose = 1; 59167700Strhodes pidfile = user = NULL; 60168868Speter while ((ch = getopt(argc, argv, "-cfp:u:")) != -1) { 6182547Smike switch (ch) { 6282547Smike case 'c': 6382547Smike nochdir = 0; 6482547Smike break; 6582547Smike case 'f': 6682547Smike noclose = 0; 6782547Smike break; 68167700Strhodes case 'p': 69167700Strhodes pidfile = optarg; 70167700Strhodes break; 71167356Strhodes case 'u': 72167356Strhodes user = optarg; 73167356Strhodes break; 7482547Smike default: 7582547Smike usage(); 7682547Smike } 7782547Smike } 7882547Smike argc -= optind; 7982547Smike argv += optind; 8082547Smike 8182547Smike if (argc == 0) 8282547Smike usage(); 83167356Strhodes 84231909Strociny pfh = NULL; 85129983Sphk /* 86129983Sphk * Try to open the pidfile before calling daemon(3), 87129983Sphk * to be able to report the error intelligently 88129983Sphk */ 89231909Strociny if (pidfile != NULL) { 90149424Spjd pfh = pidfile_open(pidfile, 0600, &otherpid); 91149424Spjd if (pfh == NULL) { 92149424Spjd if (errno == EEXIST) { 93149424Spjd errx(3, "process already running, pid: %d", 94149424Spjd otherpid); 95149424Spjd } 96129983Sphk err(2, "pidfile ``%s''", pidfile); 97149424Spjd } 98129983Sphk } 99129983Sphk 10082547Smike if (daemon(nochdir, noclose) == -1) 10182547Smike err(1, NULL); 102129983Sphk 103231909Strociny pid = 0; 104231909Strociny if (pidfile != NULL) { 105231909Strociny /* 106231909Strociny * Spawn a child to exec the command, so in the parent 107231909Strociny * we could wait for it to exit and remove pidfile. 108231909Strociny */ 109231909Strociny pid = fork(); 110231909Strociny if (pid == -1) { 111231909Strociny pidfile_remove(pfh); 112231909Strociny err(1, "fork"); 113231909Strociny } 114231909Strociny } 115231909Strociny if (pid == 0) { 116231909Strociny /* Now that we are the child, write out the pid. */ 117149424Spjd pidfile_write(pfh); 118129983Sphk 119231909Strociny if (user != NULL) 120231909Strociny restrict_process(user); 12182547Smike 122231909Strociny execvp(argv[0], argv); 123129983Sphk 124231909Strociny /* 125231909Strociny * execvp() failed -- report the error. The child is 126231909Strociny * now running, so the exit status doesn't matter. 127231909Strociny */ 128231909Strociny err(1, "%s", argv[0]); 129231909Strociny } 130231909Strociny setproctitle("%s[%d]", argv[0], pid); 131231909Strociny wait_child(pid); 132231909Strociny pidfile_remove(pfh); 133231909Strociny exit(0); /* Exit status does not matter. */ 13482547Smike} 13582547Smike 13682547Smikestatic void 137167700Strhodesrestrict_process(const char *user) 138167356Strhodes{ 139167356Strhodes struct passwd *pw = NULL; 140167356Strhodes 141167700Strhodes pw = getpwnam(user); 142167700Strhodes if (pw == NULL) 143167700Strhodes errx(1, "unknown user: %s", user); 144167356Strhodes 145167700Strhodes if (setusercontext(NULL, pw, pw->pw_uid, LOGIN_SETALL) != 0) 146167700Strhodes errx(1, "failed to set user environment"); 147167356Strhodes} 148167356Strhodes 149167356Strhodesstatic void 150231909Strocinywait_child(pid_t pid) 151231909Strociny{ 152231909Strociny int status; 153231909Strociny 154231909Strociny while (waitpid(pid, &status, 0) == -1) { 155231909Strociny if (errno != EINTR) { 156231909Strociny warn("waitpid"); 157231909Strociny break; 158231909Strociny } 159231909Strociny } 160231909Strociny} 161231909Strociny 162231909Strocinystatic void 16382547Smikeusage(void) 16482547Smike{ 165129983Sphk (void)fprintf(stderr, 166167700Strhodes "usage: daemon [-cf] [-p pidfile] [-u user] command " 167167356Strhodes "arguments ...\n"); 16882547Smike exit(1); 16982547Smike} 170