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