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