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