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