No empty .Rs/.Re
[netbsd-mini2440.git] / sbin / init / init.c
blobb0c42b0167502719e7d62c70dd9a4d166864dd0d
1 /* $NetBSD: init.c,v 1.99 2009/11/22 18:40:26 mbalmer Exp $ */
3 /*-
4 * Copyright (c) 1991, 1993
5 * The Regents of the University of California. All rights reserved.
7 * This code is derived from software contributed to Berkeley by
8 * Donn Seeley at Berkeley Software Design, Inc.
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.
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.
35 #include <sys/cdefs.h>
36 #ifndef lint
37 __COPYRIGHT("@(#) Copyright (c) 1991, 1993\
38 The Regents of the University of California. All rights reserved.");
39 #endif /* not lint */
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.99 2009/11/22 18:40:26 mbalmer Exp $");
46 #endif
47 #endif /* not lint */
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 <machine/cpu.h>
57 #include <db.h>
58 #include <errno.h>
59 #include <fcntl.h>
60 #include <signal.h>
61 #include <stdio.h>
62 #include <stdlib.h>
63 #include <string.h>
64 #include <syslog.h>
65 #include <time.h>
66 #include <ttyent.h>
67 #include <unistd.h>
68 #include <util.h>
69 #include <paths.h>
70 #include <err.h>
72 #include <stdarg.h>
74 #ifdef SECURE
75 #include <pwd.h>
76 #endif
78 #include "pathnames.h"
80 #define XSTR(x) #x
81 #define STR(x) XSTR(x)
84 * Sleep times; used to prevent thrashing.
86 #define GETTY_SPACING 5 /* N secs minimum getty spacing */
87 #define GETTY_SLEEP 30 /* sleep N secs after spacing problem */
88 #define WINDOW_WAIT 3 /* wait N secs after starting window */
89 #define STALL_TIMEOUT 30 /* wait N secs after warning */
90 #define DEATH_WATCH 10 /* wait N secs for procs to die */
92 const struct timespec dtrtime = {.tv_sec = 0, .tv_nsec = 250000};
94 #if defined(RESCUEDIR)
95 #define INIT_BSHELL RESCUEDIR "/sh"
96 #define INIT_MOUNT_MFS RESCUEDIR "/mount_mfs"
97 #define INIT_PATH RESCUEDIR ":" _PATH_STDPATH
98 #else
99 #define INIT_BSHELL _PATH_BSHELL
100 #define INIT_MOUNT_MFS "/sbin/mount_mfs"
101 #define INIT_PATH _PATH_STDPATH
102 #endif
104 int main(int, char *[]);
106 void handle(sig_t, ...);
107 void delset(sigset_t *, ...);
109 void stall(const char *, ...)
110 __attribute__((__format__(__printf__,1,2)));
111 void warning(const char *, ...)
112 __attribute__((__format__(__printf__,1,2)));
113 void emergency(const char *, ...)
114 __attribute__((__format__(__printf__,1,2)));
115 void disaster(int);
116 void badsys(int);
119 * We really need a recursive typedef...
120 * The following at least guarantees that the return type of (*state_t)()
121 * is sufficiently wide to hold a function pointer.
123 typedef long (*state_func_t)(void);
124 typedef state_func_t (*state_t)(void);
126 #define DEATH 'd'
127 #define SINGLE_USER 's'
128 #define RUNCOM 'r'
129 #define READ_TTYS 't'
130 #define MULTI_USER 'm'
131 #define CLEAN_TTYS 'T'
132 #define CATATONIA 'c'
134 state_func_t single_user(void);
135 state_func_t runcom(void);
136 state_func_t read_ttys(void);
137 state_func_t multi_user(void);
138 state_func_t clean_ttys(void);
139 state_func_t catatonia(void);
140 state_func_t death(void);
142 enum { AUTOBOOT, FASTBOOT } runcom_mode = AUTOBOOT;
144 void transition(state_t);
145 void setctty(const char *);
147 typedef struct init_session {
148 int se_index; /* index of entry in ttys file */
149 pid_t se_process; /* controlling process */
150 struct timeval se_started; /* used to avoid thrashing */
151 int se_flags; /* status of session */
152 #define SE_SHUTDOWN 0x1 /* session won't be restarted */
153 #define SE_PRESENT 0x2 /* session is in /etc/ttys */
154 char *se_device; /* filename of port */
155 char *se_getty; /* what to run on that port */
156 char **se_getty_argv; /* pre-parsed argument array */
157 char *se_window; /* window system (started only once) */
158 char **se_window_argv; /* pre-parsed argument array */
159 struct init_session *se_prev;
160 struct init_session *se_next;
161 } session_t;
163 void free_session(session_t *);
164 session_t *new_session(session_t *, int, struct ttyent *);
165 session_t *sessions;
167 char **construct_argv(char *);
168 void start_window_system(session_t *);
169 void collect_child(pid_t, int);
170 pid_t start_getty(session_t *);
171 void transition_handler(int);
172 void alrm_handler(int);
173 int has_securelevel(void);
174 void setsecuritylevel(int);
175 int getsecuritylevel(void);
176 int securelevel_present;
177 int setupargv(session_t *, struct ttyent *);
178 int clang;
180 int start_session_db(void);
181 void add_session(session_t *);
182 void del_session(session_t *);
183 session_t *find_session(pid_t);
184 DB *session_db;
186 int do_setttyent(void);
188 #ifndef LETS_GET_SMALL
189 state_t requested_transition = runcom;
191 void clear_session_logs(session_t *, int);
192 state_func_t runetcrc(int);
193 #ifdef SUPPORT_UTMPX
194 static struct timeval boot_time;
195 state_t current_state = death;
196 static void session_utmpx(const session_t *, int);
197 static void make_utmpx(const char *, const char *, int, pid_t,
198 const struct timeval *, int);
199 static char get_runlevel(const state_t);
200 static void utmpx_set_runlevel(char, char);
201 #endif
203 #ifdef CHROOT
204 int did_multiuser_chroot = 0;
205 char rootdir[PATH_MAX];
206 int shouldchroot(void);
207 int createsysctlnode(void);
208 #endif /* CHROOT */
210 #else /* LETS_GET_SMALL */
211 state_t requested_transition = single_user;
212 #endif /* !LETS_GET_SMALL */
214 #ifdef MFS_DEV_IF_NO_CONSOLE
216 static int mfs_dev(void);
218 #endif
221 * The mother of all processes.
224 main(int argc, char **argv)
226 struct sigaction sa;
227 sigset_t mask;
228 #ifndef LETS_GET_SMALL
229 int c;
231 #ifdef SUPPORT_UTMPX
232 (void)gettimeofday(&boot_time, NULL);
233 #endif /* SUPPORT_UTMPX */
235 /* Dispose of random users. */
236 if (getuid() != 0) {
237 errno = EPERM;
238 err(1, NULL);
241 /* System V users like to reexec init. */
242 if (getpid() != 1)
243 errx(1, "already running");
244 #endif
247 * Create an initial session.
249 if (setsid() < 0)
250 warn("initial setsid() failed");
253 * Establish an initial user so that programs running
254 * single user do not freak out and die (like passwd).
256 if (setlogin("root") < 0)
257 warn("setlogin() failed");
260 #ifdef MFS_DEV_IF_NO_CONSOLE
261 if (mfs_dev() == -1)
262 requested_transition = single_user;
263 #endif
265 #ifndef LETS_GET_SMALL
267 * Note that this does NOT open a file...
268 * Does 'init' deserve its own facility number?
270 openlog("init", LOG_CONS, LOG_AUTH);
271 #endif /* LETS_GET_SMALL */
274 #ifndef LETS_GET_SMALL
276 * This code assumes that we always get arguments through flags,
277 * never through bits set in some random machine register.
279 while ((c = getopt(argc, argv, "sf")) != -1)
280 switch (c) {
281 case 's':
282 requested_transition = single_user;
283 break;
284 case 'f':
285 runcom_mode = FASTBOOT;
286 break;
287 default:
288 warning("unrecognized flag `%c'", c);
289 break;
292 if (optind != argc)
293 warning("ignoring excess arguments");
294 #else /* LETS_GET_SMALL */
295 requested_transition = single_user;
296 #endif /* LETS_GET_SMALL */
299 * We catch or block signals rather than ignore them,
300 * so that they get reset on exec.
302 handle(badsys, SIGSYS, 0);
303 handle(disaster, SIGABRT, SIGFPE, SIGILL, SIGSEGV,
304 SIGBUS, SIGXCPU, SIGXFSZ, 0);
305 handle(transition_handler, SIGHUP, SIGTERM, SIGTSTP, 0);
306 handle(alrm_handler, SIGALRM, 0);
307 (void)sigfillset(&mask);
308 delset(&mask, SIGABRT, SIGFPE, SIGILL, SIGSEGV, SIGBUS, SIGSYS,
309 SIGXCPU, SIGXFSZ, SIGHUP, SIGTERM, SIGTSTP, SIGALRM, 0);
310 (void)sigprocmask(SIG_SETMASK, &mask, NULL);
311 (void)sigemptyset(&sa.sa_mask);
312 sa.sa_flags = 0;
313 sa.sa_handler = SIG_IGN;
314 (void)sigaction(SIGTTIN, &sa, NULL);
315 (void)sigaction(SIGTTOU, &sa, NULL);
318 * Paranoia.
320 (void)close(0);
321 (void)close(1);
322 (void)close(2);
324 #if !defined(LETS_GET_SMALL) && defined(CHROOT)
325 /* Create "init.root" sysctl node. */
326 (void)createsysctlnode();
327 #endif /* !LETS_GET_SMALL && CHROOT*/
330 * Securelevel might not be supported by the kernel. Query for it, and
331 * set a variable indicating whether we should attempt anything with it
332 * or not.
334 securelevel_present = has_securelevel();
337 * Start the state machine.
339 transition(requested_transition);
342 * Should never reach here.
344 return 1;
348 * Associate a function with a signal handler.
350 void
351 handle(sig_t handler, ...)
353 int sig;
354 struct sigaction sa;
355 sigset_t mask_everything;
356 va_list ap;
358 va_start(ap, handler);
360 sa.sa_handler = handler;
361 (void)sigfillset(&mask_everything);
363 while ((sig = va_arg(ap, int)) != 0) {
364 sa.sa_mask = mask_everything;
365 /* XXX SA_RESTART? */
366 sa.sa_flags = sig == SIGCHLD ? SA_NOCLDSTOP : 0;
367 (void)sigaction(sig, &sa, NULL);
369 va_end(ap);
373 * Delete a set of signals from a mask.
375 void
376 delset(sigset_t *maskp, ...)
378 int sig;
379 va_list ap;
381 va_start(ap, maskp);
383 while ((sig = va_arg(ap, int)) != 0)
384 (void)sigdelset(maskp, sig);
385 va_end(ap);
388 #if 0 /* Enable to get error messages from init ! */
389 #define vsyslog(level, fmt, ap) print_console(level, fmt, ap)
390 #define closelog()
392 static void
393 print_console(int level, const char *message, va_list ap)
396 * XXX: syslog seems to just plain not work in console-only
397 * XXX: situation... that should be fixed. Let's leave this
398 * XXX: note + code here in case someone gets in trouble and
399 * XXX: wants to debug. -- Jachym Holecek <freza@liberouter.org>
401 char errbuf[1024];
402 int fd, len;
404 /* We can't do anything on errors, anyway... */
405 fd = open(_PATH_CONSOLE, O_WRONLY);
406 if (fd == -1)
407 return ;
409 /* %m will get lost... */
410 len = vsnprintf(errbuf, sizeof(errbuf), message, ap);
411 (void)write(fd, (void *)errbuf, len);
412 (void)close(fd);
414 #endif
417 * Log a message and sleep for a while (to give someone an opportunity
418 * to read it and to save log or hardcopy output if the problem is chronic).
419 * NB: should send a message to the session logger to avoid blocking.
421 void
422 stall(const char *message, ...)
424 va_list ap;
426 va_start(ap, message);
427 vsyslog(LOG_ALERT, message, ap);
428 va_end(ap);
429 closelog();
430 (void)sleep(STALL_TIMEOUT);
434 * Like stall(), but doesn't sleep.
435 * If cpp had variadic macros, the two functions could be #defines for another.
436 * NB: should send a message to the session logger to avoid blocking.
438 void
439 warning(const char *message, ...)
441 va_list ap;
443 va_start(ap, message);
444 vsyslog(LOG_ALERT, message, ap);
445 va_end(ap);
446 closelog();
450 * Log an emergency message.
451 * NB: should send a message to the session logger to avoid blocking.
453 void
454 emergency(const char *message, ...)
456 va_list ap;
458 va_start(ap, message);
459 vsyslog(LOG_EMERG, message, ap);
460 va_end(ap);
461 closelog();
465 * Catch a SIGSYS signal.
467 * These may arise if a system does not support sysctl.
468 * We tolerate up to 25 of these, then throw in the towel.
470 void
471 badsys(int sig)
473 static int badcount = 0;
475 if (badcount++ < 25)
476 return;
477 disaster(sig);
481 * Catch an unexpected signal.
483 void
484 disaster(int sig)
487 emergency("fatal signal: %s", strsignal(sig));
488 (void)sleep(STALL_TIMEOUT);
489 _exit(sig); /* reboot */
493 * Check if securelevel is present.
496 has_securelevel(void)
498 #ifdef KERN_SECURELVL
499 int name[2], curlevel;
500 size_t len;
502 name[0] = CTL_KERN;
503 name[1] = KERN_SECURELVL;
504 len = sizeof curlevel;
505 if (sysctl(name, 2, &curlevel, &len, NULL, 0) == -1) {
506 /* If it doesn't exist, it's okay. */
507 if (errno == ENOENT)
508 return 0;
510 return 1;
511 #else
512 return 0;
513 #endif
517 * Get the security level of the kernel.
520 getsecuritylevel(void)
522 #ifdef KERN_SECURELVL
523 int name[2], curlevel;
524 size_t len;
526 if (!securelevel_present)
527 return -1;
529 name[0] = CTL_KERN;
530 name[1] = KERN_SECURELVL;
531 len = sizeof curlevel;
532 if (sysctl(name, 2, &curlevel, &len, NULL, 0) == -1) {
533 emergency("cannot get kernel security level: %m");
534 return -1;
536 return curlevel;
537 #else
538 return -1;
539 #endif
543 * Set the security level of the kernel.
545 void
546 setsecuritylevel(int newlevel)
548 #ifdef KERN_SECURELVL
549 int name[2], curlevel;
551 if (!securelevel_present)
552 return;
554 curlevel = getsecuritylevel();
555 if (newlevel == curlevel)
556 return;
557 name[0] = CTL_KERN;
558 name[1] = KERN_SECURELVL;
559 if (sysctl(name, 2, NULL, NULL, &newlevel, sizeof newlevel) == -1) {
560 emergency("cannot change kernel security level from"
561 " %d to %d: %m", curlevel, newlevel);
562 return;
564 #ifdef SECURE
565 warning("kernel security level changed from %d to %d",
566 curlevel, newlevel);
567 #endif
568 #endif
572 * Change states in the finite state machine.
573 * The initial state is passed as an argument.
575 void
576 transition(state_t s)
579 if (s == NULL)
580 return;
581 for (;;) {
582 #ifdef SUPPORT_UTMPX
583 #ifndef LETS_GET_SMALL
584 utmpx_set_runlevel(get_runlevel(current_state),
585 get_runlevel(s));
586 current_state = s;
587 #endif
588 #endif
589 s = (state_t)(*s)();
593 #ifndef LETS_GET_SMALL
595 * Close out the accounting files for a login session.
596 * NB: should send a message to the session logger to avoid blocking.
598 void
599 clear_session_logs(session_t *sp, int status)
601 #if defined(SUPPORT_UTMP) || defined(SUPPORT_UTMPX)
602 char *line = sp->se_device + sizeof(_PATH_DEV) - 1;
603 #endif
605 #ifdef SUPPORT_UTMPX
606 if (logoutx(line, status, DEAD_PROCESS))
607 logwtmpx(line, "", "", status, DEAD_PROCESS);
608 #endif
609 #ifdef SUPPORT_UTMP
610 if (logout(line))
611 logwtmp(line, "", "");
612 #endif
614 #endif
617 * Start a session and allocate a controlling terminal.
618 * Only called by children of init after forking.
620 void
621 setctty(const char *name)
623 int fd;
625 (void)revoke(name);
626 (void)nanosleep(&dtrtime, NULL); /* leave DTR low for a bit */
627 if ((fd = open(name, O_RDWR)) == -1) {
628 stall("can't open %s: %m", name);
629 _exit(1);
631 if (login_tty(fd) == -1) {
632 stall("can't get %s for controlling terminal: %m", name);
633 _exit(2);
638 * Bring the system up single user.
640 state_func_t
641 single_user(void)
643 pid_t pid, wpid;
644 int status;
645 int from_securitylevel;
646 sigset_t mask;
647 struct sigaction sa, satstp, sahup;
648 #ifdef ALTSHELL
649 const char *shell = INIT_BSHELL;
650 #endif
651 const char *argv[2];
652 #ifdef SECURE
653 struct ttyent *typ;
654 struct passwd *pp;
655 char *clear, *password;
656 #endif
657 #ifdef ALTSHELL
658 char altshell[128];
659 #endif /* ALTSHELL */
661 #if !defined(LETS_GET_SMALL) && defined(CHROOT)
662 /* Clear previous idea, just in case. */
663 did_multiuser_chroot = 0;
664 #endif /* !LETS_GET_SMALL && CHROOT */
667 * If the kernel is in secure mode, downgrade it to insecure mode.
669 from_securitylevel = getsecuritylevel();
670 if (from_securitylevel > 0)
671 setsecuritylevel(0);
673 (void)sigemptyset(&sa.sa_mask);
674 sa.sa_flags = 0;
675 sa.sa_handler = SIG_IGN;
676 (void)sigaction(SIGTSTP, &sa, &satstp);
677 (void)sigaction(SIGHUP, &sa, &sahup);
678 if ((pid = fork()) == 0) {
680 * Start the single user session.
682 if (access(_PATH_CONSTTY, F_OK) == 0)
683 setctty(_PATH_CONSTTY);
684 else
685 setctty(_PATH_CONSOLE);
687 #ifdef SECURE
689 * Check the root password.
690 * We don't care if the console is 'on' by default;
691 * it's the only tty that can be 'off' and 'secure'.
693 typ = getttynam("console");
694 pp = getpwnam("root");
695 if (typ && (from_securitylevel >=2 || (typ->ty_status
696 & TTY_SECURE) == 0) && pp && *pp->pw_passwd != '\0') {
697 (void)fprintf(stderr,
698 "Enter root password, or ^D to go multi-user\n");
699 for (;;) {
700 clear = getpass("Password:");
701 if (clear == 0 || *clear == '\0')
702 _exit(0);
703 password = crypt(clear, pp->pw_passwd);
704 (void)memset(clear, 0, _PASSWORD_LEN);
705 if (strcmp(password, pp->pw_passwd) == 0)
706 break;
707 warning("single-user login failed");
710 (void)endttyent();
711 endpwent();
712 #endif /* SECURE */
714 #ifdef ALTSHELL
715 (void)fprintf(stderr,
716 "Enter pathname of shell or RETURN for %s: ", shell);
717 if (fgets(altshell, sizeof(altshell), stdin) == NULL) {
718 altshell[0] = '\0';
719 } else {
720 /* nuke \n */
721 char *p;
723 if ((p = strchr(altshell, '\n')) != NULL)
724 *p = '\0';
727 if (altshell[0])
728 shell = altshell;
729 #endif /* ALTSHELL */
732 * Unblock signals.
733 * We catch all the interesting ones,
734 * and those are reset to SIG_DFL on exec.
736 (void)sigemptyset(&mask);
737 (void)sigprocmask(SIG_SETMASK, &mask, NULL);
740 * Fire off a shell.
741 * If the default one doesn't work, try the Bourne shell.
743 argv[0] = "-sh";
744 argv[1] = 0;
745 (void)setenv("PATH", INIT_PATH, 1);
746 #ifdef ALTSHELL
747 if (altshell[0])
748 argv[0] = altshell;
749 (void)execv(shell, __UNCONST(argv));
750 emergency("can't exec `%s' for single user: %m", shell);
751 argv[0] = "-sh";
752 #endif /* ALTSHELL */
753 (void)execv(INIT_BSHELL, __UNCONST(argv));
754 emergency("can't exec `%s' for single user: %m", INIT_BSHELL);
755 (void)sleep(STALL_TIMEOUT);
756 _exit(3);
759 if (pid == -1) {
761 * We are seriously hosed. Do our best.
763 emergency("can't fork single-user shell: %m, trying again");
764 while (waitpid(-1, NULL, WNOHANG) > 0)
765 continue;
766 (void)sigaction(SIGTSTP, &satstp, NULL);
767 (void)sigaction(SIGHUP, &sahup, NULL);
768 return (state_func_t)single_user;
771 requested_transition = 0;
772 do {
773 if ((wpid = waitpid(-1, &status, WUNTRACED)) != -1)
774 collect_child(wpid, status);
775 if (wpid == -1) {
776 if (errno == EINTR)
777 continue;
778 warning("wait for single-user shell failed: %m; "
779 "restarting");
780 return (state_func_t)single_user;
782 if (wpid == pid && WIFSTOPPED(status)) {
783 warning("shell stopped, restarting");
784 (void)kill(pid, SIGCONT);
785 wpid = -1;
787 } while (wpid != pid && !requested_transition);
789 if (requested_transition) {
790 (void)sigaction(SIGTSTP, &satstp, NULL);
791 (void)sigaction(SIGHUP, &sahup, NULL);
792 return (state_func_t)requested_transition;
795 if (WIFSIGNALED(status)) {
796 if (WTERMSIG(status) == SIGKILL) {
797 /* executed /sbin/reboot; wait for the end quietly */
798 sigset_t s;
800 (void)sigfillset(&s);
801 for (;;)
802 (void)sigsuspend(&s);
803 } else {
804 warning("single user shell terminated (%x), restarting",
805 status);
806 (void)sigaction(SIGTSTP, &satstp, NULL);
807 (void)sigaction(SIGHUP, &sahup, NULL);
808 return (state_func_t)single_user;
812 runcom_mode = FASTBOOT;
813 (void)sigaction(SIGTSTP, &satstp, NULL);
814 (void)sigaction(SIGHUP, &sahup, NULL);
815 #ifndef LETS_GET_SMALL
816 return (state_func_t)runcom;
817 #else /* LETS_GET_SMALL */
818 return (state_func_t)single_user;
819 #endif /* LETS_GET_SMALL */
822 #ifndef LETS_GET_SMALL
824 /* ARGSUSED */
825 state_func_t
826 runetcrc(int trychroot)
828 pid_t pid, wpid;
829 int status;
830 const char *argv[4];
831 struct sigaction sa;
833 switch ((pid = fork())) {
834 case 0:
835 (void)sigemptyset(&sa.sa_mask);
836 sa.sa_flags = 0;
837 sa.sa_handler = SIG_IGN;
838 (void)sigaction(SIGTSTP, &sa, NULL);
839 (void)sigaction(SIGHUP, &sa, NULL);
841 setctty(_PATH_CONSOLE);
843 argv[0] = "sh";
844 argv[1] = _PATH_RUNCOM;
845 argv[2] = (runcom_mode == AUTOBOOT ? "autoboot" : 0);
846 argv[3] = 0;
848 (void)sigprocmask(SIG_SETMASK, &sa.sa_mask, NULL);
850 #ifdef CHROOT
851 if (trychroot)
852 if (chroot(rootdir) != 0) {
853 warning("failed to chroot to `%s': %m",
854 rootdir);
855 _exit(4); /* force single user mode */
857 #endif /* CHROOT */
859 (void)execv(INIT_BSHELL, __UNCONST(argv));
860 stall("can't exec `%s' for `%s': %m", INIT_BSHELL, _PATH_RUNCOM);
861 _exit(5); /* force single user mode */
862 /*NOTREACHED*/
863 case -1:
864 emergency("can't fork for `%s' on `%s': %m", INIT_BSHELL,
865 _PATH_RUNCOM);
866 while (waitpid(-1, NULL, WNOHANG) > 0)
867 continue;
868 (void)sleep(STALL_TIMEOUT);
869 return (state_func_t)single_user;
870 default:
871 break;
875 * Copied from single_user(). This is a bit paranoid.
877 do {
878 if ((wpid = waitpid(-1, &status, WUNTRACED)) != -1)
879 collect_child(wpid, status);
880 if (wpid == -1) {
881 if (errno == EINTR)
882 continue;
883 warning("wait for `%s' on `%s' failed: %m; going to "
884 "single user mode", INIT_BSHELL, _PATH_RUNCOM);
885 return (state_func_t)single_user;
887 if (wpid == pid && WIFSTOPPED(status)) {
888 warning("`%s' on `%s' stopped, restarting",
889 INIT_BSHELL, _PATH_RUNCOM);
890 (void)kill(pid, SIGCONT);
891 wpid = -1;
893 } while (wpid != pid);
895 if (WIFSIGNALED(status) && WTERMSIG(status) == SIGTERM &&
896 requested_transition == catatonia) {
897 /* /etc/rc executed /sbin/reboot; wait for the end quietly */
898 sigset_t s;
900 (void)sigfillset(&s);
901 for (;;)
902 (void)sigsuspend(&s);
905 if (!WIFEXITED(status)) {
906 warning("`%s' on `%s' terminated abnormally, going to "
907 "single user mode", INIT_BSHELL, _PATH_RUNCOM);
908 return (state_func_t)single_user;
911 if (WEXITSTATUS(status))
912 return (state_func_t)single_user;
914 return (state_func_t)read_ttys;
918 * Run the system startup script.
920 state_func_t
921 runcom(void)
923 state_func_t next_step;
925 /* Run /etc/rc and choose next state depending on the result. */
926 next_step = runetcrc(0);
927 if (next_step != (state_func_t)read_ttys)
928 return (state_func_t)next_step;
930 #ifdef CHROOT
932 * If init.root sysctl does not point to "/", we'll chroot and run
933 * The Real(tm) /etc/rc now. Global variable rootdir will tell us
934 * where to go.
936 if (shouldchroot()) {
937 next_step = runetcrc(1);
938 if (next_step != (state_func_t)read_ttys)
939 return (state_func_t)next_step;
941 did_multiuser_chroot = 1;
942 } else {
943 did_multiuser_chroot = 0;
945 #endif /* CHROOT */
948 * Regardless of whether in chroot or not, we booted successfuly.
949 * It's time to spawn gettys (ie. next_step's value at this point).
951 runcom_mode = AUTOBOOT; /* the default */
952 /* NB: should send a message to the session logger to avoid blocking. */
953 #ifdef SUPPORT_UTMPX
954 logwtmpx("~", "reboot", "", 0, INIT_PROCESS);
955 #endif
956 #ifdef SUPPORT_UTMP
957 logwtmp("~", "reboot", "");
958 #endif
959 return (state_func_t)read_ttys;
963 * Open the session database.
965 * NB: We could pass in the size here; is it necessary?
968 start_session_db(void)
971 if (session_db && (*session_db->close)(session_db))
972 emergency("session database close: %m");
973 if ((session_db = dbopen(NULL, O_RDWR, 0, DB_HASH, NULL)) == 0) {
974 emergency("session database open: %m");
975 return 1;
977 return 0;
982 * Add a new login session.
984 void
985 add_session(session_t *sp)
987 DBT key;
988 DBT data;
990 if (session_db == NULL)
991 return;
993 key.data = &sp->se_process;
994 key.size = sizeof sp->se_process;
995 data.data = &sp;
996 data.size = sizeof sp;
998 if ((*session_db->put)(session_db, &key, &data, 0))
999 emergency("insert %d: %m", sp->se_process);
1000 #ifdef SUPPORT_UTMPX
1001 session_utmpx(sp, 1);
1002 #endif
1006 * Delete an old login session.
1008 void
1009 del_session(session_t *sp)
1011 DBT key;
1013 key.data = &sp->se_process;
1014 key.size = sizeof sp->se_process;
1016 if ((*session_db->del)(session_db, &key, 0))
1017 emergency("delete %d: %m", sp->se_process);
1018 #ifdef SUPPORT_UTMPX
1019 session_utmpx(sp, 0);
1020 #endif
1024 * Look up a login session by pid.
1026 session_t *
1027 find_session(pid_t pid)
1029 DBT key;
1030 DBT data;
1031 session_t *ret;
1033 if (session_db == NULL)
1034 return NULL;
1036 key.data = &pid;
1037 key.size = sizeof pid;
1038 if ((*session_db->get)(session_db, &key, &data, 0) != 0)
1039 return 0;
1040 (void)memmove(&ret, data.data, sizeof(ret));
1041 return ret;
1045 * Construct an argument vector from a command line.
1047 char **
1048 construct_argv(char *command)
1050 int argc = 0;
1051 char **argv = malloc(((strlen(command) + 1) / 2 + 1) * sizeof (char *));
1052 static const char separators[] = " \t";
1054 if (argv == NULL)
1055 return NULL;
1057 if ((argv[argc++] = strtok(command, separators)) == 0) {
1058 free(argv);
1059 return NULL;
1061 while ((argv[argc++] = strtok(NULL, separators)) != NULL)
1062 continue;
1063 return argv;
1067 * Deallocate a session descriptor.
1069 void
1070 free_session(session_t *sp)
1073 free(sp->se_device);
1074 if (sp->se_getty) {
1075 free(sp->se_getty);
1076 free(sp->se_getty_argv);
1078 if (sp->se_window) {
1079 free(sp->se_window);
1080 free(sp->se_window_argv);
1082 free(sp);
1086 * Allocate a new session descriptor.
1088 session_t *
1089 new_session(session_t *sprev, int session_index, struct ttyent *typ)
1091 session_t *sp;
1093 if ((typ->ty_status & TTY_ON) == 0 || typ->ty_name == NULL ||
1094 typ->ty_getty == NULL)
1095 return NULL;
1097 sp = malloc(sizeof (session_t));
1098 if (sp == NULL)
1099 return NULL;
1100 (void)memset(sp, 0, sizeof *sp);
1102 sp->se_flags = SE_PRESENT;
1103 sp->se_index = session_index;
1105 (void)asprintf(&sp->se_device, "%s%s", _PATH_DEV, typ->ty_name);
1106 if (!sp->se_device)
1107 return NULL;
1109 if (setupargv(sp, typ) == 0) {
1110 free_session(sp);
1111 return NULL;
1114 sp->se_next = NULL;
1115 if (sprev == NULL) {
1116 sessions = sp;
1117 sp->se_prev = NULL;
1118 } else {
1119 sprev->se_next = sp;
1120 sp->se_prev = sprev;
1123 return sp;
1127 * Calculate getty and if useful window argv vectors.
1130 setupargv(session_t *sp, struct ttyent *typ)
1133 if (sp->se_getty) {
1134 free(sp->se_getty);
1135 free(sp->se_getty_argv);
1137 (void)asprintf(&sp->se_getty, "%s %s", typ->ty_getty, typ->ty_name);
1138 if (!sp->se_getty)
1139 return 0;
1140 sp->se_getty_argv = construct_argv(sp->se_getty);
1141 if (sp->se_getty_argv == NULL) {
1142 warning("can't parse getty for port `%s'", sp->se_device);
1143 free(sp->se_getty);
1144 sp->se_getty = NULL;
1145 return 0;
1147 if (typ->ty_window) {
1148 if (sp->se_window)
1149 free(sp->se_window);
1150 sp->se_window = strdup(typ->ty_window);
1151 sp->se_window_argv = construct_argv(sp->se_window);
1152 if (sp->se_window_argv == NULL) {
1153 warning("can't parse window for port `%s'",
1154 sp->se_device);
1155 free(sp->se_window);
1156 sp->se_window = NULL;
1157 return 0;
1160 return 1;
1164 * Walk the list of ttys and create sessions for each active line.
1166 state_func_t
1167 read_ttys(void)
1169 int session_index = 0;
1170 session_t *sp, *snext;
1171 struct ttyent *typ;
1173 #ifdef SUPPORT_UTMPX
1174 if (sessions == NULL) {
1175 struct stat st;
1177 make_utmpx("", BOOT_MSG, BOOT_TIME, 0, &boot_time, 0);
1180 * If wtmpx is not empty, pick the down time from there
1182 if (stat(_PATH_WTMPX, &st) != -1 && st.st_size != 0) {
1183 struct timeval down_time;
1185 TIMESPEC_TO_TIMEVAL(&down_time,
1186 st.st_atime > st.st_mtime ?
1187 &st.st_atimespec : &st.st_mtimespec);
1188 make_utmpx("", DOWN_MSG, DOWN_TIME, 0, &down_time, 0);
1191 #endif
1193 * Destroy any previous session state.
1194 * There shouldn't be any, but just in case...
1196 for (sp = sessions; sp; sp = snext) {
1197 #ifndef LETS_GET_SMALL
1198 if (sp->se_process)
1199 clear_session_logs(sp, 0);
1200 #endif
1201 snext = sp->se_next;
1202 free_session(sp);
1204 sessions = NULL;
1206 if (start_session_db()) {
1207 warning("start_session_db failed, death");
1208 #ifdef CHROOT
1209 /* If /etc/rc ran in chroot, we want to kill any survivors. */
1210 if (did_multiuser_chroot)
1211 return (state_func_t)death;
1212 else
1213 #endif /* CHROOT */
1214 return (state_func_t)single_user;
1217 (void)do_setttyent();
1220 * Allocate a session entry for each active port.
1221 * Note that sp starts at 0.
1223 while ((typ = getttyent()) != NULL)
1224 if ((snext = new_session(sp, ++session_index, typ)) != NULL)
1225 sp = snext;
1226 (void)endttyent();
1228 return (state_func_t)multi_user;
1232 * Start a window system running.
1234 void
1235 start_window_system(session_t *sp)
1237 pid_t pid;
1238 sigset_t mask;
1240 if ((pid = fork()) == -1) {
1241 emergency("can't fork for window system on port `%s': %m",
1242 sp->se_device);
1243 /* hope that getty fails and we can try again */
1244 return;
1247 if (pid)
1248 return;
1250 (void)sigemptyset(&mask);
1251 (void)sigprocmask(SIG_SETMASK, &mask, NULL);
1253 if (setsid() < 0)
1254 emergency("setsid failed (window): %m");
1256 (void)execv(sp->se_window_argv[0], sp->se_window_argv);
1257 stall("can't exec window system `%s' for port `%s': %m",
1258 sp->se_window_argv[0], sp->se_device);
1259 _exit(6);
1263 * Start a login session running.
1265 pid_t
1266 start_getty(session_t *sp)
1268 pid_t pid;
1269 sigset_t mask;
1270 time_t current_time = time(NULL);
1273 * fork(), not vfork() -- we can't afford to block.
1275 if ((pid = fork()) == -1) {
1276 emergency("can't fork for getty on port `%s': %m",
1277 sp->se_device);
1278 return -1;
1281 if (pid)
1282 return pid;
1284 #ifdef CHROOT
1285 /* If /etc/rc did proceed inside chroot, we have to try as well. */
1286 if (did_multiuser_chroot)
1287 if (chroot(rootdir) != 0) {
1288 stall("can't chroot getty `%s' inside `%s': %m",
1289 sp->se_getty_argv[0], rootdir);
1290 _exit(7);
1292 #endif /* CHROOT */
1294 if (current_time > sp->se_started.tv_sec &&
1295 current_time - sp->se_started.tv_sec < GETTY_SPACING) {
1296 warning("getty repeating too quickly on port `%s', sleeping",
1297 sp->se_device);
1298 (void)sleep(GETTY_SLEEP);
1301 if (sp->se_window) {
1302 start_window_system(sp);
1303 (void)sleep(WINDOW_WAIT);
1306 (void)sigemptyset(&mask);
1307 (void)sigprocmask(SIG_SETMASK, &mask, (sigset_t *) 0);
1309 (void)execv(sp->se_getty_argv[0], sp->se_getty_argv);
1310 stall("can't exec getty `%s' for port `%s': %m",
1311 sp->se_getty_argv[0], sp->se_device);
1312 _exit(8);
1313 /*NOTREACHED*/
1315 #ifdef SUPPORT_UTMPX
1316 static void
1317 session_utmpx(const session_t *sp, int add)
1319 const char *name = sp->se_getty ? sp->se_getty :
1320 (sp->se_window ? sp->se_window : "");
1321 const char *line = sp->se_device + sizeof(_PATH_DEV) - 1;
1323 make_utmpx(name, line, add ? LOGIN_PROCESS : DEAD_PROCESS,
1324 sp->se_process, &sp->se_started, sp->se_index);
1327 static void
1328 make_utmpx(const char *name, const char *line, int type, pid_t pid,
1329 const struct timeval *tv, int session)
1331 struct utmpx ut;
1332 const char *eline;
1334 (void)memset(&ut, 0, sizeof(ut));
1335 (void)strlcpy(ut.ut_name, name, sizeof(ut.ut_name));
1336 ut.ut_type = type;
1337 (void)strlcpy(ut.ut_line, line, sizeof(ut.ut_line));
1338 ut.ut_pid = pid;
1339 if (tv)
1340 ut.ut_tv = *tv;
1341 else
1342 (void)gettimeofday(&ut.ut_tv, NULL);
1343 ut.ut_session = session;
1345 eline = line + strlen(line);
1346 if ((size_t)(eline - line) >= sizeof(ut.ut_id))
1347 line = eline - sizeof(ut.ut_id);
1348 (void)strncpy(ut.ut_id, line, sizeof(ut.ut_id));
1350 if (pututxline(&ut) == NULL)
1351 warning("can't add utmpx record for `%s': %m", ut.ut_line);
1352 endutxent();
1355 static char
1356 get_runlevel(const state_t s)
1358 if (s == (state_t)single_user)
1359 return SINGLE_USER;
1360 if (s == (state_t)runcom)
1361 return RUNCOM;
1362 if (s == (state_t)read_ttys)
1363 return READ_TTYS;
1364 if (s == (state_t)multi_user)
1365 return MULTI_USER;
1366 if (s == (state_t)clean_ttys)
1367 return CLEAN_TTYS;
1368 if (s == (state_t)catatonia)
1369 return CATATONIA;
1370 return DEATH;
1373 static void
1374 utmpx_set_runlevel(char old, char new)
1376 struct utmpx ut;
1379 * Don't record any transitions until we did the first transition
1380 * to read ttys, which is when we are guaranteed to have a read-write
1381 * /var. Perhaps use a different variable for this?
1383 if (sessions == NULL)
1384 return;
1386 (void)memset(&ut, 0, sizeof(ut));
1387 (void)snprintf(ut.ut_line, sizeof(ut.ut_line), RUNLVL_MSG, new);
1388 ut.ut_type = RUN_LVL;
1389 (void)gettimeofday(&ut.ut_tv, NULL);
1390 ut.ut_exit.e_exit = old;
1391 ut.ut_exit.e_termination = new;
1392 if (pututxline(&ut) == NULL)
1393 warning("can't add utmpx record for `runlevel': %m");
1394 endutxent();
1396 #endif /* SUPPORT_UTMPX */
1398 #endif /* LETS_GET_SMALL */
1401 * Collect exit status for a child.
1402 * If an exiting login, start a new login running.
1404 void
1405 collect_child(pid_t pid, int status)
1407 #ifndef LETS_GET_SMALL
1408 session_t *sp, *sprev, *snext;
1410 if (! sessions)
1411 return;
1413 if ((sp = find_session(pid)) == NULL)
1414 return;
1416 clear_session_logs(sp, status);
1417 del_session(sp);
1418 sp->se_process = 0;
1420 if (sp->se_flags & SE_SHUTDOWN) {
1421 if ((sprev = sp->se_prev) != NULL)
1422 sprev->se_next = sp->se_next;
1423 else
1424 sessions = sp->se_next;
1425 if ((snext = sp->se_next) != NULL)
1426 snext->se_prev = sp->se_prev;
1427 free_session(sp);
1428 return;
1431 if ((pid = start_getty(sp)) == -1) {
1432 /* serious trouble */
1433 requested_transition = clean_ttys;
1434 return;
1437 sp->se_process = pid;
1438 (void)gettimeofday(&sp->se_started, NULL);
1439 add_session(sp);
1440 #endif /* LETS_GET_SMALL */
1444 * Catch a signal and request a state transition.
1446 void
1447 transition_handler(int sig)
1450 switch (sig) {
1451 #ifndef LETS_GET_SMALL
1452 case SIGHUP:
1453 requested_transition = clean_ttys;
1454 break;
1455 case SIGTERM:
1456 requested_transition = death;
1457 break;
1458 case SIGTSTP:
1459 requested_transition = catatonia;
1460 break;
1461 #endif /* LETS_GET_SMALL */
1462 default:
1463 requested_transition = 0;
1464 break;
1468 #ifndef LETS_GET_SMALL
1470 * Take the system multiuser.
1472 state_func_t
1473 multi_user(void)
1475 pid_t pid;
1476 int status;
1477 session_t *sp;
1479 requested_transition = 0;
1482 * If the administrator has not set the security level to -1
1483 * to indicate that the kernel should not run multiuser in secure
1484 * mode, and the run script has not set a higher level of security
1485 * than level 1, then put the kernel into secure mode.
1487 if (getsecuritylevel() == 0)
1488 setsecuritylevel(1);
1490 for (sp = sessions; sp; sp = sp->se_next) {
1491 if (sp->se_process)
1492 continue;
1493 if ((pid = start_getty(sp)) == -1) {
1494 /* serious trouble */
1495 requested_transition = clean_ttys;
1496 break;
1498 sp->se_process = pid;
1499 (void)gettimeofday(&sp->se_started, NULL);
1500 add_session(sp);
1503 while (!requested_transition)
1504 if ((pid = waitpid(-1, &status, 0)) != -1)
1505 collect_child(pid, status);
1507 return (state_func_t)requested_transition;
1511 * This is an n-squared algorithm. We hope it isn't run often...
1513 state_func_t
1514 clean_ttys(void)
1516 session_t *sp, *sprev;
1517 struct ttyent *typ;
1518 int session_index = 0;
1519 int devlen;
1521 for (sp = sessions; sp; sp = sp->se_next)
1522 sp->se_flags &= ~SE_PRESENT;
1524 (void)do_setttyent();
1526 devlen = sizeof(_PATH_DEV) - 1;
1527 while ((typ = getttyent()) != NULL) {
1528 ++session_index;
1530 for (sprev = 0, sp = sessions; sp; sprev = sp, sp = sp->se_next)
1531 if (strcmp(typ->ty_name, sp->se_device + devlen) == 0)
1532 break;
1534 if (sp) {
1535 sp->se_flags |= SE_PRESENT;
1536 if (sp->se_index != session_index) {
1537 warning("port `%s' changed utmp index from "
1538 "%d to %d", sp->se_device, sp->se_index,
1539 session_index);
1540 sp->se_index = session_index;
1542 if ((typ->ty_status & TTY_ON) == 0 ||
1543 typ->ty_getty == 0) {
1544 sp->se_flags |= SE_SHUTDOWN;
1545 if (sp->se_process != 0)
1546 (void)kill(sp->se_process, SIGHUP);
1547 continue;
1549 sp->se_flags &= ~SE_SHUTDOWN;
1550 if (setupargv(sp, typ) == 0) {
1551 warning("can't parse getty for port `%s'",
1552 sp->se_device);
1553 sp->se_flags |= SE_SHUTDOWN;
1554 if (sp->se_process != 0)
1555 (void)kill(sp->se_process, SIGHUP);
1557 continue;
1560 (void)new_session(sprev, session_index, typ);
1563 (void)endttyent();
1565 for (sp = sessions; sp; sp = sp->se_next)
1566 if ((sp->se_flags & SE_PRESENT) == 0) {
1567 sp->se_flags |= SE_SHUTDOWN;
1568 if (sp->se_process != 0)
1569 (void)kill(sp->se_process, SIGHUP);
1572 return (state_func_t)multi_user;
1576 * Block further logins.
1578 state_func_t
1579 catatonia(void)
1581 session_t *sp;
1583 for (sp = sessions; sp; sp = sp->se_next)
1584 sp->se_flags |= SE_SHUTDOWN;
1586 return (state_func_t)multi_user;
1588 #endif /* LETS_GET_SMALL */
1591 * Note SIGALRM.
1593 void
1594 /*ARGSUSED*/
1595 alrm_handler(int sig)
1598 clang = 1;
1601 #ifndef LETS_GET_SMALL
1603 * Bring the system down to single user.
1605 state_func_t
1606 death(void)
1608 session_t *sp;
1609 int i, status;
1610 pid_t pid;
1611 static const int death_sigs[3] = { SIGHUP, SIGTERM, SIGKILL };
1613 for (sp = sessions; sp; sp = sp->se_next)
1614 sp->se_flags |= SE_SHUTDOWN;
1616 /* NB: should send a message to the session logger to avoid blocking. */
1617 #ifdef SUPPORT_UTMPX
1618 logwtmpx("~", "shutdown", "", 0, INIT_PROCESS);
1619 #endif
1620 #ifdef SUPPORT_UTMP
1621 logwtmp("~", "shutdown", "");
1622 #endif
1624 for (i = 0; i < 3; ++i) {
1625 if (kill(-1, death_sigs[i]) == -1 && errno == ESRCH)
1626 return (state_func_t)single_user;
1628 clang = 0;
1629 (void)alarm(DEATH_WATCH);
1631 if ((pid = waitpid(-1, &status, 0)) != -1)
1632 collect_child(pid, status);
1633 while (clang == 0 && errno != ECHILD);
1635 if (errno == ECHILD)
1636 return (state_func_t)single_user;
1639 warning("some processes would not die; ps axl advised");
1641 return (state_func_t)single_user;
1643 #endif /* LETS_GET_SMALL */
1645 #ifdef MFS_DEV_IF_NO_CONSOLE
1647 static int
1648 mfs_dev(void)
1651 * We cannot print errors so we bail out silently...
1653 pid_t pid;
1654 int status;
1656 /* If we have /dev/console, assume all is OK */
1657 if (access(_PATH_CONSOLE, F_OK) == 0)
1658 return 0;
1660 #if 0 /* Useful for testing MAKEDEV */
1661 /* Mount an mfs over /mnt so we can create a console entry */
1662 switch ((pid = fork())) {
1663 case 0:
1664 (void)execl(INIT_MOUNT_MFS, "mount_mfs",
1665 "-b", "4096", "-f", "512",
1666 "-s", 64, "-n", 10,
1667 "-p", "0755",
1668 "swap", "/mnt", NULL);
1669 _exit(9);
1670 /*NOTREACHED*/
1672 case -1:
1673 return(-1);
1675 default:
1676 if (waitpid(pid, &status, 0) == -1)
1677 return(-1);
1678 if (status != 0)
1679 return(-1);
1680 break;
1684 dev_t dev;
1685 #ifdef CPU_CONSDEV
1686 static int name[2] = { CTL_MACHDEP, CPU_CONSDEV };
1687 size_t olen;
1688 olen = sizeof(dev);
1689 if (sysctl(name, sizeof(name) / sizeof(name[0]), &dev, &olen,
1690 NULL, 0) == -1)
1691 #endif
1692 dev = makedev(0, 0);
1694 /* Make a console for us, so we can see things happening */
1695 if (mknod("/mnt/console", 0666 | S_IFCHR, dev) == -1)
1696 return(-1);
1697 (void)freopen("/mnt/console", "a", stderr);
1700 #endif
1702 /* Run the makedev script to create devices */
1703 switch ((pid = fork())) {
1704 case 0:
1705 (void)dup2(2, 1); /* Give the script stdout */
1706 if (chdir("/dev") == 0)
1707 (void)execl(INIT_BSHELL, "sh",
1708 access("./MAKEDEV", X_OK) == 0
1709 ? "./MAKEDEV" : "/etc/MAKEDEV",
1710 "-MM", "init", NULL);
1711 _exit(10);
1712 /* NOTREACHED */
1714 case -1:
1715 break;
1717 default:
1718 if (waitpid(pid, &status, 0) == -1)
1719 break;
1720 if (status != 0)
1721 warn("MAKEDEV exit status %d\n", status);
1723 * If /dev/console got created, then return 0
1724 * regardless of MAKEDEV exit status.
1726 if (access(_PATH_CONSOLE, F_OK) == 0)
1727 return 0;
1728 _exit(11);
1730 warn("Unable to run MAKEDEV");
1731 _exit(12);
1733 #endif
1736 do_setttyent(void)
1738 (void)endttyent();
1739 #ifdef CHROOT
1740 if (did_multiuser_chroot) {
1741 char path[PATH_MAX];
1743 (void)snprintf(path, sizeof(path), "%s/%s", rootdir, _PATH_TTYS);
1745 return setttyentpath(path);
1746 } else
1747 #endif /* CHROOT */
1748 return setttyent();
1751 #if !defined(LETS_GET_SMALL) && defined(CHROOT)
1754 createsysctlnode()
1756 struct sysctlnode node;
1757 int mib[2];
1758 size_t len;
1761 * Create top-level dynamic sysctl node. Its child nodes will only
1762 * be readable by the superuser, since regular mortals should not
1763 * care ("Sssh, it's a secret!").
1765 len = sizeof(struct sysctlnode);
1766 mib[0] = CTL_CREATE;
1768 (void)memset(&node, 0, len);
1769 node.sysctl_flags = SYSCTL_VERSION | CTLFLAG_READWRITE |
1770 CTLFLAG_PRIVATE | CTLTYPE_NODE;
1771 node.sysctl_num = CTL_CREATE;
1772 (void)snprintf(node.sysctl_name, SYSCTL_NAMELEN, "init");
1773 if (sysctl(&mib[0], 1, &node, &len, &node, len) == -1) {
1774 warning("could not create init node: %m");
1775 return -1;
1779 * Create second level dynamic node capable of holding pathname.
1780 * Provide "/" as the default value.
1782 len = sizeof(struct sysctlnode);
1783 mib[0] = node.sysctl_num;
1784 mib[1] = CTL_CREATE;
1786 (void)memset(&node, 0, len);
1787 node.sysctl_flags = SYSCTL_VERSION | CTLFLAG_READWRITE |
1788 CTLTYPE_STRING | CTLFLAG_OWNDATA;
1789 node.sysctl_size = _POSIX_PATH_MAX;
1790 node.sysctl_data = __UNCONST("/");
1791 node.sysctl_num = CTL_CREATE;
1792 (void)snprintf(node.sysctl_name, SYSCTL_NAMELEN, "root");
1793 if (sysctl(&mib[0], 2, NULL, NULL, &node, len) == -1) {
1794 warning("could not create init.root node: %m");
1795 return -1;
1798 return 0;
1802 shouldchroot()
1804 struct sysctlnode node;
1805 size_t len, cnt;
1806 int mib;
1808 len = sizeof(struct sysctlnode);
1810 if (sysctlbyname("init.root", rootdir, &len, NULL, 0) == -1) {
1811 warning("could not read init.root: %m");
1813 /* Child killed our node. Recreate it. */
1814 if (errno == ENOENT) {
1815 /* Destroy whatever is left, recreate from scratch. */
1816 if (sysctlnametomib("init", &mib, &cnt) != -1) {
1817 (void)memset(&node, 0, sizeof(node));
1818 node.sysctl_flags = SYSCTL_VERSION;
1819 node.sysctl_num = mib;
1820 mib = CTL_DESTROY;
1822 (void)sysctl(&mib, 1, NULL, NULL, &node,
1823 sizeof(node));
1826 (void)createsysctlnode();
1829 /* We certainly won't chroot. */
1830 return 0;
1833 if (rootdir[len] != '\0' || strlen(rootdir) != len - 1) {
1834 warning("init.root is not a string");
1835 return 0;
1838 if (strcmp(rootdir, "/") == 0)
1839 return 0;
1841 return 1;
1844 #endif /* !LETS_GET_SMALL && CHROOT */