init.c revision 159402
1/*-
2 * Copyright (c) 1991, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Donn Seeley at Berkeley Software Design, Inc.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 4. Neither the name of the University nor the names of its contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33#ifndef lint
34static const char copyright[] =
35"@(#) Copyright (c) 1991, 1993\n\
36	The Regents of the University of California.  All rights reserved.\n";
37#endif /* not lint */
38
39#ifndef lint
40#if 0
41static char sccsid[] = "@(#)init.c	8.1 (Berkeley) 7/15/93";
42#endif
43static const char rcsid[] =
44  "$FreeBSD: head/sbin/init/init.c 159402 2006-06-08 14:04:36Z kib $";
45#endif /* not lint */
46
47#include <sys/param.h>
48#include <sys/ioctl.h>
49#include <sys/mount.h>
50#include <sys/sysctl.h>
51#include <sys/wait.h>
52#include <sys/stat.h>
53#include <sys/uio.h>
54
55#include <db.h>
56#include <errno.h>
57#include <fcntl.h>
58#include <libutil.h>
59#include <paths.h>
60#include <signal.h>
61#include <stdio.h>
62#include <stdlib.h>
63#include <string.h>
64#include <syslog.h>
65#include <time.h>
66#include <ttyent.h>
67#include <unistd.h>
68#include <sys/reboot.h>
69#include <err.h>
70
71#include <stdarg.h>
72
73#ifdef SECURE
74#include <pwd.h>
75#endif
76
77#ifdef LOGIN_CAP
78#include <login_cap.h>
79#endif
80
81#include "pathnames.h"
82
83/*
84 * Sleep times; used to prevent thrashing.
85 */
86#define	GETTY_SPACING		 5	/* N secs minimum getty spacing */
87#define	GETTY_SLEEP		30	/* sleep N secs after spacing problem */
88#define GETTY_NSPACE             3      /* max. spacing count to bring reaction */
89#define	WINDOW_WAIT		 3	/* wait N secs after starting window */
90#define	STALL_TIMEOUT		30	/* wait N secs after warning */
91#define	DEATH_WATCH		10	/* wait N secs for procs to die */
92#define DEATH_SCRIPT		120	/* wait for 2min for /etc/rc.shutdown */
93#define RESOURCE_RC		"daemon"
94#define RESOURCE_WINDOW 	"default"
95#define RESOURCE_GETTY		"default"
96
97void handle(sig_t, ...);
98void delset(sigset_t *, ...);
99
100void stall(const char *, ...) __printflike(1, 2);
101void warning(const char *, ...) __printflike(1, 2);
102void emergency(const char *, ...) __printflike(1, 2);
103void disaster(int);
104void badsys(int);
105int  runshutdown(void);
106static char *strk(char *);
107
108/*
109 * We really need a recursive typedef...
110 * The following at least guarantees that the return type of (*state_t)()
111 * is sufficiently wide to hold a function pointer.
112 */
113typedef long (*state_func_t)(void);
114typedef state_func_t (*state_t)(void);
115
116state_func_t single_user(void);
117state_func_t runcom(void);
118state_func_t read_ttys(void);
119state_func_t multi_user(void);
120state_func_t clean_ttys(void);
121state_func_t catatonia(void);
122state_func_t death(void);
123
124enum { AUTOBOOT, FASTBOOT } runcom_mode = AUTOBOOT;
125#define FALSE	0
126#define TRUE	1
127
128int Reboot = FALSE;
129int howto = RB_AUTOBOOT;
130
131int devfs;
132
133void transition(state_t);
134state_t requested_transition = runcom;
135
136void setctty(const char *);
137
138typedef struct init_session {
139	int	se_index;		/* index of entry in ttys file */
140	pid_t	se_process;		/* controlling process */
141	time_t	se_started;		/* used to avoid thrashing */
142	int	se_flags;		/* status of session */
143#define	SE_SHUTDOWN	0x1		/* session won't be restarted */
144#define	SE_PRESENT	0x2		/* session is in /etc/ttys */
145	int     se_nspace;              /* spacing count */
146	char	*se_device;		/* filename of port */
147	char	*se_getty;		/* what to run on that port */
148	char    *se_getty_argv_space;   /* pre-parsed argument array space */
149	char	**se_getty_argv;	/* pre-parsed argument array */
150	char	*se_window;		/* window system (started only once) */
151	char    *se_window_argv_space;  /* pre-parsed argument array space */
152	char	**se_window_argv;	/* pre-parsed argument array */
153	char    *se_type;               /* default terminal type */
154	struct	init_session *se_prev;
155	struct	init_session *se_next;
156} session_t;
157
158void free_session(session_t *);
159session_t *new_session(session_t *, int, struct ttyent *);
160session_t *sessions;
161
162char **construct_argv(char *);
163void start_window_system(session_t *);
164void collect_child(pid_t);
165pid_t start_getty(session_t *);
166void transition_handler(int);
167void alrm_handler(int);
168void setsecuritylevel(int);
169int getsecuritylevel(void);
170int setupargv(session_t *, struct ttyent *);
171#ifdef LOGIN_CAP
172void setprocresources(const char *);
173#endif
174int clang;
175
176void clear_session_logs(session_t *);
177
178int start_session_db(void);
179void add_session(session_t *);
180void del_session(session_t *);
181session_t *find_session(pid_t);
182DB *session_db;
183
184/*
185 * The mother of all processes.
186 */
187int
188main(int argc, char *argv[])
189{
190	int c;
191	struct sigaction sa;
192	sigset_t mask;
193
194
195	/* Dispose of random users. */
196	if (getuid() != 0)
197		errx(1, "%s", strerror(EPERM));
198
199	/* System V users like to reexec init. */
200	if (getpid() != 1) {
201#ifdef COMPAT_SYSV_INIT
202		/* So give them what they want */
203		if (argc > 1) {
204			if (strlen(argv[1]) == 1) {
205				char runlevel = *argv[1];
206				int sig;
207
208				switch (runlevel) {
209					case '0': /* halt + poweroff */
210						sig = SIGUSR2;
211						break;
212					case '1': /* single-user */
213						sig = SIGTERM;
214						break;
215					case '6': /* reboot */
216						sig = SIGINT;
217						break;
218					case 'c': /* block further logins */
219						sig = SIGTSTP;
220						break;
221					case 'q': /* rescan /etc/ttys */
222						sig = SIGHUP;
223						break;
224					default:
225						goto invalid;
226				}
227				kill(1, sig);
228				_exit(0);
229			} else
230invalid:
231				errx(1, "invalid run-level ``%s''", argv[1]);
232		} else
233#endif
234			errx(1, "already running");
235	}
236	/*
237	 * Note that this does NOT open a file...
238	 * Does 'init' deserve its own facility number?
239	 */
240	openlog("init", LOG_CONS|LOG_ODELAY, LOG_AUTH);
241
242	/*
243	 * Create an initial session.
244	 */
245	if (setsid() < 0)
246		warning("initial setsid() failed: %m");
247
248	/*
249	 * Establish an initial user so that programs running
250	 * single user do not freak out and die (like passwd).
251	 */
252	if (setlogin("root") < 0)
253		warning("setlogin() failed: %m");
254
255	/*
256	 * This code assumes that we always get arguments through flags,
257	 * never through bits set in some random machine register.
258	 */
259	while ((c = getopt(argc, argv, "dsf")) != -1)
260		switch (c) {
261		case 'd':
262			devfs = 1;
263			break;
264		case 's':
265			requested_transition = single_user;
266			break;
267		case 'f':
268			runcom_mode = FASTBOOT;
269			break;
270		default:
271			warning("unrecognized flag '-%c'", c);
272			break;
273		}
274
275	if (optind != argc)
276		warning("ignoring excess arguments");
277
278	if (devfs) {
279		struct iovec iov[4];
280		char *s;
281		int i;
282
283		char _fstype[]	= "fstype";
284		char _devfs[]	= "devfs";
285		char _fspath[]	= "fspath";
286		char _path_dev[]= _PATH_DEV;
287
288		iov[0].iov_base = _fstype;
289		iov[0].iov_len = sizeof(_fstype);
290		iov[1].iov_base = _devfs;
291		iov[1].iov_len = sizeof(_devfs);
292		iov[2].iov_base = _fspath;
293		iov[2].iov_len = sizeof(_fspath);
294		/*
295		 * Try to avoid the trailing slash in _PATH_DEV.
296		 * Be *very* defensive.
297		 */
298		s = strdup(_PATH_DEV);
299		if (s != NULL) {
300			i = strlen(s);
301			if (i > 0 && s[i - 1] == '/')
302				s[i - 1] = '\0';
303			iov[3].iov_base = s;
304			iov[3].iov_len = strlen(s) + 1;
305		} else {
306			iov[3].iov_base = _path_dev;
307			iov[3].iov_len = sizeof(_path_dev);
308		}
309		nmount(iov, 4, 0);
310		if (s != NULL)
311			free(s);
312	}
313
314	/*
315	 * We catch or block signals rather than ignore them,
316	 * so that they get reset on exec.
317	 */
318	handle(badsys, SIGSYS, 0);
319	handle(disaster, SIGABRT, SIGFPE, SIGILL, SIGSEGV,
320	       SIGBUS, SIGXCPU, SIGXFSZ, 0);
321	handle(transition_handler, SIGHUP, SIGINT, SIGTERM, SIGTSTP,
322		SIGUSR1, SIGUSR2, 0);
323	handle(alrm_handler, SIGALRM, 0);
324	sigfillset(&mask);
325	delset(&mask, SIGABRT, SIGFPE, SIGILL, SIGSEGV, SIGBUS, SIGSYS,
326		SIGXCPU, SIGXFSZ, SIGHUP, SIGINT, SIGTERM, SIGTSTP, SIGALRM,
327		SIGUSR1, SIGUSR2, 0);
328	sigprocmask(SIG_SETMASK, &mask, (sigset_t *) 0);
329	sigemptyset(&sa.sa_mask);
330	sa.sa_flags = 0;
331	sa.sa_handler = SIG_IGN;
332	(void) sigaction(SIGTTIN, &sa, (struct sigaction *)0);
333	(void) sigaction(SIGTTOU, &sa, (struct sigaction *)0);
334
335	/*
336	 * Paranoia.
337	 */
338	close(0);
339	close(1);
340	close(2);
341
342	/*
343	 * Start the state machine.
344	 */
345	transition(requested_transition);
346
347	/*
348	 * Should never reach here.
349	 */
350	return 1;
351}
352
353/*
354 * Associate a function with a signal handler.
355 */
356void
357handle(sig_t handler, ...)
358{
359	int sig;
360	struct sigaction sa;
361	sigset_t mask_everything;
362	va_list ap;
363	va_start(ap, handler);
364
365	sa.sa_handler = handler;
366	sigfillset(&mask_everything);
367
368	while ((sig = va_arg(ap, int)) != 0) {
369		sa.sa_mask = mask_everything;
370		/* XXX SA_RESTART? */
371		sa.sa_flags = sig == SIGCHLD ? SA_NOCLDSTOP : 0;
372		sigaction(sig, &sa, (struct sigaction *) 0);
373	}
374	va_end(ap);
375}
376
377/*
378 * Delete a set of signals from a mask.
379 */
380void
381delset(sigset_t *maskp, ...)
382{
383	int sig;
384	va_list ap;
385	va_start(ap, maskp);
386
387	while ((sig = va_arg(ap, int)) != 0)
388		sigdelset(maskp, sig);
389	va_end(ap);
390}
391
392/*
393 * Log a message and sleep for a while (to give someone an opportunity
394 * to read it and to save log or hardcopy output if the problem is chronic).
395 * NB: should send a message to the session logger to avoid blocking.
396 */
397void
398stall(const char *message, ...)
399{
400	va_list ap;
401	va_start(ap, message);
402
403	vsyslog(LOG_ALERT, message, ap);
404	va_end(ap);
405	sleep(STALL_TIMEOUT);
406}
407
408/*
409 * Like stall(), but doesn't sleep.
410 * If cpp had variadic macros, the two functions could be #defines for another.
411 * NB: should send a message to the session logger to avoid blocking.
412 */
413void
414warning(const char *message, ...)
415{
416	va_list ap;
417	va_start(ap, message);
418
419	vsyslog(LOG_ALERT, message, ap);
420	va_end(ap);
421}
422
423/*
424 * Log an emergency message.
425 * NB: should send a message to the session logger to avoid blocking.
426 */
427void
428emergency(const char *message, ...)
429{
430	va_list ap;
431	va_start(ap, message);
432
433	vsyslog(LOG_EMERG, message, ap);
434	va_end(ap);
435}
436
437/*
438 * Catch a SIGSYS signal.
439 *
440 * These may arise if a system does not support sysctl.
441 * We tolerate up to 25 of these, then throw in the towel.
442 */
443void
444badsys(int sig)
445{
446	static int badcount = 0;
447
448	if (badcount++ < 25)
449		return;
450	disaster(sig);
451}
452
453/*
454 * Catch an unexpected signal.
455 */
456void
457disaster(int sig)
458{
459	emergency("fatal signal: %s",
460		(unsigned)sig < NSIG ? sys_siglist[sig] : "unknown signal");
461
462	sleep(STALL_TIMEOUT);
463	_exit(sig);		/* reboot */
464}
465
466/*
467 * Get the security level of the kernel.
468 */
469int
470getsecuritylevel(void)
471{
472#ifdef KERN_SECURELVL
473	int name[2], curlevel;
474	size_t len;
475
476	name[0] = CTL_KERN;
477	name[1] = KERN_SECURELVL;
478	len = sizeof curlevel;
479	if (sysctl(name, 2, &curlevel, &len, NULL, 0) == -1) {
480		emergency("cannot get kernel security level: %s",
481		    strerror(errno));
482		return (-1);
483	}
484	return (curlevel);
485#else
486	return (-1);
487#endif
488}
489
490/*
491 * Set the security level of the kernel.
492 */
493void
494setsecuritylevel(int newlevel)
495{
496#ifdef KERN_SECURELVL
497	int name[2], curlevel;
498
499	curlevel = getsecuritylevel();
500	if (newlevel == curlevel)
501		return;
502	name[0] = CTL_KERN;
503	name[1] = KERN_SECURELVL;
504	if (sysctl(name, 2, NULL, NULL, &newlevel, sizeof newlevel) == -1) {
505		emergency(
506		    "cannot change kernel security level from %d to %d: %s",
507		    curlevel, newlevel, strerror(errno));
508		return;
509	}
510#ifdef SECURE
511	warning("kernel security level changed from %d to %d",
512	    curlevel, newlevel);
513#endif
514#endif
515}
516
517/*
518 * Change states in the finite state machine.
519 * The initial state is passed as an argument.
520 */
521void
522transition(state_t s)
523{
524	for (;;)
525		s = (state_t) (*s)();
526}
527
528/*
529 * Close out the accounting files for a login session.
530 * NB: should send a message to the session logger to avoid blocking.
531 */
532void
533clear_session_logs(session_t *sp)
534{
535	char *line = sp->se_device + sizeof(_PATH_DEV) - 1;
536
537	if (logout(line))
538		logwtmp(line, "", "");
539}
540
541/*
542 * Start a session and allocate a controlling terminal.
543 * Only called by children of init after forking.
544 */
545void
546setctty(const char *name)
547{
548	int fd;
549
550	(void) revoke(name);
551	if ((fd = open(name, O_RDWR)) == -1) {
552		stall("can't open %s: %m", name);
553		_exit(1);
554	}
555	if (login_tty(fd) == -1) {
556		stall("can't get %s for controlling terminal: %m", name);
557		_exit(1);
558	}
559}
560
561/*
562 * Bring the system up single user.
563 */
564state_func_t
565single_user(void)
566{
567	pid_t pid, wpid;
568	int status;
569	sigset_t mask;
570	const char *shell = _PATH_BSHELL;
571	char *argv[2];
572#ifdef SECURE
573	struct ttyent *typ;
574	struct passwd *pp;
575	static const char banner[] =
576		"Enter root password, or ^D to go multi-user\n";
577	char *clear, *password;
578#endif
579#ifdef DEBUGSHELL
580	char altshell[128];
581#endif
582
583	if (Reboot) {
584		/* Instead of going single user, let's reboot the machine */
585		sync();
586		alarm(2);
587		pause();
588		reboot(howto);
589		_exit(0);
590	}
591
592	if ((pid = fork()) == 0) {
593		/*
594		 * Start the single user session.
595		 */
596		setctty(_PATH_CONSOLE);
597
598#ifdef SECURE
599		/*
600		 * Check the root password.
601		 * We don't care if the console is 'on' by default;
602		 * it's the only tty that can be 'off' and 'secure'.
603		 */
604		typ = getttynam("console");
605		pp = getpwnam("root");
606		if (typ && (typ->ty_status & TTY_SECURE) == 0 &&
607		    pp && *pp->pw_passwd) {
608			write(STDERR_FILENO, banner, sizeof banner - 1);
609			for (;;) {
610				clear = getpass("Password:");
611				if (clear == 0 || *clear == '\0')
612					_exit(0);
613				password = crypt(clear, pp->pw_passwd);
614				bzero(clear, _PASSWORD_LEN);
615				if (strcmp(password, pp->pw_passwd) == 0)
616					break;
617				warning("single-user login failed\n");
618			}
619		}
620		endttyent();
621		endpwent();
622#endif /* SECURE */
623
624#ifdef DEBUGSHELL
625		{
626			char *cp = altshell;
627			int num;
628
629#define	SHREQUEST \
630	"Enter full pathname of shell or RETURN for " _PATH_BSHELL ": "
631			(void)write(STDERR_FILENO,
632			    SHREQUEST, sizeof(SHREQUEST) - 1);
633			while ((num = read(STDIN_FILENO, cp, 1)) != -1 &&
634			    num != 0 && *cp != '\n' && cp < &altshell[127])
635					cp++;
636			*cp = '\0';
637			if (altshell[0] != '\0')
638				shell = altshell;
639		}
640#endif /* DEBUGSHELL */
641
642		/*
643		 * Unblock signals.
644		 * We catch all the interesting ones,
645		 * and those are reset to SIG_DFL on exec.
646		 */
647		sigemptyset(&mask);
648		sigprocmask(SIG_SETMASK, &mask, (sigset_t *) 0);
649
650		/*
651		 * Fire off a shell.
652		 * If the default one doesn't work, try the Bourne shell.
653		 */
654
655		char name[] = "-sh";
656
657		argv[0] = name;
658		argv[1] = 0;
659		execv(shell, argv);
660		emergency("can't exec %s for single user: %m", shell);
661		execv(_PATH_BSHELL, argv);
662		emergency("can't exec %s for single user: %m", _PATH_BSHELL);
663		sleep(STALL_TIMEOUT);
664		_exit(1);
665	}
666
667	if (pid == -1) {
668		/*
669		 * We are seriously hosed.  Do our best.
670		 */
671		emergency("can't fork single-user shell, trying again");
672		while (waitpid(-1, (int *) 0, WNOHANG) > 0)
673			continue;
674		return (state_func_t) single_user;
675	}
676
677	requested_transition = 0;
678	do {
679		if ((wpid = waitpid(-1, &status, WUNTRACED)) != -1)
680			collect_child(wpid);
681		if (wpid == -1) {
682			if (errno == EINTR)
683				continue;
684			warning("wait for single-user shell failed: %m; restarting");
685			return (state_func_t) single_user;
686		}
687		if (wpid == pid && WIFSTOPPED(status)) {
688			warning("init: shell stopped, restarting\n");
689			kill(pid, SIGCONT);
690			wpid = -1;
691		}
692	} while (wpid != pid && !requested_transition);
693
694	if (requested_transition)
695		return (state_func_t) requested_transition;
696
697	if (!WIFEXITED(status)) {
698		if (WTERMSIG(status) == SIGKILL) {
699			/*
700			 *  reboot(8) killed shell?
701			 */
702			warning("single user shell terminated.");
703			sleep(STALL_TIMEOUT);
704			_exit(0);
705		} else {
706			warning("single user shell terminated, restarting");
707			return (state_func_t) single_user;
708		}
709	}
710
711	runcom_mode = FASTBOOT;
712	return (state_func_t) runcom;
713}
714
715/*
716 * Run the system startup script.
717 */
718state_func_t
719runcom(void)
720{
721	pid_t pid, wpid;
722	int status;
723	char *argv[4];
724	struct sigaction sa;
725
726	if ((pid = fork()) == 0) {
727		sigemptyset(&sa.sa_mask);
728		sa.sa_flags = 0;
729		sa.sa_handler = SIG_IGN;
730		(void) sigaction(SIGTSTP, &sa, (struct sigaction *)0);
731		(void) sigaction(SIGHUP, &sa, (struct sigaction *)0);
732
733		setctty(_PATH_CONSOLE);
734
735		char _sh[]	 	= "sh";
736		char _path_runcom[]	= _PATH_RUNCOM;
737		char _autoboot[]	= "autoboot";
738
739		argv[0] = _sh;
740		argv[1] = _path_runcom;
741		argv[2] = runcom_mode == AUTOBOOT ? _autoboot : 0;
742		argv[3] = 0;
743
744		sigprocmask(SIG_SETMASK, &sa.sa_mask, (sigset_t *) 0);
745
746#ifdef LOGIN_CAP
747		setprocresources(RESOURCE_RC);
748#endif
749		execv(_PATH_BSHELL, argv);
750		stall("can't exec %s for %s: %m", _PATH_BSHELL, _PATH_RUNCOM);
751		_exit(1);	/* force single user mode */
752	}
753
754	if (pid == -1) {
755		emergency("can't fork for %s on %s: %m",
756			_PATH_BSHELL, _PATH_RUNCOM);
757		while (waitpid(-1, (int *) 0, WNOHANG) > 0)
758			continue;
759		sleep(STALL_TIMEOUT);
760		return (state_func_t) single_user;
761	}
762
763	/*
764	 * Copied from single_user().  This is a bit paranoid.
765	 */
766	requested_transition = 0;
767	do {
768		if ((wpid = waitpid(-1, &status, WUNTRACED)) != -1)
769			collect_child(wpid);
770		if (wpid == -1) {
771			if (requested_transition == death)
772				return (state_func_t) death;
773			if (errno == EINTR)
774				continue;
775			warning("wait for %s on %s failed: %m; going to single user mode",
776				_PATH_BSHELL, _PATH_RUNCOM);
777			return (state_func_t) single_user;
778		}
779		if (wpid == pid && WIFSTOPPED(status)) {
780			warning("init: %s on %s stopped, restarting\n",
781				_PATH_BSHELL, _PATH_RUNCOM);
782			kill(pid, SIGCONT);
783			wpid = -1;
784		}
785	} while (wpid != pid);
786
787	if (WIFSIGNALED(status) && WTERMSIG(status) == SIGTERM &&
788	    requested_transition == catatonia) {
789		/* /etc/rc executed /sbin/reboot; wait for the end quietly */
790		sigset_t s;
791
792		sigfillset(&s);
793		for (;;)
794			sigsuspend(&s);
795	}
796
797	if (!WIFEXITED(status)) {
798		warning("%s on %s terminated abnormally, going to single user mode",
799			_PATH_BSHELL, _PATH_RUNCOM);
800		return (state_func_t) single_user;
801	}
802
803	if (WEXITSTATUS(status))
804		return (state_func_t) single_user;
805
806	runcom_mode = AUTOBOOT;		/* the default */
807	/* NB: should send a message to the session logger to avoid blocking. */
808	logwtmp("~", "reboot", "");
809	return (state_func_t) read_ttys;
810}
811
812/*
813 * Open the session database.
814 *
815 * NB: We could pass in the size here; is it necessary?
816 */
817int
818start_session_db(void)
819{
820	if (session_db && (*session_db->close)(session_db))
821		emergency("session database close: %s", strerror(errno));
822	if ((session_db = dbopen(NULL, O_RDWR, 0, DB_HASH, NULL)) == 0) {
823		emergency("session database open: %s", strerror(errno));
824		return (1);
825	}
826	return (0);
827
828}
829
830/*
831 * Add a new login session.
832 */
833void
834add_session(session_t *sp)
835{
836	DBT key;
837	DBT data;
838
839	key.data = &sp->se_process;
840	key.size = sizeof sp->se_process;
841	data.data = &sp;
842	data.size = sizeof sp;
843
844	if ((*session_db->put)(session_db, &key, &data, 0))
845		emergency("insert %d: %s", sp->se_process, strerror(errno));
846}
847
848/*
849 * Delete an old login session.
850 */
851void
852del_session(session_t *sp)
853{
854	DBT key;
855
856	key.data = &sp->se_process;
857	key.size = sizeof sp->se_process;
858
859	if ((*session_db->del)(session_db, &key, 0))
860		emergency("delete %d: %s", sp->se_process, strerror(errno));
861}
862
863/*
864 * Look up a login session by pid.
865 */
866session_t *
867find_session(pid_t pid)
868{
869	DBT key;
870	DBT data;
871	session_t *ret;
872
873	key.data = &pid;
874	key.size = sizeof pid;
875	if ((*session_db->get)(session_db, &key, &data, 0) != 0)
876		return 0;
877	bcopy(data.data, (char *)&ret, sizeof(ret));
878	return ret;
879}
880
881/*
882 * Construct an argument vector from a command line.
883 */
884char **
885construct_argv(char *command)
886{
887	int argc = 0;
888	char **argv = (char **) malloc(((strlen(command) + 1) / 2 + 1)
889						* sizeof (char *));
890
891	if ((argv[argc++] = strk(command)) == 0) {
892		free(argv);
893		return (NULL);
894	}
895	while ((argv[argc++] = strk((char *) 0)) != NULL)
896		continue;
897	return argv;
898}
899
900/*
901 * Deallocate a session descriptor.
902 */
903void
904free_session(session_t *sp)
905{
906	free(sp->se_device);
907	if (sp->se_getty) {
908		free(sp->se_getty);
909		free(sp->se_getty_argv_space);
910		free(sp->se_getty_argv);
911	}
912	if (sp->se_window) {
913		free(sp->se_window);
914		free(sp->se_window_argv_space);
915		free(sp->se_window_argv);
916	}
917	if (sp->se_type)
918		free(sp->se_type);
919	free(sp);
920}
921
922/*
923 * Allocate a new session descriptor.
924 * Mark it SE_PRESENT.
925 */
926session_t *
927new_session(session_t *sprev, int session_index, struct ttyent *typ)
928{
929	session_t *sp;
930	int fd;
931
932	if ((typ->ty_status & TTY_ON) == 0 ||
933	    typ->ty_name == 0 ||
934	    typ->ty_getty == 0)
935		return 0;
936
937	sp = (session_t *) calloc(1, sizeof (session_t));
938
939	sp->se_index = session_index;
940	sp->se_flags |= SE_PRESENT;
941
942	sp->se_device = malloc(sizeof(_PATH_DEV) + strlen(typ->ty_name));
943	(void) sprintf(sp->se_device, "%s%s", _PATH_DEV, typ->ty_name);
944
945	/*
946	 * Attempt to open the device, if we get "device not configured"
947	 * then don't add the device to the session list.
948	 */
949	if ((fd = open(sp->se_device, O_RDONLY | O_NONBLOCK, 0)) < 0) {
950		if (errno == ENXIO) {
951			free_session(sp);
952			return (0);
953		}
954	} else
955		close(fd);
956
957	if (setupargv(sp, typ) == 0) {
958		free_session(sp);
959		return (0);
960	}
961
962	sp->se_next = 0;
963	if (sprev == 0) {
964		sessions = sp;
965		sp->se_prev = 0;
966	} else {
967		sprev->se_next = sp;
968		sp->se_prev = sprev;
969	}
970
971	return sp;
972}
973
974/*
975 * Calculate getty and if useful window argv vectors.
976 */
977int
978setupargv(session_t *sp, struct ttyent *typ)
979{
980
981	if (sp->se_getty) {
982		free(sp->se_getty);
983		free(sp->se_getty_argv_space);
984		free(sp->se_getty_argv);
985	}
986	sp->se_getty = malloc(strlen(typ->ty_getty) + strlen(typ->ty_name) + 2);
987	(void) sprintf(sp->se_getty, "%s %s", typ->ty_getty, typ->ty_name);
988	sp->se_getty_argv_space = strdup(sp->se_getty);
989	sp->se_getty_argv = construct_argv(sp->se_getty_argv_space);
990	if (sp->se_getty_argv == 0) {
991		warning("can't parse getty for port %s", sp->se_device);
992		free(sp->se_getty);
993		free(sp->se_getty_argv_space);
994		sp->se_getty = sp->se_getty_argv_space = 0;
995		return (0);
996	}
997	if (sp->se_window) {
998		free(sp->se_window);
999		free(sp->se_window_argv_space);
1000		free(sp->se_window_argv);
1001	}
1002	sp->se_window = sp->se_window_argv_space = 0;
1003	sp->se_window_argv = 0;
1004	if (typ->ty_window) {
1005		sp->se_window = strdup(typ->ty_window);
1006		sp->se_window_argv_space = strdup(sp->se_window);
1007		sp->se_window_argv = construct_argv(sp->se_window_argv_space);
1008		if (sp->se_window_argv == 0) {
1009			warning("can't parse window for port %s",
1010				sp->se_device);
1011			free(sp->se_window_argv_space);
1012			free(sp->se_window);
1013			sp->se_window = sp->se_window_argv_space = 0;
1014			return (0);
1015		}
1016	}
1017	if (sp->se_type)
1018		free(sp->se_type);
1019	sp->se_type = typ->ty_type ? strdup(typ->ty_type) : 0;
1020	return (1);
1021}
1022
1023/*
1024 * Walk the list of ttys and create sessions for each active line.
1025 */
1026state_func_t
1027read_ttys(void)
1028{
1029	int session_index = 0;
1030	session_t *sp, *snext;
1031	struct ttyent *typ;
1032
1033	/*
1034	 * Destroy any previous session state.
1035	 * There shouldn't be any, but just in case...
1036	 */
1037	for (sp = sessions; sp; sp = snext) {
1038		if (sp->se_process)
1039			clear_session_logs(sp);
1040		snext = sp->se_next;
1041		free_session(sp);
1042	}
1043	sessions = 0;
1044	if (start_session_db())
1045		return (state_func_t) single_user;
1046
1047	/*
1048	 * Allocate a session entry for each active port.
1049	 * Note that sp starts at 0.
1050	 */
1051	while ((typ = getttyent()) != NULL)
1052		if ((snext = new_session(sp, ++session_index, typ)) != NULL)
1053			sp = snext;
1054
1055	endttyent();
1056
1057	return (state_func_t) multi_user;
1058}
1059
1060/*
1061 * Start a window system running.
1062 */
1063void
1064start_window_system(session_t *sp)
1065{
1066	pid_t pid;
1067	sigset_t mask;
1068	char term[64], *env[2];
1069	int status;
1070
1071	if ((pid = fork()) == -1) {
1072		emergency("can't fork for window system on port %s: %m",
1073			sp->se_device);
1074		/* hope that getty fails and we can try again */
1075		return;
1076	}
1077	if (pid)
1078	{
1079		waitpid(-1, &status, 0);
1080		return;
1081	}
1082
1083	/* reparent window process to the init to not make a zombie on exit */
1084	if ((pid = fork()) == -1) {
1085		emergency("can't fork for window system on port %s: %m",
1086			sp->se_device);
1087		_exit(1);
1088	}
1089	if (pid)
1090		_exit(0);
1091
1092	sigemptyset(&mask);
1093	sigprocmask(SIG_SETMASK, &mask, (sigset_t *) 0);
1094
1095	if (setsid() < 0)
1096		emergency("setsid failed (window) %m");
1097
1098#ifdef LOGIN_CAP
1099	setprocresources(RESOURCE_WINDOW);
1100#endif
1101	if (sp->se_type) {
1102		/* Don't use malloc after fork */
1103		strcpy(term, "TERM=");
1104		strncat(term, sp->se_type, sizeof(term) - 6);
1105		env[0] = term;
1106		env[1] = 0;
1107	}
1108	else
1109		env[0] = 0;
1110	execve(sp->se_window_argv[0], sp->se_window_argv, env);
1111	stall("can't exec window system '%s' for port %s: %m",
1112		sp->se_window_argv[0], sp->se_device);
1113	_exit(1);
1114}
1115
1116/*
1117 * Start a login session running.
1118 */
1119pid_t
1120start_getty(session_t *sp)
1121{
1122	pid_t pid;
1123	sigset_t mask;
1124	time_t current_time = time((time_t *) 0);
1125	int too_quick = 0;
1126	char term[64], *env[2];
1127
1128	if (current_time >= sp->se_started &&
1129	    current_time - sp->se_started < GETTY_SPACING) {
1130		if (++sp->se_nspace > GETTY_NSPACE) {
1131			sp->se_nspace = 0;
1132			too_quick = 1;
1133		}
1134	} else
1135		sp->se_nspace = 0;
1136
1137	/*
1138	 * fork(), not vfork() -- we can't afford to block.
1139	 */
1140	if ((pid = fork()) == -1) {
1141		emergency("can't fork for getty on port %s: %m", sp->se_device);
1142		return -1;
1143	}
1144
1145	if (pid)
1146		return pid;
1147
1148	if (too_quick) {
1149		warning("getty repeating too quickly on port %s, sleeping %d secs",
1150			sp->se_device, GETTY_SLEEP);
1151		sleep((unsigned) GETTY_SLEEP);
1152	}
1153
1154	if (sp->se_window) {
1155		start_window_system(sp);
1156		sleep(WINDOW_WAIT);
1157	}
1158
1159	sigemptyset(&mask);
1160	sigprocmask(SIG_SETMASK, &mask, (sigset_t *) 0);
1161
1162#ifdef LOGIN_CAP
1163	setprocresources(RESOURCE_GETTY);
1164#endif
1165	if (sp->se_type) {
1166		/* Don't use malloc after fork */
1167		strcpy(term, "TERM=");
1168		strncat(term, sp->se_type, sizeof(term) - 6);
1169		env[0] = term;
1170		env[1] = 0;
1171	}
1172	else
1173		env[0] = 0;
1174	execve(sp->se_getty_argv[0], sp->se_getty_argv, env);
1175	stall("can't exec getty '%s' for port %s: %m",
1176		sp->se_getty_argv[0], sp->se_device);
1177	_exit(1);
1178}
1179
1180/*
1181 * Collect exit status for a child.
1182 * If an exiting login, start a new login running.
1183 */
1184void
1185collect_child(pid_t pid)
1186{
1187	session_t *sp, *sprev, *snext;
1188
1189	if (! sessions)
1190		return;
1191
1192	if (! (sp = find_session(pid)))
1193		return;
1194
1195	clear_session_logs(sp);
1196	del_session(sp);
1197	sp->se_process = 0;
1198
1199	if (sp->se_flags & SE_SHUTDOWN) {
1200		if ((sprev = sp->se_prev) != NULL)
1201			sprev->se_next = sp->se_next;
1202		else
1203			sessions = sp->se_next;
1204		if ((snext = sp->se_next) != NULL)
1205			snext->se_prev = sp->se_prev;
1206		free_session(sp);
1207		return;
1208	}
1209
1210	if ((pid = start_getty(sp)) == -1) {
1211		/* serious trouble */
1212		requested_transition = clean_ttys;
1213		return;
1214	}
1215
1216	sp->se_process = pid;
1217	sp->se_started = time((time_t *) 0);
1218	add_session(sp);
1219}
1220
1221/*
1222 * Catch a signal and request a state transition.
1223 */
1224void
1225transition_handler(int sig)
1226{
1227
1228	switch (sig) {
1229	case SIGHUP:
1230		requested_transition = clean_ttys;
1231		break;
1232	case SIGUSR2:
1233		howto = RB_POWEROFF;
1234	case SIGUSR1:
1235		howto |= RB_HALT;
1236	case SIGINT:
1237		Reboot = TRUE;
1238	case SIGTERM:
1239		requested_transition = death;
1240		break;
1241	case SIGTSTP:
1242		requested_transition = catatonia;
1243		break;
1244	default:
1245		requested_transition = 0;
1246		break;
1247	}
1248}
1249
1250/*
1251 * Take the system multiuser.
1252 */
1253state_func_t
1254multi_user(void)
1255{
1256	pid_t pid;
1257	session_t *sp;
1258
1259	requested_transition = 0;
1260
1261	/*
1262	 * If the administrator has not set the security level to -1
1263	 * to indicate that the kernel should not run multiuser in secure
1264	 * mode, and the run script has not set a higher level of security
1265	 * than level 1, then put the kernel into secure mode.
1266	 */
1267	if (getsecuritylevel() == 0)
1268		setsecuritylevel(1);
1269
1270	for (sp = sessions; sp; sp = sp->se_next) {
1271		if (sp->se_process)
1272			continue;
1273		if ((pid = start_getty(sp)) == -1) {
1274			/* serious trouble */
1275			requested_transition = clean_ttys;
1276			break;
1277		}
1278		sp->se_process = pid;
1279		sp->se_started = time((time_t *) 0);
1280		add_session(sp);
1281	}
1282
1283	while (!requested_transition)
1284		if ((pid = waitpid(-1, (int *) 0, 0)) != -1)
1285			collect_child(pid);
1286
1287	return (state_func_t) requested_transition;
1288}
1289
1290/*
1291 * This is an (n*2)+(n^2) algorithm.  We hope it isn't run often...
1292 */
1293state_func_t
1294clean_ttys(void)
1295{
1296	session_t *sp, *sprev;
1297	struct ttyent *typ;
1298	int session_index = 0;
1299	int devlen;
1300	char *old_getty, *old_window, *old_type;
1301
1302	/*
1303	 * mark all sessions for death, (!SE_PRESENT)
1304	 * as we find or create new ones they'll be marked as keepers,
1305	 * we'll later nuke all the ones not found in /etc/ttys
1306	 */
1307	for (sp = sessions; sp != NULL; sp = sp->se_next)
1308		sp->se_flags &= ~SE_PRESENT;
1309
1310	devlen = sizeof(_PATH_DEV) - 1;
1311	while ((typ = getttyent()) != NULL) {
1312		++session_index;
1313
1314		for (sprev = 0, sp = sessions; sp; sprev = sp, sp = sp->se_next)
1315			if (strcmp(typ->ty_name, sp->se_device + devlen) == 0)
1316				break;
1317
1318		if (sp) {
1319			/* we want this one to live */
1320			sp->se_flags |= SE_PRESENT;
1321			if (sp->se_index != session_index) {
1322				warning("port %s changed utmp index from %d to %d",
1323				       sp->se_device, sp->se_index,
1324				       session_index);
1325				sp->se_index = session_index;
1326			}
1327			if ((typ->ty_status & TTY_ON) == 0 ||
1328			    typ->ty_getty == 0) {
1329				sp->se_flags |= SE_SHUTDOWN;
1330				kill(sp->se_process, SIGHUP);
1331				continue;
1332			}
1333			sp->se_flags &= ~SE_SHUTDOWN;
1334			old_getty = sp->se_getty ? strdup(sp->se_getty) : 0;
1335			old_window = sp->se_window ? strdup(sp->se_window) : 0;
1336			old_type = sp->se_type ? strdup(sp->se_type) : 0;
1337			if (setupargv(sp, typ) == 0) {
1338				warning("can't parse getty for port %s",
1339					sp->se_device);
1340				sp->se_flags |= SE_SHUTDOWN;
1341				kill(sp->se_process, SIGHUP);
1342			}
1343			else if (   !old_getty
1344				 || (!old_type && sp->se_type)
1345				 || (old_type && !sp->se_type)
1346				 || (!old_window && sp->se_window)
1347				 || (old_window && !sp->se_window)
1348				 || (strcmp(old_getty, sp->se_getty) != 0)
1349				 || (old_window && strcmp(old_window, sp->se_window) != 0)
1350				 || (old_type && strcmp(old_type, sp->se_type) != 0)
1351				) {
1352				/* Don't set SE_SHUTDOWN here */
1353				sp->se_nspace = 0;
1354				sp->se_started = 0;
1355				kill(sp->se_process, SIGHUP);
1356			}
1357			if (old_getty)
1358				free(old_getty);
1359			if (old_window)
1360				free(old_window);
1361			if (old_type)
1362				free(old_type);
1363			continue;
1364		}
1365
1366		new_session(sprev, session_index, typ);
1367	}
1368
1369	endttyent();
1370
1371	/*
1372	 * sweep through and kill all deleted sessions
1373	 * ones who's /etc/ttys line was deleted (SE_PRESENT unset)
1374	 */
1375	for (sp = sessions; sp != NULL; sp = sp->se_next) {
1376		if ((sp->se_flags & SE_PRESENT) == 0) {
1377			sp->se_flags |= SE_SHUTDOWN;
1378			kill(sp->se_process, SIGHUP);
1379		}
1380	}
1381
1382	return (state_func_t) multi_user;
1383}
1384
1385/*
1386 * Block further logins.
1387 */
1388state_func_t
1389catatonia(void)
1390{
1391	session_t *sp;
1392
1393	for (sp = sessions; sp; sp = sp->se_next)
1394		sp->se_flags |= SE_SHUTDOWN;
1395
1396	return (state_func_t) multi_user;
1397}
1398
1399/*
1400 * Note SIGALRM.
1401 */
1402void
1403alrm_handler(int sig)
1404{
1405	(void)sig;
1406	clang = 1;
1407}
1408
1409/*
1410 * Bring the system down to single user.
1411 */
1412state_func_t
1413death(void)
1414{
1415	session_t *sp;
1416	int i;
1417	pid_t pid;
1418	static const int death_sigs[2] = { SIGTERM, SIGKILL };
1419
1420	/* NB: should send a message to the session logger to avoid blocking. */
1421	logwtmp("~", "shutdown", "");
1422
1423	for (sp = sessions; sp; sp = sp->se_next) {
1424		sp->se_flags |= SE_SHUTDOWN;
1425		kill(sp->se_process, SIGHUP);
1426	}
1427
1428	/* Try to run the rc.shutdown script within a period of time */
1429	(void) runshutdown();
1430
1431	for (i = 0; i < 2; ++i) {
1432		if (kill(-1, death_sigs[i]) == -1 && errno == ESRCH)
1433			return (state_func_t) single_user;
1434
1435		clang = 0;
1436		alarm(DEATH_WATCH);
1437		do
1438			if ((pid = waitpid(-1, (int *)0, 0)) != -1)
1439				collect_child(pid);
1440		while (clang == 0 && errno != ECHILD);
1441
1442		if (errno == ECHILD)
1443			return (state_func_t) single_user;
1444	}
1445
1446	warning("some processes would not die; ps axl advised");
1447
1448	return (state_func_t) single_user;
1449}
1450
1451/*
1452 * Run the system shutdown script.
1453 *
1454 * Exit codes:      XXX I should document more
1455 * -2       shutdown script terminated abnormally
1456 * -1       fatal error - can't run script
1457 * 0        good.
1458 * >0       some error (exit code)
1459 */
1460int
1461runshutdown(void)
1462{
1463	pid_t pid, wpid;
1464	int status;
1465	int shutdowntimeout;
1466	size_t len;
1467	char *argv[4];
1468	struct sigaction sa;
1469	struct stat sb;
1470
1471	/*
1472	 * rc.shutdown is optional, so to prevent any unnecessary
1473	 * complaints from the shell we simply don't run it if the
1474	 * file does not exist. If the stat() here fails for other
1475	 * reasons, we'll let the shell complain.
1476	 */
1477	if (stat(_PATH_RUNDOWN, &sb) == -1 && errno == ENOENT)
1478		return 0;
1479
1480	if ((pid = fork()) == 0) {
1481		int	fd;
1482
1483		/* Assume that init already grab console as ctty before */
1484
1485		sigemptyset(&sa.sa_mask);
1486		sa.sa_flags = 0;
1487		sa.sa_handler = SIG_IGN;
1488		(void) sigaction(SIGTSTP, &sa, (struct sigaction *)0);
1489		(void) sigaction(SIGHUP, &sa, (struct sigaction *)0);
1490
1491		if ((fd = open(_PATH_CONSOLE, O_RDWR)) == -1)
1492		    warning("can't open %s: %m", _PATH_CONSOLE);
1493		else {
1494		    (void) dup2(fd, 0);
1495		    (void) dup2(fd, 1);
1496		    (void) dup2(fd, 2);
1497		    if (fd > 2)
1498			close(fd);
1499		}
1500
1501		/*
1502		 * Run the shutdown script.
1503		 */
1504
1505		char _sh[]	= "sh";
1506		char _reboot[]	= "reboot";
1507		char _single[]	= "single";
1508		char _path_rundown[] = _PATH_RUNDOWN;
1509
1510		argv[0] = _sh;
1511		argv[1] = _path_rundown;
1512		argv[2] = Reboot ? _reboot : _single;
1513		argv[3] = 0;
1514
1515		sigprocmask(SIG_SETMASK, &sa.sa_mask, (sigset_t *) 0);
1516
1517#ifdef LOGIN_CAP
1518		setprocresources(RESOURCE_RC);
1519#endif
1520		execv(_PATH_BSHELL, argv);
1521		warning("can't exec %s for %s: %m", _PATH_BSHELL, _PATH_RUNDOWN);
1522		_exit(1);	/* force single user mode */
1523	}
1524
1525	if (pid == -1) {
1526		emergency("can't fork for %s on %s: %m",
1527			_PATH_BSHELL, _PATH_RUNDOWN);
1528		while (waitpid(-1, (int *) 0, WNOHANG) > 0)
1529			continue;
1530		sleep(STALL_TIMEOUT);
1531		return -1;
1532	}
1533
1534	len = sizeof(shutdowntimeout);
1535	if (sysctlbyname("kern.init_shutdown_timeout",
1536			 &shutdowntimeout,
1537			 &len, NULL, 0) == -1 || shutdowntimeout < 2)
1538	    shutdowntimeout = DEATH_SCRIPT;
1539	alarm(shutdowntimeout);
1540	clang = 0;
1541	/*
1542	 * Copied from single_user().  This is a bit paranoid.
1543	 * Use the same ALRM handler.
1544	 */
1545	do {
1546		if ((wpid = waitpid(-1, &status, WUNTRACED)) != -1)
1547			collect_child(wpid);
1548		if (clang == 1) {
1549			/* we were waiting for the sub-shell */
1550			kill(wpid, SIGTERM);
1551			warning("timeout expired for %s on %s: %m; going to single user mode",
1552				_PATH_BSHELL, _PATH_RUNDOWN);
1553			return -1;
1554		}
1555		if (wpid == -1) {
1556			if (errno == EINTR)
1557				continue;
1558			warning("wait for %s on %s failed: %m; going to single user mode",
1559				_PATH_BSHELL, _PATH_RUNDOWN);
1560			return -1;
1561		}
1562		if (wpid == pid && WIFSTOPPED(status)) {
1563			warning("init: %s on %s stopped, restarting\n",
1564				_PATH_BSHELL, _PATH_RUNDOWN);
1565			kill(pid, SIGCONT);
1566			wpid = -1;
1567		}
1568	} while (wpid != pid && !clang);
1569
1570	/* Turn off the alarm */
1571	alarm(0);
1572
1573	if (WIFSIGNALED(status) && WTERMSIG(status) == SIGTERM &&
1574	    requested_transition == catatonia) {
1575		/*
1576		 * /etc/rc.shutdown executed /sbin/reboot;
1577		 * wait for the end quietly
1578		 */
1579		sigset_t s;
1580
1581		sigfillset(&s);
1582		for (;;)
1583			sigsuspend(&s);
1584	}
1585
1586	if (!WIFEXITED(status)) {
1587		warning("%s on %s terminated abnormally, going to single user mode",
1588			_PATH_BSHELL, _PATH_RUNDOWN);
1589		return -2;
1590	}
1591
1592	if ((status = WEXITSTATUS(status)) != 0)
1593		warning("%s returned status %d", _PATH_RUNDOWN, status);
1594
1595	return status;
1596}
1597
1598static char *
1599strk(char *p)
1600{
1601    static char *t;
1602    char *q;
1603    int c;
1604
1605    if (p)
1606	t = p;
1607    if (!t)
1608	return 0;
1609
1610    c = *t;
1611    while (c == ' ' || c == '\t' )
1612	c = *++t;
1613    if (!c) {
1614	t = 0;
1615	return 0;
1616    }
1617    q = t;
1618    if (c == '\'') {
1619	c = *++t;
1620	q = t;
1621	while (c && c != '\'')
1622	    c = *++t;
1623	if (!c)  /* unterminated string */
1624	    q = t = 0;
1625	else
1626	    *t++ = 0;
1627    } else {
1628	while (c && c != ' ' && c != '\t' )
1629	    c = *++t;
1630	*t++ = 0;
1631	if (!c)
1632	    t = 0;
1633    }
1634    return q;
1635}
1636
1637#ifdef LOGIN_CAP
1638void
1639setprocresources(const char *cname)
1640{
1641	login_cap_t *lc;
1642	if ((lc = login_getclassbyname(cname, NULL)) != NULL) {
1643		setusercontext(lc, (struct passwd*)NULL, 0, LOGIN_SETPRIORITY|LOGIN_SETRESOURCES);
1644		login_close(lc);
1645	}
1646}
1647#endif
1648