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