init.c revision 1558
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 * 3. All advertising materials mentioning features or use of this software
17 *    must display the following acknowledgement:
18 *	This product includes software developed by the University of
19 *	California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 *    may be used to endorse or promote products derived from this software
22 *    without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37#ifndef lint
38static char copyright[] =
39"@(#) Copyright (c) 1991, 1993\n\
40	The Regents of the University of California.  All rights reserved.\n";
41#endif /* not lint */
42
43#ifndef lint
44static char sccsid[] = "@(#)init.c	8.1 (Berkeley) 7/15/93";
45#endif /* not lint */
46
47#include <sys/param.h>
48#include <sys/sysctl.h>
49#include <sys/wait.h>
50
51#include <db.h>
52#include <errno.h>
53#include <fcntl.h>
54#include <signal.h>
55#include <stdio.h>
56#include <stdlib.h>
57#include <string.h>
58#include <syslog.h>
59#include <time.h>
60#include <ttyent.h>
61#include <unistd.h>
62
63#ifdef __STDC__
64#include <stdarg.h>
65#else
66#include <varargs.h>
67#endif
68
69#ifdef SECURE
70#include <pwd.h>
71#endif
72
73#include "pathnames.h"
74
75/*
76 * Until the mythical util.h arrives...
77 */
78extern int login_tty __P((int));
79extern int logout __P((const char *));
80extern void logwtmp __P((const char *, const char *, const char *));
81
82/*
83 * Sleep times; used to prevent thrashing.
84 */
85#define	GETTY_SPACING		 5	/* N secs minimum getty spacing */
86#define	GETTY_SLEEP		30	/* sleep N secs after spacing problem */
87#define	WINDOW_WAIT		 3	/* wait N secs after starting window */
88#define	STALL_TIMEOUT		30	/* wait N secs after warning */
89#define	DEATH_WATCH		10	/* wait N secs for procs to die */
90
91void handle __P((sig_t, ...));
92void delset __P((sigset_t *, ...));
93
94void stall __P((char *, ...));
95void warning __P((char *, ...));
96void emergency __P((char *, ...));
97void disaster __P((int));
98void badsys __P((int));
99
100/*
101 * We really need a recursive typedef...
102 * The following at least guarantees that the return type of (*state_t)()
103 * is sufficiently wide to hold a function pointer.
104 */
105typedef long (*state_func_t) __P((void));
106typedef state_func_t (*state_t) __P((void));
107
108state_func_t single_user __P((void));
109state_func_t runcom __P((void));
110state_func_t read_ttys __P((void));
111state_func_t multi_user __P((void));
112state_func_t clean_ttys __P((void));
113state_func_t catatonia __P((void));
114state_func_t death __P((void));
115
116enum { AUTOBOOT, FASTBOOT } runcom_mode = AUTOBOOT;
117
118void transition __P((state_t));
119state_t requested_transition = runcom;
120
121void setctty __P((char *));
122
123typedef struct init_session {
124	int	se_index;		/* index of entry in ttys file */
125	pid_t	se_process;		/* controlling process */
126	time_t	se_started;		/* used to avoid thrashing */
127	int	se_flags;		/* status of session */
128#define	SE_SHUTDOWN	0x1		/* session won't be restarted */
129	char	*se_device;		/* filename of port */
130	char	*se_getty;		/* what to run on that port */
131	char	**se_getty_argv;	/* pre-parsed argument array */
132	char	*se_window;		/* window system (started only once) */
133	char	**se_window_argv;	/* pre-parsed argument array */
134	struct	init_session *se_prev;
135	struct	init_session *se_next;
136} session_t;
137
138void free_session __P((session_t *));
139session_t *new_session __P((session_t *, int, struct ttyent *));
140session_t *sessions;
141
142char **construct_argv __P((char *));
143void start_window_system __P((session_t *));
144void collect_child __P((pid_t));
145pid_t start_getty __P((session_t *));
146void transition_handler __P((int));
147void alrm_handler __P((int));
148void setsecuritylevel __P((int));
149int getsecuritylevel __P((void));
150int setupargv __P((session_t *, struct ttyent *));
151int clang;
152
153void clear_session_logs __P((session_t *));
154
155int start_session_db __P((void));
156void add_session __P((session_t *));
157void del_session __P((session_t *));
158session_t *find_session __P((pid_t));
159DB *session_db;
160
161/*
162 * The mother of all processes.
163 */
164int
165main(argc, argv)
166	int argc;
167	char **argv;
168{
169	int c;
170	struct sigaction sa;
171	sigset_t mask;
172
173
174	/* Dispose of random users. */
175	if (getuid() != 0) {
176		(void)fprintf(stderr, "init: %s\n", strerror(EPERM));
177		exit (1);
178	}
179
180	/* System V users like to reexec init. */
181	if (getpid() != 1) {
182		(void)fprintf(stderr, "init: already running\n");
183		exit (1);
184	}
185
186	/*
187	 * Note that this does NOT open a file...
188	 * Does 'init' deserve its own facility number?
189	 */
190	openlog("init", LOG_CONS|LOG_ODELAY, LOG_AUTH);
191
192	/*
193	 * Create an initial session.
194	 */
195	if (setsid() < 0)
196		warning("initial setsid() failed: %m");
197
198	/*
199	 * Establish an initial user so that programs running
200	 * single user do not freak out and die (like passwd).
201	 */
202	if (setlogin("root") < 0)
203		warning("setlogin() failed: %m");
204
205	/*
206	 * This code assumes that we always get arguments through flags,
207	 * never through bits set in some random machine register.
208	 */
209	while ((c = getopt(argc, argv, "sf")) != -1)
210		switch (c) {
211		case 's':
212			requested_transition = single_user;
213			break;
214		case 'f':
215			runcom_mode = FASTBOOT;
216			break;
217		default:
218			warning("unrecognized flag '-%c'", c);
219			break;
220		}
221
222	if (optind != argc)
223		warning("ignoring excess arguments");
224
225	/*
226	 * We catch or block signals rather than ignore them,
227	 * so that they get reset on exec.
228	 */
229	handle(badsys, SIGSYS, 0);
230	handle(disaster, SIGABRT, SIGFPE, SIGILL, SIGSEGV,
231	       SIGBUS, SIGXCPU, SIGXFSZ, 0);
232	handle(transition_handler, SIGHUP, SIGTERM, SIGTSTP, 0);
233	handle(alrm_handler, SIGALRM, 0);
234	sigfillset(&mask);
235	delset(&mask, SIGABRT, SIGFPE, SIGILL, SIGSEGV, SIGBUS, SIGSYS,
236		SIGXCPU, SIGXFSZ, SIGHUP, SIGTERM, SIGTSTP, SIGALRM, 0);
237	sigprocmask(SIG_SETMASK, &mask, (sigset_t *) 0);
238	sigemptyset(&sa.sa_mask);
239	sa.sa_flags = 0;
240	sa.sa_handler = SIG_IGN;
241	(void) sigaction(SIGTTIN, &sa, (struct sigaction *)0);
242	(void) sigaction(SIGTTOU, &sa, (struct sigaction *)0);
243
244	/*
245	 * Paranoia.
246	 */
247	close(0);
248	close(1);
249	close(2);
250
251	/*
252	 * Start the state machine.
253	 */
254	transition(requested_transition);
255
256	/*
257	 * Should never reach here.
258	 */
259	return 1;
260}
261
262/*
263 * Associate a function with a signal handler.
264 */
265void
266#ifdef __STDC__
267handle(sig_t handler, ...)
268#else
269handle(va_alist)
270	va_dcl
271#endif
272{
273	int sig;
274	struct sigaction sa;
275	int mask_everything;
276	va_list ap;
277#ifndef __STDC__
278	sig_t handler;
279
280	va_start(ap);
281	handler = va_arg(ap, sig_t);
282#else
283	va_start(ap, handler);
284#endif
285
286	sa.sa_handler = handler;
287	sigfillset(&mask_everything);
288
289	while (sig = va_arg(ap, int)) {
290		sa.sa_mask = mask_everything;
291		/* XXX SA_RESTART? */
292		sa.sa_flags = sig == SIGCHLD ? SA_NOCLDSTOP : 0;
293		sigaction(sig, &sa, (struct sigaction *) 0);
294	}
295	va_end(ap);
296}
297
298/*
299 * Delete a set of signals from a mask.
300 */
301void
302#ifdef __STDC__
303delset(sigset_t *maskp, ...)
304#else
305delset(va_alist)
306	va_dcl
307#endif
308{
309	int sig;
310	va_list ap;
311#ifndef __STDC__
312	sigset_t *maskp;
313
314	va_start(ap);
315	maskp = va_arg(ap, sigset_t *);
316#else
317	va_start(ap, maskp);
318#endif
319
320	while (sig = va_arg(ap, int))
321		sigdelset(maskp, sig);
322	va_end(ap);
323}
324
325/*
326 * Log a message and sleep for a while (to give someone an opportunity
327 * to read it and to save log or hardcopy output if the problem is chronic).
328 * NB: should send a message to the session logger to avoid blocking.
329 */
330void
331#ifdef __STDC__
332stall(char *message, ...)
333#else
334stall(va_alist)
335	va_dcl
336#endif
337{
338	va_list ap;
339#ifndef __STDC__
340	char *message;
341
342	va_start(ap);
343	message = va_arg(ap, char *);
344#else
345	va_start(ap, message);
346#endif
347
348	vsyslog(LOG_ALERT, message, ap);
349	va_end(ap);
350	sleep(STALL_TIMEOUT);
351}
352
353/*
354 * Like stall(), but doesn't sleep.
355 * If cpp had variadic macros, the two functions could be #defines for another.
356 * NB: should send a message to the session logger to avoid blocking.
357 */
358void
359#ifdef __STDC__
360warning(char *message, ...)
361#else
362warning(va_alist)
363	va_dcl
364#endif
365{
366	va_list ap;
367#ifndef __STDC__
368	char *message;
369
370	va_start(ap);
371	message = va_arg(ap, char *);
372#else
373	va_start(ap, message);
374#endif
375
376	vsyslog(LOG_ALERT, message, ap);
377	va_end(ap);
378}
379
380/*
381 * Log an emergency message.
382 * NB: should send a message to the session logger to avoid blocking.
383 */
384void
385#ifdef __STDC__
386emergency(char *message, ...)
387#else
388emergency(va_alist)
389	va_dcl
390#endif
391{
392	va_list ap;
393#ifndef __STDC__
394	char *message;
395
396	va_start(ap);
397	message = va_arg(ap, char *);
398#else
399	va_start(ap, message);
400#endif
401
402	vsyslog(LOG_EMERG, message, ap);
403	va_end(ap);
404}
405
406/*
407 * Catch a SIGSYS signal.
408 *
409 * These may arise if a system does not support sysctl.
410 * We tolerate up to 25 of these, then throw in the towel.
411 */
412void
413badsys(sig)
414	int sig;
415{
416	static int badcount = 0;
417
418	if (badcount++ < 25)
419		return;
420	disaster(sig);
421}
422
423/*
424 * Catch an unexpected signal.
425 */
426void
427disaster(sig)
428	int sig;
429{
430	emergency("fatal signal: %s",
431		sig < (unsigned) NSIG ? sys_siglist[sig] : "unknown signal");
432
433	sleep(STALL_TIMEOUT);
434	_exit(sig);		/* reboot */
435}
436
437/*
438 * Get the security level of the kernel.
439 */
440int
441getsecuritylevel()
442{
443#ifdef KERN_SECURELVL
444	int name[2], curlevel;
445	size_t len;
446	extern int errno;
447
448	name[0] = CTL_KERN;
449	name[1] = KERN_SECURELVL;
450	len = sizeof curlevel;
451	if (sysctl(name, 2, &curlevel, &len, NULL, 0) == -1) {
452		emergency("cannot get kernel security level: %s",
453		    strerror(errno));
454		return (-1);
455	}
456	return (curlevel);
457#else
458	return (-1);
459#endif
460}
461
462/*
463 * Set the security level of the kernel.
464 */
465void
466setsecuritylevel(newlevel)
467	int newlevel;
468{
469#ifdef KERN_SECURELVL
470	int name[2], curlevel;
471	extern int errno;
472
473	curlevel = getsecuritylevel();
474	if (newlevel == curlevel)
475		return;
476	name[0] = CTL_KERN;
477	name[1] = KERN_SECURELVL;
478	if (sysctl(name, 2, NULL, NULL, &newlevel, sizeof newlevel) == -1) {
479		emergency(
480		    "cannot change kernel security level from %d to %d: %s",
481		    curlevel, newlevel, strerror(errno));
482		return;
483	}
484#ifdef SECURE
485	warning("kernel security level changed from %d to %d",
486	    curlevel, newlevel);
487#endif
488#endif
489}
490
491/*
492 * Change states in the finite state machine.
493 * The initial state is passed as an argument.
494 */
495void
496transition(s)
497	state_t s;
498{
499	for (;;)
500		s = (state_t) (*s)();
501}
502
503/*
504 * Close out the accounting files for a login session.
505 * NB: should send a message to the session logger to avoid blocking.
506 */
507void
508clear_session_logs(sp)
509	session_t *sp;
510{
511	char *line = sp->se_device + sizeof(_PATH_DEV) - 1;
512
513	if (logout(line))
514		logwtmp(line, "", "");
515}
516
517/*
518 * Start a session and allocate a controlling terminal.
519 * Only called by children of init after forking.
520 */
521void
522setctty(name)
523	char *name;
524{
525	int fd;
526
527	(void) revoke(name);
528	sleep (2);			/* leave DTR low */
529	if ((fd = open(name, O_RDWR)) == -1) {
530		stall("can't open %s: %m", name);
531		_exit(1);
532	}
533	if (login_tty(fd) == -1) {
534		stall("can't get %s for controlling terminal: %m", name);
535		_exit(1);
536	}
537}
538
539/*
540 * Bring the system up single user.
541 */
542state_func_t
543single_user()
544{
545	pid_t pid, wpid;
546	int status;
547	sigset_t mask;
548	char *shell = _PATH_BSHELL;
549	char *argv[2];
550#ifdef SECURE
551	struct ttyent *typ;
552	struct passwd *pp;
553	static const char banner[] =
554		"Enter root password, or ^D to go multi-user\n";
555	char *clear, *password;
556#endif
557
558	/*
559	 * If the kernel is in secure mode, downgrade it to insecure mode.
560	 */
561	if (getsecuritylevel() > 0)
562		setsecuritylevel(0);
563
564	if ((pid = fork()) == 0) {
565		/*
566		 * Start the single user session.
567		 */
568		setctty(_PATH_CONSOLE);
569
570#ifdef SECURE
571		/*
572		 * Check the root password.
573		 * We don't care if the console is 'on' by default;
574		 * it's the only tty that can be 'off' and 'secure'.
575		 */
576		typ = getttynam("console");
577		pp = getpwnam("root");
578		if (typ && (typ->ty_status & TTY_SECURE) == 0 && pp) {
579			write(2, banner, sizeof banner - 1);
580			for (;;) {
581				clear = getpass("Password:");
582				if (clear == 0 || *clear == '\0')
583					_exit(0);
584				password = crypt(clear, pp->pw_passwd);
585				bzero(clear, _PASSWORD_LEN);
586				if (strcmp(password, pp->pw_passwd) == 0)
587					break;
588				warning("single-user login failed\n");
589			}
590		}
591		endttyent();
592		endpwent();
593#endif /* SECURE */
594
595#ifdef DEBUGSHELL
596		{
597			char altshell[128], *cp = altshell;
598			int num;
599
600#define	SHREQUEST \
601	"Enter pathname of shell or RETURN for sh: "
602			(void)write(STDERR_FILENO,
603			    SHREQUEST, sizeof(SHREQUEST) - 1);
604			while ((num = read(STDIN_FILENO, cp, 1)) != -1 &&
605			    num != 0 && *cp != '\n' && cp < &altshell[127])
606					cp++;
607			*cp = '\0';
608			if (altshell[0] != '\0')
609				shell = altshell;
610		}
611#endif /* DEBUGSHELL */
612
613		/*
614		 * Unblock signals.
615		 * We catch all the interesting ones,
616		 * and those are reset to SIG_DFL on exec.
617		 */
618		sigemptyset(&mask);
619		sigprocmask(SIG_SETMASK, &mask, (sigset_t *) 0);
620
621		/*
622		 * Fire off a shell.
623		 * If the default one doesn't work, try the Bourne shell.
624		 */
625		argv[0] = "-sh";
626		argv[1] = 0;
627		execv(shell, argv);
628		emergency("can't exec %s for single user: %m", shell);
629		execv(_PATH_BSHELL, argv);
630		emergency("can't exec %s for single user: %m", _PATH_BSHELL);
631		sleep(STALL_TIMEOUT);
632		_exit(1);
633	}
634
635	if (pid == -1) {
636		/*
637		 * We are seriously hosed.  Do our best.
638		 */
639		emergency("can't fork single-user shell, trying again");
640		while (waitpid(-1, (int *) 0, WNOHANG) > 0)
641			continue;
642		return (state_func_t) single_user;
643	}
644
645	requested_transition = 0;
646	do {
647		if ((wpid = waitpid(-1, &status, WUNTRACED)) != -1)
648			collect_child(wpid);
649		if (wpid == -1) {
650			if (errno == EINTR)
651				continue;
652			warning("wait for single-user shell failed: %m; restarting");
653			return (state_func_t) single_user;
654		}
655		if (wpid == pid && WIFSTOPPED(status)) {
656			warning("init: shell stopped, restarting\n");
657			kill(pid, SIGCONT);
658			wpid = -1;
659		}
660	} while (wpid != pid && !requested_transition);
661
662	if (requested_transition)
663		return (state_func_t) requested_transition;
664
665	if (!WIFEXITED(status)) {
666		if (WTERMSIG(status) == SIGKILL) {
667			/*
668			 *  reboot(8) killed shell?
669			 */
670			warning("single user shell terminated.");
671			sleep(STALL_TIMEOUT);
672			_exit(0);
673		} else {
674			warning("single user shell terminated, restarting");
675			return (state_func_t) single_user;
676		}
677	}
678
679	runcom_mode = FASTBOOT;
680	return (state_func_t) runcom;
681}
682
683/*
684 * Run the system startup script.
685 */
686state_func_t
687runcom()
688{
689	pid_t pid, wpid;
690	int status;
691	char *argv[4];
692	struct sigaction sa;
693
694	if ((pid = fork()) == 0) {
695		sigemptyset(&sa.sa_mask);
696		sa.sa_flags = 0;
697		sa.sa_handler = SIG_IGN;
698		(void) sigaction(SIGTSTP, &sa, (struct sigaction *)0);
699		(void) sigaction(SIGHUP, &sa, (struct sigaction *)0);
700
701		setctty(_PATH_CONSOLE);
702
703		argv[0] = "sh";
704		argv[1] = _PATH_RUNCOM;
705		argv[2] = runcom_mode == AUTOBOOT ? "autoboot" : 0;
706		argv[3] = 0;
707
708		sigprocmask(SIG_SETMASK, &sa.sa_mask, (sigset_t *) 0);
709
710		execv(_PATH_BSHELL, argv);
711		stall("can't exec %s for %s: %m", _PATH_BSHELL, _PATH_RUNCOM);
712		_exit(1);	/* force single user mode */
713	}
714
715	if (pid == -1) {
716		emergency("can't fork for %s on %s: %m",
717			_PATH_BSHELL, _PATH_RUNCOM);
718		while (waitpid(-1, (int *) 0, WNOHANG) > 0)
719			continue;
720		sleep(STALL_TIMEOUT);
721		return (state_func_t) single_user;
722	}
723
724	/*
725	 * Copied from single_user().  This is a bit paranoid.
726	 */
727	do {
728		if ((wpid = waitpid(-1, &status, WUNTRACED)) != -1)
729			collect_child(wpid);
730		if (wpid == -1) {
731			if (errno == EINTR)
732				continue;
733			warning("wait for %s on %s failed: %m; going to single user mode",
734				_PATH_BSHELL, _PATH_RUNCOM);
735			return (state_func_t) single_user;
736		}
737		if (wpid == pid && WIFSTOPPED(status)) {
738			warning("init: %s on %s stopped, restarting\n",
739				_PATH_BSHELL, _PATH_RUNCOM);
740			kill(pid, SIGCONT);
741			wpid = -1;
742		}
743	} while (wpid != pid);
744
745	if (WIFSIGNALED(status) && WTERMSIG(status) == SIGTERM &&
746	    requested_transition == catatonia) {
747		/* /etc/rc executed /sbin/reboot; wait for the end quietly */
748		sigset_t s;
749
750		sigfillset(&s);
751		for (;;)
752			sigsuspend(&s);
753	}
754
755	if (!WIFEXITED(status)) {
756		warning("%s on %s terminated abnormally, going to single user mode",
757			_PATH_BSHELL, _PATH_RUNCOM);
758		return (state_func_t) single_user;
759	}
760
761	if (WEXITSTATUS(status))
762		return (state_func_t) single_user;
763
764	runcom_mode = AUTOBOOT;		/* the default */
765	/* NB: should send a message to the session logger to avoid blocking. */
766	logwtmp("~", "reboot", "");
767	return (state_func_t) read_ttys;
768}
769
770/*
771 * Open the session database.
772 *
773 * NB: We could pass in the size here; is it necessary?
774 */
775int
776start_session_db()
777{
778	if (session_db && (*session_db->close)(session_db))
779		emergency("session database close: %s", strerror(errno));
780	if ((session_db = dbopen(NULL, O_RDWR, 0, DB_HASH, NULL)) == 0) {
781		emergency("session database open: %s", strerror(errno));
782		return (1);
783	}
784	return (0);
785
786}
787
788/*
789 * Add a new login session.
790 */
791void
792add_session(sp)
793	session_t *sp;
794{
795	DBT key;
796	DBT data;
797
798	key.data = &sp->se_process;
799	key.size = sizeof sp->se_process;
800	data.data = &sp;
801	data.size = sizeof sp;
802
803	if ((*session_db->put)(session_db, &key, &data, 0))
804		emergency("insert %d: %s", sp->se_process, strerror(errno));
805}
806
807/*
808 * Delete an old login session.
809 */
810void
811del_session(sp)
812	session_t *sp;
813{
814	DBT key;
815
816	key.data = &sp->se_process;
817	key.size = sizeof sp->se_process;
818
819	if ((*session_db->del)(session_db, &key, 0))
820		emergency("delete %d: %s", sp->se_process, strerror(errno));
821}
822
823/*
824 * Look up a login session by pid.
825 */
826session_t *
827#ifdef __STDC__
828find_session(pid_t pid)
829#else
830find_session(pid)
831	pid_t pid;
832#endif
833{
834	DBT key;
835	DBT data;
836	session_t *ret;
837
838	key.data = &pid;
839	key.size = sizeof pid;
840	if ((*session_db->get)(session_db, &key, &data, 0) != 0)
841		return 0;
842	bcopy(data.data, (char *)&ret, sizeof(ret));
843	return ret;
844}
845
846/*
847 * Construct an argument vector from a command line.
848 */
849char **
850construct_argv(command)
851	char *command;
852{
853	register int argc = 0;
854	register char **argv = (char **) malloc(((strlen(command) + 1) / 2 + 1)
855						* sizeof (char *));
856	static const char separators[] = " \t";
857
858	if ((argv[argc++] = strtok(command, separators)) == 0)
859		return 0;
860	while (argv[argc++] = strtok((char *) 0, separators))
861		continue;
862	return argv;
863}
864
865/*
866 * Deallocate a session descriptor.
867 */
868void
869free_session(sp)
870	register session_t *sp;
871{
872	free(sp->se_device);
873	if (sp->se_getty) {
874		free(sp->se_getty);
875		free(sp->se_getty_argv);
876	}
877	if (sp->se_window) {
878		free(sp->se_window);
879		free(sp->se_window_argv);
880	}
881	free(sp);
882}
883
884/*
885 * Allocate a new session descriptor.
886 */
887session_t *
888new_session(sprev, session_index, typ)
889	session_t *sprev;
890	int session_index;
891	register struct ttyent *typ;
892{
893	register session_t *sp;
894
895	if ((typ->ty_status & TTY_ON) == 0 ||
896	    typ->ty_name == 0 ||
897	    typ->ty_getty == 0)
898		return 0;
899
900	sp = (session_t *) malloc(sizeof (session_t));
901	bzero(sp, sizeof *sp);
902
903	sp->se_index = session_index;
904
905	sp->se_device = malloc(sizeof(_PATH_DEV) + strlen(typ->ty_name));
906	(void) sprintf(sp->se_device, "%s%s", _PATH_DEV, typ->ty_name);
907
908	if (setupargv(sp, typ) == 0) {
909		free_session(sp);
910		return (0);
911	}
912
913	sp->se_next = 0;
914	if (sprev == 0) {
915		sessions = sp;
916		sp->se_prev = 0;
917	} else {
918		sprev->se_next = sp;
919		sp->se_prev = sprev;
920	}
921
922	return sp;
923}
924
925/*
926 * Calculate getty and if useful window argv vectors.
927 */
928int
929setupargv(sp, typ)
930	session_t *sp;
931	struct ttyent *typ;
932{
933
934	if (sp->se_getty) {
935		free(sp->se_getty);
936		free(sp->se_getty_argv);
937	}
938	sp->se_getty = malloc(strlen(typ->ty_getty) + strlen(typ->ty_name) + 2);
939	(void) sprintf(sp->se_getty, "%s %s", typ->ty_getty, typ->ty_name);
940	sp->se_getty_argv = construct_argv(sp->se_getty);
941	if (sp->se_getty_argv == 0) {
942		warning("can't parse getty for port %s", sp->se_device);
943		free(sp->se_getty);
944		sp->se_getty = 0;
945		return (0);
946	}
947	if (typ->ty_window) {
948		if (sp->se_window)
949			free(sp->se_window);
950		sp->se_window = strdup(typ->ty_window);
951		sp->se_window_argv = construct_argv(sp->se_window);
952		if (sp->se_window_argv == 0) {
953			warning("can't parse window for port %s",
954				sp->se_device);
955			free(sp->se_window);
956			sp->se_window = 0;
957			return (0);
958		}
959	}
960	return (1);
961}
962
963/*
964 * Walk the list of ttys and create sessions for each active line.
965 */
966state_func_t
967read_ttys()
968{
969	int session_index = 0;
970	register session_t *sp, *snext;
971	register struct ttyent *typ;
972
973	/*
974	 * Destroy any previous session state.
975	 * There shouldn't be any, but just in case...
976	 */
977	for (sp = sessions; sp; sp = snext) {
978		if (sp->se_process)
979			clear_session_logs(sp);
980		snext = sp->se_next;
981		free_session(sp);
982	}
983	sessions = 0;
984	if (start_session_db())
985		return (state_func_t) single_user;
986
987	/*
988	 * Allocate a session entry for each active port.
989	 * Note that sp starts at 0.
990	 */
991	while (typ = getttyent())
992		if (snext = new_session(sp, ++session_index, typ))
993			sp = snext;
994
995	endttyent();
996
997	return (state_func_t) multi_user;
998}
999
1000/*
1001 * Start a window system running.
1002 */
1003void
1004start_window_system(sp)
1005	session_t *sp;
1006{
1007	pid_t pid;
1008	sigset_t mask;
1009
1010	if ((pid = fork()) == -1) {
1011		emergency("can't fork for window system on port %s: %m",
1012			sp->se_device);
1013		/* hope that getty fails and we can try again */
1014		return;
1015	}
1016
1017	if (pid)
1018		return;
1019
1020	sigemptyset(&mask);
1021	sigprocmask(SIG_SETMASK, &mask, (sigset_t *) 0);
1022
1023	if (setsid() < 0)
1024		emergency("setsid failed (window) %m");
1025
1026	execv(sp->se_window_argv[0], sp->se_window_argv);
1027	stall("can't exec window system '%s' for port %s: %m",
1028		sp->se_window_argv[0], sp->se_device);
1029	_exit(1);
1030}
1031
1032/*
1033 * Start a login session running.
1034 */
1035pid_t
1036start_getty(sp)
1037	session_t *sp;
1038{
1039	pid_t pid;
1040	sigset_t mask;
1041	time_t current_time = time((time_t *) 0);
1042
1043	/*
1044	 * fork(), not vfork() -- we can't afford to block.
1045	 */
1046	if ((pid = fork()) == -1) {
1047		emergency("can't fork for getty on port %s: %m", sp->se_device);
1048		return -1;
1049	}
1050
1051	if (pid)
1052		return pid;
1053
1054	if (current_time > sp->se_started &&
1055	    current_time - sp->se_started < GETTY_SPACING) {
1056		warning("getty repeating too quickly on port %s, sleeping",
1057		        sp->se_device);
1058		sleep((unsigned) GETTY_SLEEP);
1059	}
1060
1061	if (sp->se_window) {
1062		start_window_system(sp);
1063		sleep(WINDOW_WAIT);
1064	}
1065
1066	sigemptyset(&mask);
1067	sigprocmask(SIG_SETMASK, &mask, (sigset_t *) 0);
1068
1069	execv(sp->se_getty_argv[0], sp->se_getty_argv);
1070	stall("can't exec getty '%s' for port %s: %m",
1071		sp->se_getty_argv[0], sp->se_device);
1072	_exit(1);
1073}
1074
1075/*
1076 * Collect exit status for a child.
1077 * If an exiting login, start a new login running.
1078 */
1079void
1080#ifdef __STDC__
1081collect_child(pid_t pid)
1082#else
1083collect_child(pid)
1084	pid_t pid;
1085#endif
1086{
1087	register session_t *sp, *sprev, *snext;
1088
1089	if (! sessions)
1090		return;
1091
1092	if (! (sp = find_session(pid)))
1093		return;
1094
1095	clear_session_logs(sp);
1096	del_session(sp);
1097	sp->se_process = 0;
1098
1099	if (sp->se_flags & SE_SHUTDOWN) {
1100		if (sprev = sp->se_prev)
1101			sprev->se_next = sp->se_next;
1102		else
1103			sessions = sp->se_next;
1104		if (snext = sp->se_next)
1105			snext->se_prev = sp->se_prev;
1106		free_session(sp);
1107		return;
1108	}
1109
1110	if ((pid = start_getty(sp)) == -1) {
1111		/* serious trouble */
1112		requested_transition = clean_ttys;
1113		return;
1114	}
1115
1116	sp->se_process = pid;
1117	sp->se_started = time((time_t *) 0);
1118	add_session(sp);
1119}
1120
1121/*
1122 * Catch a signal and request a state transition.
1123 */
1124void
1125transition_handler(sig)
1126	int sig;
1127{
1128
1129	switch (sig) {
1130	case SIGHUP:
1131		requested_transition = clean_ttys;
1132		break;
1133	case SIGTERM:
1134		requested_transition = death;
1135		break;
1136	case SIGTSTP:
1137		requested_transition = catatonia;
1138		break;
1139	default:
1140		requested_transition = 0;
1141		break;
1142	}
1143}
1144
1145/*
1146 * Take the system multiuser.
1147 */
1148state_func_t
1149multi_user()
1150{
1151	pid_t pid;
1152	register session_t *sp;
1153
1154	requested_transition = 0;
1155
1156	/*
1157	 * If the administrator has not set the security level to -1
1158	 * to indicate that the kernel should not run multiuser in secure
1159	 * mode, and the run script has not set a higher level of security
1160	 * than level 1, then put the kernel into secure mode.
1161	 */
1162	if (getsecuritylevel() == 0)
1163		setsecuritylevel(1);
1164
1165	for (sp = sessions; sp; sp = sp->se_next) {
1166		if (sp->se_process)
1167			continue;
1168		if ((pid = start_getty(sp)) == -1) {
1169			/* serious trouble */
1170			requested_transition = clean_ttys;
1171			break;
1172		}
1173		sp->se_process = pid;
1174		sp->se_started = time((time_t *) 0);
1175		add_session(sp);
1176	}
1177
1178	while (!requested_transition)
1179		if ((pid = waitpid(-1, (int *) 0, 0)) != -1)
1180			collect_child(pid);
1181
1182	return (state_func_t) requested_transition;
1183}
1184
1185/*
1186 * This is an n-squared algorithm.  We hope it isn't run often...
1187 */
1188state_func_t
1189clean_ttys()
1190{
1191	register session_t *sp, *sprev;
1192	register struct ttyent *typ;
1193	register int session_index = 0;
1194	register int devlen;
1195
1196	if (! sessions)
1197		return (state_func_t) multi_user;
1198
1199	devlen = sizeof(_PATH_DEV) - 1;
1200	while (typ = getttyent()) {
1201		++session_index;
1202
1203		for (sprev = 0, sp = sessions; sp; sprev = sp, sp = sp->se_next)
1204			if (strcmp(typ->ty_name, sp->se_device + devlen) == 0)
1205				break;
1206
1207		if (sp) {
1208			if (sp->se_index != session_index) {
1209				warning("port %s changed utmp index from %d to %d",
1210				       sp->se_device, sp->se_index,
1211				       session_index);
1212				sp->se_index = session_index;
1213			}
1214			if ((typ->ty_status & TTY_ON) == 0 ||
1215			    typ->ty_getty == 0) {
1216				sp->se_flags |= SE_SHUTDOWN;
1217				kill(sp->se_process, SIGHUP);
1218				continue;
1219			}
1220			sp->se_flags &= ~SE_SHUTDOWN;
1221			if (setupargv(sp, typ) == 0) {
1222				warning("can't parse getty for port %s",
1223					sp->se_device);
1224				sp->se_flags |= SE_SHUTDOWN;
1225				kill(sp->se_process, SIGHUP);
1226			}
1227			continue;
1228		}
1229
1230		new_session(sprev, session_index, typ);
1231	}
1232
1233	endttyent();
1234
1235	return (state_func_t) multi_user;
1236}
1237
1238/*
1239 * Block further logins.
1240 */
1241state_func_t
1242catatonia()
1243{
1244	register session_t *sp;
1245
1246	for (sp = sessions; sp; sp = sp->se_next)
1247		sp->se_flags |= SE_SHUTDOWN;
1248
1249	return (state_func_t) multi_user;
1250}
1251
1252/*
1253 * Note SIGALRM.
1254 */
1255void
1256alrm_handler(sig)
1257	int sig;
1258{
1259	clang = 1;
1260}
1261
1262/*
1263 * Bring the system down to single user.
1264 */
1265state_func_t
1266death()
1267{
1268	register session_t *sp;
1269	register int i;
1270	pid_t pid;
1271	static const int death_sigs[3] = { SIGHUP, SIGTERM, SIGKILL };
1272
1273	for (sp = sessions; sp; sp = sp->se_next)
1274		sp->se_flags |= SE_SHUTDOWN;
1275
1276	/* NB: should send a message to the session logger to avoid blocking. */
1277	logwtmp("~", "shutdown", "");
1278
1279	for (i = 0; i < 3; ++i) {
1280		if (kill(-1, death_sigs[i]) == -1 && errno == ESRCH)
1281			return (state_func_t) single_user;
1282
1283		clang = 0;
1284		alarm(DEATH_WATCH);
1285		do
1286			if ((pid = waitpid(-1, (int *)0, 0)) != -1)
1287				collect_child(pid);
1288		while (clang == 0 && errno != ECHILD);
1289
1290		if (errno == ECHILD)
1291			return (state_func_t) single_user;
1292	}
1293
1294	warning("some processes would not die; ps axl advised");
1295
1296	return (state_func_t) single_user;
1297}
1298