18fae3551SRodney W. Grimes /*- 28fae3551SRodney W. Grimes * Copyright (c) 1991, 1993 38fae3551SRodney W. Grimes * The Regents of the University of California. All rights reserved. 48fae3551SRodney W. Grimes * 58fae3551SRodney W. Grimes * This code is derived from software contributed to Berkeley by 68fae3551SRodney W. Grimes * Donn Seeley at Berkeley Software Design, Inc. 78fae3551SRodney W. Grimes * 88fae3551SRodney W. Grimes * Redistribution and use in source and binary forms, with or without 98fae3551SRodney W. Grimes * modification, are permitted provided that the following conditions 108fae3551SRodney W. Grimes * are met: 118fae3551SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 128fae3551SRodney W. Grimes * notice, this list of conditions and the following disclaimer. 138fae3551SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 148fae3551SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 158fae3551SRodney W. Grimes * documentation and/or other materials provided with the distribution. 168fae3551SRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 178fae3551SRodney W. Grimes * must display the following acknowledgement: 188fae3551SRodney W. Grimes * This product includes software developed by the University of 198fae3551SRodney W. Grimes * California, Berkeley and its contributors. 208fae3551SRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 218fae3551SRodney W. Grimes * may be used to endorse or promote products derived from this software 228fae3551SRodney W. Grimes * without specific prior written permission. 238fae3551SRodney W. Grimes * 248fae3551SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 258fae3551SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 268fae3551SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 278fae3551SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 288fae3551SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 298fae3551SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 308fae3551SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 318fae3551SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 328fae3551SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 338fae3551SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 348fae3551SRodney W. Grimes * SUCH DAMAGE. 358fae3551SRodney W. Grimes */ 368fae3551SRodney W. Grimes 378fae3551SRodney W. Grimes #ifndef lint 388fae3551SRodney W. Grimes static char copyright[] = 398fae3551SRodney W. Grimes "@(#) Copyright (c) 1991, 1993\n\ 408fae3551SRodney W. Grimes The Regents of the University of California. All rights reserved.\n"; 418fae3551SRodney W. Grimes #endif /* not lint */ 428fae3551SRodney W. Grimes 438fae3551SRodney W. Grimes #ifndef lint 448fae3551SRodney W. Grimes static char sccsid[] = "@(#)init.c 8.1 (Berkeley) 7/15/93"; 458fae3551SRodney W. Grimes #endif /* not lint */ 468fae3551SRodney W. Grimes 478fae3551SRodney W. Grimes #include <sys/param.h> 488fae3551SRodney W. Grimes #include <sys/sysctl.h> 498fae3551SRodney W. Grimes #include <sys/wait.h> 508fae3551SRodney W. Grimes 518fae3551SRodney W. Grimes #include <db.h> 528fae3551SRodney W. Grimes #include <errno.h> 538fae3551SRodney W. Grimes #include <fcntl.h> 548fae3551SRodney W. Grimes #include <signal.h> 558fae3551SRodney W. Grimes #include <stdio.h> 568fae3551SRodney W. Grimes #include <stdlib.h> 578fae3551SRodney W. Grimes #include <string.h> 588fae3551SRodney W. Grimes #include <syslog.h> 598fae3551SRodney W. Grimes #include <time.h> 608fae3551SRodney W. Grimes #include <ttyent.h> 618fae3551SRodney W. Grimes #include <unistd.h> 628fae3551SRodney W. Grimes 638fae3551SRodney W. Grimes #ifdef __STDC__ 648fae3551SRodney W. Grimes #include <stdarg.h> 658fae3551SRodney W. Grimes #else 668fae3551SRodney W. Grimes #include <varargs.h> 678fae3551SRodney W. Grimes #endif 688fae3551SRodney W. Grimes 698fae3551SRodney W. Grimes #ifdef SECURE 708fae3551SRodney W. Grimes #include <pwd.h> 718fae3551SRodney W. Grimes #endif 728fae3551SRodney W. Grimes 738fae3551SRodney W. Grimes #include "pathnames.h" 748fae3551SRodney W. Grimes 758fae3551SRodney W. Grimes /* 768fae3551SRodney W. Grimes * Until the mythical util.h arrives... 778fae3551SRodney W. Grimes */ 788fae3551SRodney W. Grimes extern int login_tty __P((int)); 798fae3551SRodney W. Grimes extern int logout __P((const char *)); 808fae3551SRodney W. Grimes extern void logwtmp __P((const char *, const char *, const char *)); 818fae3551SRodney W. Grimes 828fae3551SRodney W. Grimes /* 838fae3551SRodney W. Grimes * Sleep times; used to prevent thrashing. 848fae3551SRodney W. Grimes */ 858fae3551SRodney W. Grimes #define GETTY_SPACING 5 /* N secs minimum getty spacing */ 868fae3551SRodney W. Grimes #define GETTY_SLEEP 30 /* sleep N secs after spacing problem */ 878fae3551SRodney W. Grimes #define WINDOW_WAIT 3 /* wait N secs after starting window */ 888fae3551SRodney W. Grimes #define STALL_TIMEOUT 30 /* wait N secs after warning */ 898fae3551SRodney W. Grimes #define DEATH_WATCH 10 /* wait N secs for procs to die */ 908fae3551SRodney W. Grimes 918fae3551SRodney W. Grimes void handle __P((sig_t, ...)); 928fae3551SRodney W. Grimes void delset __P((sigset_t *, ...)); 938fae3551SRodney W. Grimes 948fae3551SRodney W. Grimes void stall __P((char *, ...)); 958fae3551SRodney W. Grimes void warning __P((char *, ...)); 968fae3551SRodney W. Grimes void emergency __P((char *, ...)); 978fae3551SRodney W. Grimes void disaster __P((int)); 988fae3551SRodney W. Grimes void badsys __P((int)); 998fae3551SRodney W. Grimes 1008fae3551SRodney W. Grimes /* 1018fae3551SRodney W. Grimes * We really need a recursive typedef... 1028fae3551SRodney W. Grimes * The following at least guarantees that the return type of (*state_t)() 1038fae3551SRodney W. Grimes * is sufficiently wide to hold a function pointer. 1048fae3551SRodney W. Grimes */ 1058fae3551SRodney W. Grimes typedef long (*state_func_t) __P((void)); 1068fae3551SRodney W. Grimes typedef state_func_t (*state_t) __P((void)); 1078fae3551SRodney W. Grimes 1088fae3551SRodney W. Grimes state_func_t single_user __P((void)); 1098fae3551SRodney W. Grimes state_func_t runcom __P((void)); 1108fae3551SRodney W. Grimes state_func_t read_ttys __P((void)); 1118fae3551SRodney W. Grimes state_func_t multi_user __P((void)); 1128fae3551SRodney W. Grimes state_func_t clean_ttys __P((void)); 1138fae3551SRodney W. Grimes state_func_t catatonia __P((void)); 1148fae3551SRodney W. Grimes state_func_t death __P((void)); 1158fae3551SRodney W. Grimes 1168fae3551SRodney W. Grimes enum { AUTOBOOT, FASTBOOT } runcom_mode = AUTOBOOT; 1178fae3551SRodney W. Grimes 1188fae3551SRodney W. Grimes void transition __P((state_t)); 1198fae3551SRodney W. Grimes state_t requested_transition = runcom; 1208fae3551SRodney W. Grimes 1218fae3551SRodney W. Grimes void setctty __P((char *)); 1228fae3551SRodney W. Grimes 1238fae3551SRodney W. Grimes typedef struct init_session { 1248fae3551SRodney W. Grimes int se_index; /* index of entry in ttys file */ 1258fae3551SRodney W. Grimes pid_t se_process; /* controlling process */ 1268fae3551SRodney W. Grimes time_t se_started; /* used to avoid thrashing */ 1278fae3551SRodney W. Grimes int se_flags; /* status of session */ 1288fae3551SRodney W. Grimes #define SE_SHUTDOWN 0x1 /* session won't be restarted */ 1298fae3551SRodney W. Grimes char *se_device; /* filename of port */ 1308fae3551SRodney W. Grimes char *se_getty; /* what to run on that port */ 1318fae3551SRodney W. Grimes char **se_getty_argv; /* pre-parsed argument array */ 1328fae3551SRodney W. Grimes char *se_window; /* window system (started only once) */ 1338fae3551SRodney W. Grimes char **se_window_argv; /* pre-parsed argument array */ 1348fae3551SRodney W. Grimes struct init_session *se_prev; 1358fae3551SRodney W. Grimes struct init_session *se_next; 1368fae3551SRodney W. Grimes } session_t; 1378fae3551SRodney W. Grimes 1388fae3551SRodney W. Grimes void free_session __P((session_t *)); 1398fae3551SRodney W. Grimes session_t *new_session __P((session_t *, int, struct ttyent *)); 1408fae3551SRodney W. Grimes session_t *sessions; 1418fae3551SRodney W. Grimes 1428fae3551SRodney W. Grimes char **construct_argv __P((char *)); 1438fae3551SRodney W. Grimes void start_window_system __P((session_t *)); 1448fae3551SRodney W. Grimes void collect_child __P((pid_t)); 1458fae3551SRodney W. Grimes pid_t start_getty __P((session_t *)); 1468fae3551SRodney W. Grimes void transition_handler __P((int)); 1478fae3551SRodney W. Grimes void alrm_handler __P((int)); 1488fae3551SRodney W. Grimes void setsecuritylevel __P((int)); 1498fae3551SRodney W. Grimes int getsecuritylevel __P((void)); 1508fae3551SRodney W. Grimes int setupargv __P((session_t *, struct ttyent *)); 1518fae3551SRodney W. Grimes int clang; 1528fae3551SRodney W. Grimes 1538fae3551SRodney W. Grimes void clear_session_logs __P((session_t *)); 1548fae3551SRodney W. Grimes 1558fae3551SRodney W. Grimes int start_session_db __P((void)); 1568fae3551SRodney W. Grimes void add_session __P((session_t *)); 1578fae3551SRodney W. Grimes void del_session __P((session_t *)); 1588fae3551SRodney W. Grimes session_t *find_session __P((pid_t)); 1598fae3551SRodney W. Grimes DB *session_db; 1608fae3551SRodney W. Grimes 1618fae3551SRodney W. Grimes /* 1628fae3551SRodney W. Grimes * The mother of all processes. 1638fae3551SRodney W. Grimes */ 1648fae3551SRodney W. Grimes int 1658fae3551SRodney W. Grimes main(argc, argv) 1668fae3551SRodney W. Grimes int argc; 1678fae3551SRodney W. Grimes char **argv; 1688fae3551SRodney W. Grimes { 1698fae3551SRodney W. Grimes int c; 1708fae3551SRodney W. Grimes struct sigaction sa; 1718fae3551SRodney W. Grimes sigset_t mask; 1728fae3551SRodney W. Grimes 1738fae3551SRodney W. Grimes 1748fae3551SRodney W. Grimes /* Dispose of random users. */ 1758fae3551SRodney W. Grimes if (getuid() != 0) { 1768fae3551SRodney W. Grimes (void)fprintf(stderr, "init: %s\n", strerror(EPERM)); 1778fae3551SRodney W. Grimes exit (1); 1788fae3551SRodney W. Grimes } 1798fae3551SRodney W. Grimes 1808fae3551SRodney W. Grimes /* System V users like to reexec init. */ 1818fae3551SRodney W. Grimes if (getpid() != 1) { 1828fae3551SRodney W. Grimes (void)fprintf(stderr, "init: already running\n"); 1838fae3551SRodney W. Grimes exit (1); 1848fae3551SRodney W. Grimes } 1858fae3551SRodney W. Grimes 1868fae3551SRodney W. Grimes /* 1878fae3551SRodney W. Grimes * Note that this does NOT open a file... 1888fae3551SRodney W. Grimes * Does 'init' deserve its own facility number? 1898fae3551SRodney W. Grimes */ 1908fae3551SRodney W. Grimes openlog("init", LOG_CONS|LOG_ODELAY, LOG_AUTH); 1918fae3551SRodney W. Grimes 1928fae3551SRodney W. Grimes /* 1938fae3551SRodney W. Grimes * Create an initial session. 1948fae3551SRodney W. Grimes */ 1958fae3551SRodney W. Grimes if (setsid() < 0) 1968fae3551SRodney W. Grimes warning("initial setsid() failed: %m"); 1978fae3551SRodney W. Grimes 1988fae3551SRodney W. Grimes /* 1998fae3551SRodney W. Grimes * Establish an initial user so that programs running 2008fae3551SRodney W. Grimes * single user do not freak out and die (like passwd). 2018fae3551SRodney W. Grimes */ 2028fae3551SRodney W. Grimes if (setlogin("root") < 0) 2038fae3551SRodney W. Grimes warning("setlogin() failed: %m"); 2048fae3551SRodney W. Grimes 2058fae3551SRodney W. Grimes /* 2068fae3551SRodney W. Grimes * This code assumes that we always get arguments through flags, 2078fae3551SRodney W. Grimes * never through bits set in some random machine register. 2088fae3551SRodney W. Grimes */ 2098fae3551SRodney W. Grimes while ((c = getopt(argc, argv, "sf")) != -1) 2108fae3551SRodney W. Grimes switch (c) { 2118fae3551SRodney W. Grimes case 's': 2128fae3551SRodney W. Grimes requested_transition = single_user; 2138fae3551SRodney W. Grimes break; 2148fae3551SRodney W. Grimes case 'f': 2158fae3551SRodney W. Grimes runcom_mode = FASTBOOT; 2168fae3551SRodney W. Grimes break; 2178fae3551SRodney W. Grimes default: 2188fae3551SRodney W. Grimes warning("unrecognized flag '-%c'", c); 2198fae3551SRodney W. Grimes break; 2208fae3551SRodney W. Grimes } 2218fae3551SRodney W. Grimes 2228fae3551SRodney W. Grimes if (optind != argc) 2238fae3551SRodney W. Grimes warning("ignoring excess arguments"); 2248fae3551SRodney W. Grimes 2258fae3551SRodney W. Grimes /* 2268fae3551SRodney W. Grimes * We catch or block signals rather than ignore them, 2278fae3551SRodney W. Grimes * so that they get reset on exec. 2288fae3551SRodney W. Grimes */ 2298fae3551SRodney W. Grimes handle(badsys, SIGSYS, 0); 2308fae3551SRodney W. Grimes handle(disaster, SIGABRT, SIGFPE, SIGILL, SIGSEGV, 2318fae3551SRodney W. Grimes SIGBUS, SIGXCPU, SIGXFSZ, 0); 2328fae3551SRodney W. Grimes handle(transition_handler, SIGHUP, SIGTERM, SIGTSTP, 0); 2338fae3551SRodney W. Grimes handle(alrm_handler, SIGALRM, 0); 2348fae3551SRodney W. Grimes sigfillset(&mask); 2358fae3551SRodney W. Grimes delset(&mask, SIGABRT, SIGFPE, SIGILL, SIGSEGV, SIGBUS, SIGSYS, 2368fae3551SRodney W. Grimes SIGXCPU, SIGXFSZ, SIGHUP, SIGTERM, SIGTSTP, SIGALRM, 0); 2378fae3551SRodney W. Grimes sigprocmask(SIG_SETMASK, &mask, (sigset_t *) 0); 2388fae3551SRodney W. Grimes sigemptyset(&sa.sa_mask); 2398fae3551SRodney W. Grimes sa.sa_flags = 0; 2408fae3551SRodney W. Grimes sa.sa_handler = SIG_IGN; 2418fae3551SRodney W. Grimes (void) sigaction(SIGTTIN, &sa, (struct sigaction *)0); 2428fae3551SRodney W. Grimes (void) sigaction(SIGTTOU, &sa, (struct sigaction *)0); 2438fae3551SRodney W. Grimes 2448fae3551SRodney W. Grimes /* 2458fae3551SRodney W. Grimes * Paranoia. 2468fae3551SRodney W. Grimes */ 2478fae3551SRodney W. Grimes close(0); 2488fae3551SRodney W. Grimes close(1); 2498fae3551SRodney W. Grimes close(2); 2508fae3551SRodney W. Grimes 2518fae3551SRodney W. Grimes /* 2528fae3551SRodney W. Grimes * Start the state machine. 2538fae3551SRodney W. Grimes */ 2548fae3551SRodney W. Grimes transition(requested_transition); 2558fae3551SRodney W. Grimes 2568fae3551SRodney W. Grimes /* 2578fae3551SRodney W. Grimes * Should never reach here. 2588fae3551SRodney W. Grimes */ 2598fae3551SRodney W. Grimes return 1; 2608fae3551SRodney W. Grimes } 2618fae3551SRodney W. Grimes 2628fae3551SRodney W. Grimes /* 2638fae3551SRodney W. Grimes * Associate a function with a signal handler. 2648fae3551SRodney W. Grimes */ 2658fae3551SRodney W. Grimes void 2668fae3551SRodney W. Grimes #ifdef __STDC__ 2678fae3551SRodney W. Grimes handle(sig_t handler, ...) 2688fae3551SRodney W. Grimes #else 2698fae3551SRodney W. Grimes handle(va_alist) 2708fae3551SRodney W. Grimes va_dcl 2718fae3551SRodney W. Grimes #endif 2728fae3551SRodney W. Grimes { 2738fae3551SRodney W. Grimes int sig; 2748fae3551SRodney W. Grimes struct sigaction sa; 2758fae3551SRodney W. Grimes int mask_everything; 2768fae3551SRodney W. Grimes va_list ap; 2778fae3551SRodney W. Grimes #ifndef __STDC__ 2788fae3551SRodney W. Grimes sig_t handler; 2798fae3551SRodney W. Grimes 2808fae3551SRodney W. Grimes va_start(ap); 2818fae3551SRodney W. Grimes handler = va_arg(ap, sig_t); 2828fae3551SRodney W. Grimes #else 2838fae3551SRodney W. Grimes va_start(ap, handler); 2848fae3551SRodney W. Grimes #endif 2858fae3551SRodney W. Grimes 2868fae3551SRodney W. Grimes sa.sa_handler = handler; 2878fae3551SRodney W. Grimes sigfillset(&mask_everything); 2888fae3551SRodney W. Grimes 2898fae3551SRodney W. Grimes while (sig = va_arg(ap, int)) { 2908fae3551SRodney W. Grimes sa.sa_mask = mask_everything; 2918fae3551SRodney W. Grimes /* XXX SA_RESTART? */ 2928fae3551SRodney W. Grimes sa.sa_flags = sig == SIGCHLD ? SA_NOCLDSTOP : 0; 2938fae3551SRodney W. Grimes sigaction(sig, &sa, (struct sigaction *) 0); 2948fae3551SRodney W. Grimes } 2958fae3551SRodney W. Grimes va_end(ap); 2968fae3551SRodney W. Grimes } 2978fae3551SRodney W. Grimes 2988fae3551SRodney W. Grimes /* 2998fae3551SRodney W. Grimes * Delete a set of signals from a mask. 3008fae3551SRodney W. Grimes */ 3018fae3551SRodney W. Grimes void 3028fae3551SRodney W. Grimes #ifdef __STDC__ 3038fae3551SRodney W. Grimes delset(sigset_t *maskp, ...) 3048fae3551SRodney W. Grimes #else 3058fae3551SRodney W. Grimes delset(va_alist) 3068fae3551SRodney W. Grimes va_dcl 3078fae3551SRodney W. Grimes #endif 3088fae3551SRodney W. Grimes { 3098fae3551SRodney W. Grimes int sig; 3108fae3551SRodney W. Grimes va_list ap; 3118fae3551SRodney W. Grimes #ifndef __STDC__ 3128fae3551SRodney W. Grimes sigset_t *maskp; 3138fae3551SRodney W. Grimes 3148fae3551SRodney W. Grimes va_start(ap); 3158fae3551SRodney W. Grimes maskp = va_arg(ap, sigset_t *); 3168fae3551SRodney W. Grimes #else 3178fae3551SRodney W. Grimes va_start(ap, maskp); 3188fae3551SRodney W. Grimes #endif 3198fae3551SRodney W. Grimes 3208fae3551SRodney W. Grimes while (sig = va_arg(ap, int)) 3218fae3551SRodney W. Grimes sigdelset(maskp, sig); 3228fae3551SRodney W. Grimes va_end(ap); 3238fae3551SRodney W. Grimes } 3248fae3551SRodney W. Grimes 3258fae3551SRodney W. Grimes /* 3268fae3551SRodney W. Grimes * Log a message and sleep for a while (to give someone an opportunity 3278fae3551SRodney W. Grimes * to read it and to save log or hardcopy output if the problem is chronic). 3288fae3551SRodney W. Grimes * NB: should send a message to the session logger to avoid blocking. 3298fae3551SRodney W. Grimes */ 3308fae3551SRodney W. Grimes void 3318fae3551SRodney W. Grimes #ifdef __STDC__ 3328fae3551SRodney W. Grimes stall(char *message, ...) 3338fae3551SRodney W. Grimes #else 3348fae3551SRodney W. Grimes stall(va_alist) 3358fae3551SRodney W. Grimes va_dcl 3368fae3551SRodney W. Grimes #endif 3378fae3551SRodney W. Grimes { 3388fae3551SRodney W. Grimes va_list ap; 3398fae3551SRodney W. Grimes #ifndef __STDC__ 3408fae3551SRodney W. Grimes char *message; 3418fae3551SRodney W. Grimes 3428fae3551SRodney W. Grimes va_start(ap); 3438fae3551SRodney W. Grimes message = va_arg(ap, char *); 3448fae3551SRodney W. Grimes #else 3458fae3551SRodney W. Grimes va_start(ap, message); 3468fae3551SRodney W. Grimes #endif 3478fae3551SRodney W. Grimes 3488fae3551SRodney W. Grimes vsyslog(LOG_ALERT, message, ap); 3498fae3551SRodney W. Grimes va_end(ap); 3508fae3551SRodney W. Grimes sleep(STALL_TIMEOUT); 3518fae3551SRodney W. Grimes } 3528fae3551SRodney W. Grimes 3538fae3551SRodney W. Grimes /* 3548fae3551SRodney W. Grimes * Like stall(), but doesn't sleep. 3558fae3551SRodney W. Grimes * If cpp had variadic macros, the two functions could be #defines for another. 3568fae3551SRodney W. Grimes * NB: should send a message to the session logger to avoid blocking. 3578fae3551SRodney W. Grimes */ 3588fae3551SRodney W. Grimes void 3598fae3551SRodney W. Grimes #ifdef __STDC__ 3608fae3551SRodney W. Grimes warning(char *message, ...) 3618fae3551SRodney W. Grimes #else 3628fae3551SRodney W. Grimes warning(va_alist) 3638fae3551SRodney W. Grimes va_dcl 3648fae3551SRodney W. Grimes #endif 3658fae3551SRodney W. Grimes { 3668fae3551SRodney W. Grimes va_list ap; 3678fae3551SRodney W. Grimes #ifndef __STDC__ 3688fae3551SRodney W. Grimes char *message; 3698fae3551SRodney W. Grimes 3708fae3551SRodney W. Grimes va_start(ap); 3718fae3551SRodney W. Grimes message = va_arg(ap, char *); 3728fae3551SRodney W. Grimes #else 3738fae3551SRodney W. Grimes va_start(ap, message); 3748fae3551SRodney W. Grimes #endif 3758fae3551SRodney W. Grimes 3768fae3551SRodney W. Grimes vsyslog(LOG_ALERT, message, ap); 3778fae3551SRodney W. Grimes va_end(ap); 3788fae3551SRodney W. Grimes } 3798fae3551SRodney W. Grimes 3808fae3551SRodney W. Grimes /* 3818fae3551SRodney W. Grimes * Log an emergency message. 3828fae3551SRodney W. Grimes * NB: should send a message to the session logger to avoid blocking. 3838fae3551SRodney W. Grimes */ 3848fae3551SRodney W. Grimes void 3858fae3551SRodney W. Grimes #ifdef __STDC__ 3868fae3551SRodney W. Grimes emergency(char *message, ...) 3878fae3551SRodney W. Grimes #else 3888fae3551SRodney W. Grimes emergency(va_alist) 3898fae3551SRodney W. Grimes va_dcl 3908fae3551SRodney W. Grimes #endif 3918fae3551SRodney W. Grimes { 3928fae3551SRodney W. Grimes va_list ap; 3938fae3551SRodney W. Grimes #ifndef __STDC__ 3948fae3551SRodney W. Grimes char *message; 3958fae3551SRodney W. Grimes 3968fae3551SRodney W. Grimes va_start(ap); 3978fae3551SRodney W. Grimes message = va_arg(ap, char *); 3988fae3551SRodney W. Grimes #else 3998fae3551SRodney W. Grimes va_start(ap, message); 4008fae3551SRodney W. Grimes #endif 4018fae3551SRodney W. Grimes 4028fae3551SRodney W. Grimes vsyslog(LOG_EMERG, message, ap); 4038fae3551SRodney W. Grimes va_end(ap); 4048fae3551SRodney W. Grimes } 4058fae3551SRodney W. Grimes 4068fae3551SRodney W. Grimes /* 4078fae3551SRodney W. Grimes * Catch a SIGSYS signal. 4088fae3551SRodney W. Grimes * 4098fae3551SRodney W. Grimes * These may arise if a system does not support sysctl. 4108fae3551SRodney W. Grimes * We tolerate up to 25 of these, then throw in the towel. 4118fae3551SRodney W. Grimes */ 4128fae3551SRodney W. Grimes void 4138fae3551SRodney W. Grimes badsys(sig) 4148fae3551SRodney W. Grimes int sig; 4158fae3551SRodney W. Grimes { 4168fae3551SRodney W. Grimes static int badcount = 0; 4178fae3551SRodney W. Grimes 4188fae3551SRodney W. Grimes if (badcount++ < 25) 4198fae3551SRodney W. Grimes return; 4208fae3551SRodney W. Grimes disaster(sig); 4218fae3551SRodney W. Grimes } 4228fae3551SRodney W. Grimes 4238fae3551SRodney W. Grimes /* 4248fae3551SRodney W. Grimes * Catch an unexpected signal. 4258fae3551SRodney W. Grimes */ 4268fae3551SRodney W. Grimes void 4278fae3551SRodney W. Grimes disaster(sig) 4288fae3551SRodney W. Grimes int sig; 4298fae3551SRodney W. Grimes { 4308fae3551SRodney W. Grimes emergency("fatal signal: %s", 4318fae3551SRodney W. Grimes sig < (unsigned) NSIG ? sys_siglist[sig] : "unknown signal"); 4328fae3551SRodney W. Grimes 4338fae3551SRodney W. Grimes sleep(STALL_TIMEOUT); 4348fae3551SRodney W. Grimes _exit(sig); /* reboot */ 4358fae3551SRodney W. Grimes } 4368fae3551SRodney W. Grimes 4378fae3551SRodney W. Grimes /* 4388fae3551SRodney W. Grimes * Get the security level of the kernel. 4398fae3551SRodney W. Grimes */ 4408fae3551SRodney W. Grimes int 4418fae3551SRodney W. Grimes getsecuritylevel() 4428fae3551SRodney W. Grimes { 4438fae3551SRodney W. Grimes #ifdef KERN_SECURELVL 4448fae3551SRodney W. Grimes int name[2], curlevel; 4458fae3551SRodney W. Grimes size_t len; 4468fae3551SRodney W. Grimes extern int errno; 4478fae3551SRodney W. Grimes 4488fae3551SRodney W. Grimes name[0] = CTL_KERN; 4498fae3551SRodney W. Grimes name[1] = KERN_SECURELVL; 4508fae3551SRodney W. Grimes len = sizeof curlevel; 4518fae3551SRodney W. Grimes if (sysctl(name, 2, &curlevel, &len, NULL, 0) == -1) { 4528fae3551SRodney W. Grimes emergency("cannot get kernel security level: %s", 4538fae3551SRodney W. Grimes strerror(errno)); 4548fae3551SRodney W. Grimes return (-1); 4558fae3551SRodney W. Grimes } 4568fae3551SRodney W. Grimes return (curlevel); 4578fae3551SRodney W. Grimes #else 4588fae3551SRodney W. Grimes return (-1); 4598fae3551SRodney W. Grimes #endif 4608fae3551SRodney W. Grimes } 4618fae3551SRodney W. Grimes 4628fae3551SRodney W. Grimes /* 4638fae3551SRodney W. Grimes * Set the security level of the kernel. 4648fae3551SRodney W. Grimes */ 4658fae3551SRodney W. Grimes void 4668fae3551SRodney W. Grimes setsecuritylevel(newlevel) 4678fae3551SRodney W. Grimes int newlevel; 4688fae3551SRodney W. Grimes { 4698fae3551SRodney W. Grimes #ifdef KERN_SECURELVL 4708fae3551SRodney W. Grimes int name[2], curlevel; 4718fae3551SRodney W. Grimes extern int errno; 4728fae3551SRodney W. Grimes 4738fae3551SRodney W. Grimes curlevel = getsecuritylevel(); 4748fae3551SRodney W. Grimes if (newlevel == curlevel) 4758fae3551SRodney W. Grimes return; 4768fae3551SRodney W. Grimes name[0] = CTL_KERN; 4778fae3551SRodney W. Grimes name[1] = KERN_SECURELVL; 4788fae3551SRodney W. Grimes if (sysctl(name, 2, NULL, NULL, &newlevel, sizeof newlevel) == -1) { 4798fae3551SRodney W. Grimes emergency( 4808fae3551SRodney W. Grimes "cannot change kernel security level from %d to %d: %s", 4818fae3551SRodney W. Grimes curlevel, newlevel, strerror(errno)); 4828fae3551SRodney W. Grimes return; 4838fae3551SRodney W. Grimes } 4848fae3551SRodney W. Grimes #ifdef SECURE 4858fae3551SRodney W. Grimes warning("kernel security level changed from %d to %d", 4868fae3551SRodney W. Grimes curlevel, newlevel); 4878fae3551SRodney W. Grimes #endif 4888fae3551SRodney W. Grimes #endif 4898fae3551SRodney W. Grimes } 4908fae3551SRodney W. Grimes 4918fae3551SRodney W. Grimes /* 4928fae3551SRodney W. Grimes * Change states in the finite state machine. 4938fae3551SRodney W. Grimes * The initial state is passed as an argument. 4948fae3551SRodney W. Grimes */ 4958fae3551SRodney W. Grimes void 4968fae3551SRodney W. Grimes transition(s) 4978fae3551SRodney W. Grimes state_t s; 4988fae3551SRodney W. Grimes { 4998fae3551SRodney W. Grimes for (;;) 5008fae3551SRodney W. Grimes s = (state_t) (*s)(); 5018fae3551SRodney W. Grimes } 5028fae3551SRodney W. Grimes 5038fae3551SRodney W. Grimes /* 5048fae3551SRodney W. Grimes * Close out the accounting files for a login session. 5058fae3551SRodney W. Grimes * NB: should send a message to the session logger to avoid blocking. 5068fae3551SRodney W. Grimes */ 5078fae3551SRodney W. Grimes void 5088fae3551SRodney W. Grimes clear_session_logs(sp) 5098fae3551SRodney W. Grimes session_t *sp; 5108fae3551SRodney W. Grimes { 5118fae3551SRodney W. Grimes char *line = sp->se_device + sizeof(_PATH_DEV) - 1; 5128fae3551SRodney W. Grimes 5138fae3551SRodney W. Grimes if (logout(line)) 5148fae3551SRodney W. Grimes logwtmp(line, "", ""); 5158fae3551SRodney W. Grimes } 5168fae3551SRodney W. Grimes 5178fae3551SRodney W. Grimes /* 5188fae3551SRodney W. Grimes * Start a session and allocate a controlling terminal. 5198fae3551SRodney W. Grimes * Only called by children of init after forking. 5208fae3551SRodney W. Grimes */ 5218fae3551SRodney W. Grimes void 5228fae3551SRodney W. Grimes setctty(name) 5238fae3551SRodney W. Grimes char *name; 5248fae3551SRodney W. Grimes { 5258fae3551SRodney W. Grimes int fd; 5268fae3551SRodney W. Grimes 5278fae3551SRodney W. Grimes (void) revoke(name); 5288fae3551SRodney W. Grimes sleep (2); /* leave DTR low */ 5298fae3551SRodney W. Grimes if ((fd = open(name, O_RDWR)) == -1) { 5308fae3551SRodney W. Grimes stall("can't open %s: %m", name); 5318fae3551SRodney W. Grimes _exit(1); 5328fae3551SRodney W. Grimes } 5338fae3551SRodney W. Grimes if (login_tty(fd) == -1) { 5348fae3551SRodney W. Grimes stall("can't get %s for controlling terminal: %m", name); 5358fae3551SRodney W. Grimes _exit(1); 5368fae3551SRodney W. Grimes } 5378fae3551SRodney W. Grimes } 5388fae3551SRodney W. Grimes 5398fae3551SRodney W. Grimes /* 5408fae3551SRodney W. Grimes * Bring the system up single user. 5418fae3551SRodney W. Grimes */ 5428fae3551SRodney W. Grimes state_func_t 5438fae3551SRodney W. Grimes single_user() 5448fae3551SRodney W. Grimes { 5458fae3551SRodney W. Grimes pid_t pid, wpid; 5468fae3551SRodney W. Grimes int status; 5478fae3551SRodney W. Grimes sigset_t mask; 5488fae3551SRodney W. Grimes char *shell = _PATH_BSHELL; 5498fae3551SRodney W. Grimes char *argv[2]; 5508fae3551SRodney W. Grimes #ifdef SECURE 5518fae3551SRodney W. Grimes struct ttyent *typ; 5528fae3551SRodney W. Grimes struct passwd *pp; 5538fae3551SRodney W. Grimes static const char banner[] = 5548fae3551SRodney W. Grimes "Enter root password, or ^D to go multi-user\n"; 5558fae3551SRodney W. Grimes char *clear, *password; 5568fae3551SRodney W. Grimes #endif 5578fae3551SRodney W. Grimes 5588fae3551SRodney W. Grimes /* 5598fae3551SRodney W. Grimes * If the kernel is in secure mode, downgrade it to insecure mode. 5608fae3551SRodney W. Grimes */ 5618fae3551SRodney W. Grimes if (getsecuritylevel() > 0) 5628fae3551SRodney W. Grimes setsecuritylevel(0); 5638fae3551SRodney W. Grimes 5648fae3551SRodney W. Grimes if ((pid = fork()) == 0) { 5658fae3551SRodney W. Grimes /* 5668fae3551SRodney W. Grimes * Start the single user session. 5678fae3551SRodney W. Grimes */ 5688fae3551SRodney W. Grimes setctty(_PATH_CONSOLE); 5698fae3551SRodney W. Grimes 5708fae3551SRodney W. Grimes #ifdef SECURE 5718fae3551SRodney W. Grimes /* 5728fae3551SRodney W. Grimes * Check the root password. 5738fae3551SRodney W. Grimes * We don't care if the console is 'on' by default; 5748fae3551SRodney W. Grimes * it's the only tty that can be 'off' and 'secure'. 5758fae3551SRodney W. Grimes */ 5768fae3551SRodney W. Grimes typ = getttynam("console"); 5778fae3551SRodney W. Grimes pp = getpwnam("root"); 5788fae3551SRodney W. Grimes if (typ && (typ->ty_status & TTY_SECURE) == 0 && pp) { 5798fae3551SRodney W. Grimes write(2, banner, sizeof banner - 1); 5808fae3551SRodney W. Grimes for (;;) { 5818fae3551SRodney W. Grimes clear = getpass("Password:"); 5828fae3551SRodney W. Grimes if (clear == 0 || *clear == '\0') 5838fae3551SRodney W. Grimes _exit(0); 5848fae3551SRodney W. Grimes password = crypt(clear, pp->pw_passwd); 5858fae3551SRodney W. Grimes bzero(clear, _PASSWORD_LEN); 5868fae3551SRodney W. Grimes if (strcmp(password, pp->pw_passwd) == 0) 5878fae3551SRodney W. Grimes break; 5888fae3551SRodney W. Grimes warning("single-user login failed\n"); 5898fae3551SRodney W. Grimes } 5908fae3551SRodney W. Grimes } 5918fae3551SRodney W. Grimes endttyent(); 5928fae3551SRodney W. Grimes endpwent(); 5938fae3551SRodney W. Grimes #endif /* SECURE */ 5948fae3551SRodney W. Grimes 5958fae3551SRodney W. Grimes #ifdef DEBUGSHELL 5968fae3551SRodney W. Grimes { 5978fae3551SRodney W. Grimes char altshell[128], *cp = altshell; 5988fae3551SRodney W. Grimes int num; 5998fae3551SRodney W. Grimes 6008fae3551SRodney W. Grimes #define SHREQUEST \ 6018fae3551SRodney W. Grimes "Enter pathname of shell or RETURN for sh: " 6028fae3551SRodney W. Grimes (void)write(STDERR_FILENO, 6038fae3551SRodney W. Grimes SHREQUEST, sizeof(SHREQUEST) - 1); 6048fae3551SRodney W. Grimes while ((num = read(STDIN_FILENO, cp, 1)) != -1 && 6058fae3551SRodney W. Grimes num != 0 && *cp != '\n' && cp < &altshell[127]) 6068fae3551SRodney W. Grimes cp++; 6078fae3551SRodney W. Grimes *cp = '\0'; 6088fae3551SRodney W. Grimes if (altshell[0] != '\0') 6098fae3551SRodney W. Grimes shell = altshell; 6108fae3551SRodney W. Grimes } 6118fae3551SRodney W. Grimes #endif /* DEBUGSHELL */ 6128fae3551SRodney W. Grimes 6138fae3551SRodney W. Grimes /* 6148fae3551SRodney W. Grimes * Unblock signals. 6158fae3551SRodney W. Grimes * We catch all the interesting ones, 6168fae3551SRodney W. Grimes * and those are reset to SIG_DFL on exec. 6178fae3551SRodney W. Grimes */ 6188fae3551SRodney W. Grimes sigemptyset(&mask); 6198fae3551SRodney W. Grimes sigprocmask(SIG_SETMASK, &mask, (sigset_t *) 0); 6208fae3551SRodney W. Grimes 6218fae3551SRodney W. Grimes /* 6228fae3551SRodney W. Grimes * Fire off a shell. 6238fae3551SRodney W. Grimes * If the default one doesn't work, try the Bourne shell. 6248fae3551SRodney W. Grimes */ 6258fae3551SRodney W. Grimes argv[0] = "-sh"; 6268fae3551SRodney W. Grimes argv[1] = 0; 6278fae3551SRodney W. Grimes execv(shell, argv); 6288fae3551SRodney W. Grimes emergency("can't exec %s for single user: %m", shell); 6298fae3551SRodney W. Grimes execv(_PATH_BSHELL, argv); 6308fae3551SRodney W. Grimes emergency("can't exec %s for single user: %m", _PATH_BSHELL); 6318fae3551SRodney W. Grimes sleep(STALL_TIMEOUT); 6328fae3551SRodney W. Grimes _exit(1); 6338fae3551SRodney W. Grimes } 6348fae3551SRodney W. Grimes 6358fae3551SRodney W. Grimes if (pid == -1) { 6368fae3551SRodney W. Grimes /* 6378fae3551SRodney W. Grimes * We are seriously hosed. Do our best. 6388fae3551SRodney W. Grimes */ 6398fae3551SRodney W. Grimes emergency("can't fork single-user shell, trying again"); 6408fae3551SRodney W. Grimes while (waitpid(-1, (int *) 0, WNOHANG) > 0) 6418fae3551SRodney W. Grimes continue; 6428fae3551SRodney W. Grimes return (state_func_t) single_user; 6438fae3551SRodney W. Grimes } 6448fae3551SRodney W. Grimes 6458fae3551SRodney W. Grimes requested_transition = 0; 6468fae3551SRodney W. Grimes do { 6478fae3551SRodney W. Grimes if ((wpid = waitpid(-1, &status, WUNTRACED)) != -1) 6488fae3551SRodney W. Grimes collect_child(wpid); 6498fae3551SRodney W. Grimes if (wpid == -1) { 6508fae3551SRodney W. Grimes if (errno == EINTR) 6518fae3551SRodney W. Grimes continue; 6528fae3551SRodney W. Grimes warning("wait for single-user shell failed: %m; restarting"); 6538fae3551SRodney W. Grimes return (state_func_t) single_user; 6548fae3551SRodney W. Grimes } 6558fae3551SRodney W. Grimes if (wpid == pid && WIFSTOPPED(status)) { 6568fae3551SRodney W. Grimes warning("init: shell stopped, restarting\n"); 6578fae3551SRodney W. Grimes kill(pid, SIGCONT); 6588fae3551SRodney W. Grimes wpid = -1; 6598fae3551SRodney W. Grimes } 6608fae3551SRodney W. Grimes } while (wpid != pid && !requested_transition); 6618fae3551SRodney W. Grimes 6628fae3551SRodney W. Grimes if (requested_transition) 6638fae3551SRodney W. Grimes return (state_func_t) requested_transition; 6648fae3551SRodney W. Grimes 6658fae3551SRodney W. Grimes if (!WIFEXITED(status)) { 6668fae3551SRodney W. Grimes if (WTERMSIG(status) == SIGKILL) { 6678fae3551SRodney W. Grimes /* 6688fae3551SRodney W. Grimes * reboot(8) killed shell? 6698fae3551SRodney W. Grimes */ 6708fae3551SRodney W. Grimes warning("single user shell terminated."); 6718fae3551SRodney W. Grimes sleep(STALL_TIMEOUT); 6728fae3551SRodney W. Grimes _exit(0); 6738fae3551SRodney W. Grimes } else { 6748fae3551SRodney W. Grimes warning("single user shell terminated, restarting"); 6758fae3551SRodney W. Grimes return (state_func_t) single_user; 6768fae3551SRodney W. Grimes } 6778fae3551SRodney W. Grimes } 6788fae3551SRodney W. Grimes 6798fae3551SRodney W. Grimes runcom_mode = FASTBOOT; 6808fae3551SRodney W. Grimes return (state_func_t) runcom; 6818fae3551SRodney W. Grimes } 6828fae3551SRodney W. Grimes 6838fae3551SRodney W. Grimes /* 6848fae3551SRodney W. Grimes * Run the system startup script. 6858fae3551SRodney W. Grimes */ 6868fae3551SRodney W. Grimes state_func_t 6878fae3551SRodney W. Grimes runcom() 6888fae3551SRodney W. Grimes { 6898fae3551SRodney W. Grimes pid_t pid, wpid; 6908fae3551SRodney W. Grimes int status; 6918fae3551SRodney W. Grimes char *argv[4]; 6928fae3551SRodney W. Grimes struct sigaction sa; 6938fae3551SRodney W. Grimes 6948fae3551SRodney W. Grimes if ((pid = fork()) == 0) { 6958fae3551SRodney W. Grimes sigemptyset(&sa.sa_mask); 6968fae3551SRodney W. Grimes sa.sa_flags = 0; 6978fae3551SRodney W. Grimes sa.sa_handler = SIG_IGN; 6988fae3551SRodney W. Grimes (void) sigaction(SIGTSTP, &sa, (struct sigaction *)0); 6998fae3551SRodney W. Grimes (void) sigaction(SIGHUP, &sa, (struct sigaction *)0); 7008fae3551SRodney W. Grimes 7018fae3551SRodney W. Grimes setctty(_PATH_CONSOLE); 7028fae3551SRodney W. Grimes 7038fae3551SRodney W. Grimes argv[0] = "sh"; 7048fae3551SRodney W. Grimes argv[1] = _PATH_RUNCOM; 7058fae3551SRodney W. Grimes argv[2] = runcom_mode == AUTOBOOT ? "autoboot" : 0; 7068fae3551SRodney W. Grimes argv[3] = 0; 7078fae3551SRodney W. Grimes 7088fae3551SRodney W. Grimes sigprocmask(SIG_SETMASK, &sa.sa_mask, (sigset_t *) 0); 7098fae3551SRodney W. Grimes 7108fae3551SRodney W. Grimes execv(_PATH_BSHELL, argv); 7118fae3551SRodney W. Grimes stall("can't exec %s for %s: %m", _PATH_BSHELL, _PATH_RUNCOM); 7128fae3551SRodney W. Grimes _exit(1); /* force single user mode */ 7138fae3551SRodney W. Grimes } 7148fae3551SRodney W. Grimes 7158fae3551SRodney W. Grimes if (pid == -1) { 7168fae3551SRodney W. Grimes emergency("can't fork for %s on %s: %m", 7178fae3551SRodney W. Grimes _PATH_BSHELL, _PATH_RUNCOM); 7188fae3551SRodney W. Grimes while (waitpid(-1, (int *) 0, WNOHANG) > 0) 7198fae3551SRodney W. Grimes continue; 7208fae3551SRodney W. Grimes sleep(STALL_TIMEOUT); 7218fae3551SRodney W. Grimes return (state_func_t) single_user; 7228fae3551SRodney W. Grimes } 7238fae3551SRodney W. Grimes 7248fae3551SRodney W. Grimes /* 7258fae3551SRodney W. Grimes * Copied from single_user(). This is a bit paranoid. 7268fae3551SRodney W. Grimes */ 7278fae3551SRodney W. Grimes do { 7288fae3551SRodney W. Grimes if ((wpid = waitpid(-1, &status, WUNTRACED)) != -1) 7298fae3551SRodney W. Grimes collect_child(wpid); 7308fae3551SRodney W. Grimes if (wpid == -1) { 7318fae3551SRodney W. Grimes if (errno == EINTR) 7328fae3551SRodney W. Grimes continue; 7338fae3551SRodney W. Grimes warning("wait for %s on %s failed: %m; going to single user mode", 7348fae3551SRodney W. Grimes _PATH_BSHELL, _PATH_RUNCOM); 7358fae3551SRodney W. Grimes return (state_func_t) single_user; 7368fae3551SRodney W. Grimes } 7378fae3551SRodney W. Grimes if (wpid == pid && WIFSTOPPED(status)) { 7388fae3551SRodney W. Grimes warning("init: %s on %s stopped, restarting\n", 7398fae3551SRodney W. Grimes _PATH_BSHELL, _PATH_RUNCOM); 7408fae3551SRodney W. Grimes kill(pid, SIGCONT); 7418fae3551SRodney W. Grimes wpid = -1; 7428fae3551SRodney W. Grimes } 7438fae3551SRodney W. Grimes } while (wpid != pid); 7448fae3551SRodney W. Grimes 7458fae3551SRodney W. Grimes if (WIFSIGNALED(status) && WTERMSIG(status) == SIGTERM && 7468fae3551SRodney W. Grimes requested_transition == catatonia) { 7478fae3551SRodney W. Grimes /* /etc/rc executed /sbin/reboot; wait for the end quietly */ 7488fae3551SRodney W. Grimes sigset_t s; 7498fae3551SRodney W. Grimes 7508fae3551SRodney W. Grimes sigfillset(&s); 7518fae3551SRodney W. Grimes for (;;) 7528fae3551SRodney W. Grimes sigsuspend(&s); 7538fae3551SRodney W. Grimes } 7548fae3551SRodney W. Grimes 7558fae3551SRodney W. Grimes if (!WIFEXITED(status)) { 7568fae3551SRodney W. Grimes warning("%s on %s terminated abnormally, going to single user mode", 7578fae3551SRodney W. Grimes _PATH_BSHELL, _PATH_RUNCOM); 7588fae3551SRodney W. Grimes return (state_func_t) single_user; 7598fae3551SRodney W. Grimes } 7608fae3551SRodney W. Grimes 7618fae3551SRodney W. Grimes if (WEXITSTATUS(status)) 7628fae3551SRodney W. Grimes return (state_func_t) single_user; 7638fae3551SRodney W. Grimes 7648fae3551SRodney W. Grimes runcom_mode = AUTOBOOT; /* the default */ 7658fae3551SRodney W. Grimes /* NB: should send a message to the session logger to avoid blocking. */ 7668fae3551SRodney W. Grimes logwtmp("~", "reboot", ""); 7678fae3551SRodney W. Grimes return (state_func_t) read_ttys; 7688fae3551SRodney W. Grimes } 7698fae3551SRodney W. Grimes 7708fae3551SRodney W. Grimes /* 7718fae3551SRodney W. Grimes * Open the session database. 7728fae3551SRodney W. Grimes * 7738fae3551SRodney W. Grimes * NB: We could pass in the size here; is it necessary? 7748fae3551SRodney W. Grimes */ 7758fae3551SRodney W. Grimes int 7768fae3551SRodney W. Grimes start_session_db() 7778fae3551SRodney W. Grimes { 7788fae3551SRodney W. Grimes if (session_db && (*session_db->close)(session_db)) 7798fae3551SRodney W. Grimes emergency("session database close: %s", strerror(errno)); 7808fae3551SRodney W. Grimes if ((session_db = dbopen(NULL, O_RDWR, 0, DB_HASH, NULL)) == 0) { 7818fae3551SRodney W. Grimes emergency("session database open: %s", strerror(errno)); 7828fae3551SRodney W. Grimes return (1); 7838fae3551SRodney W. Grimes } 7848fae3551SRodney W. Grimes return (0); 7858fae3551SRodney W. Grimes 7868fae3551SRodney W. Grimes } 7878fae3551SRodney W. Grimes 7888fae3551SRodney W. Grimes /* 7898fae3551SRodney W. Grimes * Add a new login session. 7908fae3551SRodney W. Grimes */ 7918fae3551SRodney W. Grimes void 7928fae3551SRodney W. Grimes add_session(sp) 7938fae3551SRodney W. Grimes session_t *sp; 7948fae3551SRodney W. Grimes { 7958fae3551SRodney W. Grimes DBT key; 7968fae3551SRodney W. Grimes DBT data; 7978fae3551SRodney W. Grimes 7988fae3551SRodney W. Grimes key.data = &sp->se_process; 7998fae3551SRodney W. Grimes key.size = sizeof sp->se_process; 8008fae3551SRodney W. Grimes data.data = &sp; 8018fae3551SRodney W. Grimes data.size = sizeof sp; 8028fae3551SRodney W. Grimes 8038fae3551SRodney W. Grimes if ((*session_db->put)(session_db, &key, &data, 0)) 8048fae3551SRodney W. Grimes emergency("insert %d: %s", sp->se_process, strerror(errno)); 8058fae3551SRodney W. Grimes } 8068fae3551SRodney W. Grimes 8078fae3551SRodney W. Grimes /* 8088fae3551SRodney W. Grimes * Delete an old login session. 8098fae3551SRodney W. Grimes */ 8108fae3551SRodney W. Grimes void 8118fae3551SRodney W. Grimes del_session(sp) 8128fae3551SRodney W. Grimes session_t *sp; 8138fae3551SRodney W. Grimes { 8148fae3551SRodney W. Grimes DBT key; 8158fae3551SRodney W. Grimes 8168fae3551SRodney W. Grimes key.data = &sp->se_process; 8178fae3551SRodney W. Grimes key.size = sizeof sp->se_process; 8188fae3551SRodney W. Grimes 8198fae3551SRodney W. Grimes if ((*session_db->del)(session_db, &key, 0)) 8208fae3551SRodney W. Grimes emergency("delete %d: %s", sp->se_process, strerror(errno)); 8218fae3551SRodney W. Grimes } 8228fae3551SRodney W. Grimes 8238fae3551SRodney W. Grimes /* 8248fae3551SRodney W. Grimes * Look up a login session by pid. 8258fae3551SRodney W. Grimes */ 8268fae3551SRodney W. Grimes session_t * 8278fae3551SRodney W. Grimes #ifdef __STDC__ 8288fae3551SRodney W. Grimes find_session(pid_t pid) 8298fae3551SRodney W. Grimes #else 8308fae3551SRodney W. Grimes find_session(pid) 8318fae3551SRodney W. Grimes pid_t pid; 8328fae3551SRodney W. Grimes #endif 8338fae3551SRodney W. Grimes { 8348fae3551SRodney W. Grimes DBT key; 8358fae3551SRodney W. Grimes DBT data; 8368fae3551SRodney W. Grimes session_t *ret; 8378fae3551SRodney W. Grimes 8388fae3551SRodney W. Grimes key.data = &pid; 8398fae3551SRodney W. Grimes key.size = sizeof pid; 8408fae3551SRodney W. Grimes if ((*session_db->get)(session_db, &key, &data, 0) != 0) 8418fae3551SRodney W. Grimes return 0; 8428fae3551SRodney W. Grimes bcopy(data.data, (char *)&ret, sizeof(ret)); 8438fae3551SRodney W. Grimes return ret; 8448fae3551SRodney W. Grimes } 8458fae3551SRodney W. Grimes 8468fae3551SRodney W. Grimes /* 8478fae3551SRodney W. Grimes * Construct an argument vector from a command line. 8488fae3551SRodney W. Grimes */ 8498fae3551SRodney W. Grimes char ** 8508fae3551SRodney W. Grimes construct_argv(command) 8518fae3551SRodney W. Grimes char *command; 8528fae3551SRodney W. Grimes { 8538fae3551SRodney W. Grimes register int argc = 0; 8548fae3551SRodney W. Grimes register char **argv = (char **) malloc(((strlen(command) + 1) / 2 + 1) 8558fae3551SRodney W. Grimes * sizeof (char *)); 8568fae3551SRodney W. Grimes static const char separators[] = " \t"; 8578fae3551SRodney W. Grimes 8588fae3551SRodney W. Grimes if ((argv[argc++] = strtok(command, separators)) == 0) 8598fae3551SRodney W. Grimes return 0; 8608fae3551SRodney W. Grimes while (argv[argc++] = strtok((char *) 0, separators)) 8618fae3551SRodney W. Grimes continue; 8628fae3551SRodney W. Grimes return argv; 8638fae3551SRodney W. Grimes } 8648fae3551SRodney W. Grimes 8658fae3551SRodney W. Grimes /* 8668fae3551SRodney W. Grimes * Deallocate a session descriptor. 8678fae3551SRodney W. Grimes */ 8688fae3551SRodney W. Grimes void 8698fae3551SRodney W. Grimes free_session(sp) 8708fae3551SRodney W. Grimes register session_t *sp; 8718fae3551SRodney W. Grimes { 8728fae3551SRodney W. Grimes free(sp->se_device); 8738fae3551SRodney W. Grimes if (sp->se_getty) { 8748fae3551SRodney W. Grimes free(sp->se_getty); 8758fae3551SRodney W. Grimes free(sp->se_getty_argv); 8768fae3551SRodney W. Grimes } 8778fae3551SRodney W. Grimes if (sp->se_window) { 8788fae3551SRodney W. Grimes free(sp->se_window); 8798fae3551SRodney W. Grimes free(sp->se_window_argv); 8808fae3551SRodney W. Grimes } 8818fae3551SRodney W. Grimes free(sp); 8828fae3551SRodney W. Grimes } 8838fae3551SRodney W. Grimes 8848fae3551SRodney W. Grimes /* 8858fae3551SRodney W. Grimes * Allocate a new session descriptor. 8868fae3551SRodney W. Grimes */ 8878fae3551SRodney W. Grimes session_t * 8888fae3551SRodney W. Grimes new_session(sprev, session_index, typ) 8898fae3551SRodney W. Grimes session_t *sprev; 8908fae3551SRodney W. Grimes int session_index; 8918fae3551SRodney W. Grimes register struct ttyent *typ; 8928fae3551SRodney W. Grimes { 8938fae3551SRodney W. Grimes register session_t *sp; 8948fae3551SRodney W. Grimes 8958fae3551SRodney W. Grimes if ((typ->ty_status & TTY_ON) == 0 || 8968fae3551SRodney W. Grimes typ->ty_name == 0 || 8978fae3551SRodney W. Grimes typ->ty_getty == 0) 8988fae3551SRodney W. Grimes return 0; 8998fae3551SRodney W. Grimes 9008fae3551SRodney W. Grimes sp = (session_t *) malloc(sizeof (session_t)); 9018fae3551SRodney W. Grimes bzero(sp, sizeof *sp); 9028fae3551SRodney W. Grimes 9038fae3551SRodney W. Grimes sp->se_index = session_index; 9048fae3551SRodney W. Grimes 9058fae3551SRodney W. Grimes sp->se_device = malloc(sizeof(_PATH_DEV) + strlen(typ->ty_name)); 9068fae3551SRodney W. Grimes (void) sprintf(sp->se_device, "%s%s", _PATH_DEV, typ->ty_name); 9078fae3551SRodney W. Grimes 9088fae3551SRodney W. Grimes if (setupargv(sp, typ) == 0) { 9098fae3551SRodney W. Grimes free_session(sp); 9108fae3551SRodney W. Grimes return (0); 9118fae3551SRodney W. Grimes } 9128fae3551SRodney W. Grimes 9138fae3551SRodney W. Grimes sp->se_next = 0; 9148fae3551SRodney W. Grimes if (sprev == 0) { 9158fae3551SRodney W. Grimes sessions = sp; 9168fae3551SRodney W. Grimes sp->se_prev = 0; 9178fae3551SRodney W. Grimes } else { 9188fae3551SRodney W. Grimes sprev->se_next = sp; 9198fae3551SRodney W. Grimes sp->se_prev = sprev; 9208fae3551SRodney W. Grimes } 9218fae3551SRodney W. Grimes 9228fae3551SRodney W. Grimes return sp; 9238fae3551SRodney W. Grimes } 9248fae3551SRodney W. Grimes 9258fae3551SRodney W. Grimes /* 9268fae3551SRodney W. Grimes * Calculate getty and if useful window argv vectors. 9278fae3551SRodney W. Grimes */ 9288fae3551SRodney W. Grimes int 9298fae3551SRodney W. Grimes setupargv(sp, typ) 9308fae3551SRodney W. Grimes session_t *sp; 9318fae3551SRodney W. Grimes struct ttyent *typ; 9328fae3551SRodney W. Grimes { 9338fae3551SRodney W. Grimes 9348fae3551SRodney W. Grimes if (sp->se_getty) { 9358fae3551SRodney W. Grimes free(sp->se_getty); 9368fae3551SRodney W. Grimes free(sp->se_getty_argv); 9378fae3551SRodney W. Grimes } 9388fae3551SRodney W. Grimes sp->se_getty = malloc(strlen(typ->ty_getty) + strlen(typ->ty_name) + 2); 9398fae3551SRodney W. Grimes (void) sprintf(sp->se_getty, "%s %s", typ->ty_getty, typ->ty_name); 9408fae3551SRodney W. Grimes sp->se_getty_argv = construct_argv(sp->se_getty); 9418fae3551SRodney W. Grimes if (sp->se_getty_argv == 0) { 9428fae3551SRodney W. Grimes warning("can't parse getty for port %s", sp->se_device); 9438fae3551SRodney W. Grimes free(sp->se_getty); 9448fae3551SRodney W. Grimes sp->se_getty = 0; 9458fae3551SRodney W. Grimes return (0); 9468fae3551SRodney W. Grimes } 9478fae3551SRodney W. Grimes if (typ->ty_window) { 9488fae3551SRodney W. Grimes if (sp->se_window) 9498fae3551SRodney W. Grimes free(sp->se_window); 9508fae3551SRodney W. Grimes sp->se_window = strdup(typ->ty_window); 9518fae3551SRodney W. Grimes sp->se_window_argv = construct_argv(sp->se_window); 9528fae3551SRodney W. Grimes if (sp->se_window_argv == 0) { 9538fae3551SRodney W. Grimes warning("can't parse window for port %s", 9548fae3551SRodney W. Grimes sp->se_device); 9558fae3551SRodney W. Grimes free(sp->se_window); 9568fae3551SRodney W. Grimes sp->se_window = 0; 9578fae3551SRodney W. Grimes return (0); 9588fae3551SRodney W. Grimes } 9598fae3551SRodney W. Grimes } 9608fae3551SRodney W. Grimes return (1); 9618fae3551SRodney W. Grimes } 9628fae3551SRodney W. Grimes 9638fae3551SRodney W. Grimes /* 9648fae3551SRodney W. Grimes * Walk the list of ttys and create sessions for each active line. 9658fae3551SRodney W. Grimes */ 9668fae3551SRodney W. Grimes state_func_t 9678fae3551SRodney W. Grimes read_ttys() 9688fae3551SRodney W. Grimes { 9698fae3551SRodney W. Grimes int session_index = 0; 9708fae3551SRodney W. Grimes register session_t *sp, *snext; 9718fae3551SRodney W. Grimes register struct ttyent *typ; 9728fae3551SRodney W. Grimes 9738fae3551SRodney W. Grimes /* 9748fae3551SRodney W. Grimes * Destroy any previous session state. 9758fae3551SRodney W. Grimes * There shouldn't be any, but just in case... 9768fae3551SRodney W. Grimes */ 9778fae3551SRodney W. Grimes for (sp = sessions; sp; sp = snext) { 9788fae3551SRodney W. Grimes if (sp->se_process) 9798fae3551SRodney W. Grimes clear_session_logs(sp); 9808fae3551SRodney W. Grimes snext = sp->se_next; 9818fae3551SRodney W. Grimes free_session(sp); 9828fae3551SRodney W. Grimes } 9838fae3551SRodney W. Grimes sessions = 0; 9848fae3551SRodney W. Grimes if (start_session_db()) 9858fae3551SRodney W. Grimes return (state_func_t) single_user; 9868fae3551SRodney W. Grimes 9878fae3551SRodney W. Grimes /* 9888fae3551SRodney W. Grimes * Allocate a session entry for each active port. 9898fae3551SRodney W. Grimes * Note that sp starts at 0. 9908fae3551SRodney W. Grimes */ 9918fae3551SRodney W. Grimes while (typ = getttyent()) 9928fae3551SRodney W. Grimes if (snext = new_session(sp, ++session_index, typ)) 9938fae3551SRodney W. Grimes sp = snext; 9948fae3551SRodney W. Grimes 9958fae3551SRodney W. Grimes endttyent(); 9968fae3551SRodney W. Grimes 9978fae3551SRodney W. Grimes return (state_func_t) multi_user; 9988fae3551SRodney W. Grimes } 9998fae3551SRodney W. Grimes 10008fae3551SRodney W. Grimes /* 10018fae3551SRodney W. Grimes * Start a window system running. 10028fae3551SRodney W. Grimes */ 10038fae3551SRodney W. Grimes void 10048fae3551SRodney W. Grimes start_window_system(sp) 10058fae3551SRodney W. Grimes session_t *sp; 10068fae3551SRodney W. Grimes { 10078fae3551SRodney W. Grimes pid_t pid; 10088fae3551SRodney W. Grimes sigset_t mask; 10098fae3551SRodney W. Grimes 10108fae3551SRodney W. Grimes if ((pid = fork()) == -1) { 10118fae3551SRodney W. Grimes emergency("can't fork for window system on port %s: %m", 10128fae3551SRodney W. Grimes sp->se_device); 10138fae3551SRodney W. Grimes /* hope that getty fails and we can try again */ 10148fae3551SRodney W. Grimes return; 10158fae3551SRodney W. Grimes } 10168fae3551SRodney W. Grimes 10178fae3551SRodney W. Grimes if (pid) 10188fae3551SRodney W. Grimes return; 10198fae3551SRodney W. Grimes 10208fae3551SRodney W. Grimes sigemptyset(&mask); 10218fae3551SRodney W. Grimes sigprocmask(SIG_SETMASK, &mask, (sigset_t *) 0); 10228fae3551SRodney W. Grimes 10238fae3551SRodney W. Grimes if (setsid() < 0) 10248fae3551SRodney W. Grimes emergency("setsid failed (window) %m"); 10258fae3551SRodney W. Grimes 10268fae3551SRodney W. Grimes execv(sp->se_window_argv[0], sp->se_window_argv); 10278fae3551SRodney W. Grimes stall("can't exec window system '%s' for port %s: %m", 10288fae3551SRodney W. Grimes sp->se_window_argv[0], sp->se_device); 10298fae3551SRodney W. Grimes _exit(1); 10308fae3551SRodney W. Grimes } 10318fae3551SRodney W. Grimes 10328fae3551SRodney W. Grimes /* 10338fae3551SRodney W. Grimes * Start a login session running. 10348fae3551SRodney W. Grimes */ 10358fae3551SRodney W. Grimes pid_t 10368fae3551SRodney W. Grimes start_getty(sp) 10378fae3551SRodney W. Grimes session_t *sp; 10388fae3551SRodney W. Grimes { 10398fae3551SRodney W. Grimes pid_t pid; 10408fae3551SRodney W. Grimes sigset_t mask; 10418fae3551SRodney W. Grimes time_t current_time = time((time_t *) 0); 10428fae3551SRodney W. Grimes 10438fae3551SRodney W. Grimes /* 10448fae3551SRodney W. Grimes * fork(), not vfork() -- we can't afford to block. 10458fae3551SRodney W. Grimes */ 10468fae3551SRodney W. Grimes if ((pid = fork()) == -1) { 10478fae3551SRodney W. Grimes emergency("can't fork for getty on port %s: %m", sp->se_device); 10488fae3551SRodney W. Grimes return -1; 10498fae3551SRodney W. Grimes } 10508fae3551SRodney W. Grimes 10518fae3551SRodney W. Grimes if (pid) 10528fae3551SRodney W. Grimes return pid; 10538fae3551SRodney W. Grimes 10548fae3551SRodney W. Grimes if (current_time > sp->se_started && 10558fae3551SRodney W. Grimes current_time - sp->se_started < GETTY_SPACING) { 10568fae3551SRodney W. Grimes warning("getty repeating too quickly on port %s, sleeping", 10578fae3551SRodney W. Grimes sp->se_device); 10588fae3551SRodney W. Grimes sleep((unsigned) GETTY_SLEEP); 10598fae3551SRodney W. Grimes } 10608fae3551SRodney W. Grimes 10618fae3551SRodney W. Grimes if (sp->se_window) { 10628fae3551SRodney W. Grimes start_window_system(sp); 10638fae3551SRodney W. Grimes sleep(WINDOW_WAIT); 10648fae3551SRodney W. Grimes } 10658fae3551SRodney W. Grimes 10668fae3551SRodney W. Grimes sigemptyset(&mask); 10678fae3551SRodney W. Grimes sigprocmask(SIG_SETMASK, &mask, (sigset_t *) 0); 10688fae3551SRodney W. Grimes 10698fae3551SRodney W. Grimes execv(sp->se_getty_argv[0], sp->se_getty_argv); 10708fae3551SRodney W. Grimes stall("can't exec getty '%s' for port %s: %m", 10718fae3551SRodney W. Grimes sp->se_getty_argv[0], sp->se_device); 10728fae3551SRodney W. Grimes _exit(1); 10738fae3551SRodney W. Grimes } 10748fae3551SRodney W. Grimes 10758fae3551SRodney W. Grimes /* 10768fae3551SRodney W. Grimes * Collect exit status for a child. 10778fae3551SRodney W. Grimes * If an exiting login, start a new login running. 10788fae3551SRodney W. Grimes */ 10798fae3551SRodney W. Grimes void 10808fae3551SRodney W. Grimes #ifdef __STDC__ 10818fae3551SRodney W. Grimes collect_child(pid_t pid) 10828fae3551SRodney W. Grimes #else 10838fae3551SRodney W. Grimes collect_child(pid) 10848fae3551SRodney W. Grimes pid_t pid; 10858fae3551SRodney W. Grimes #endif 10868fae3551SRodney W. Grimes { 10878fae3551SRodney W. Grimes register session_t *sp, *sprev, *snext; 10888fae3551SRodney W. Grimes 10898fae3551SRodney W. Grimes if (! sessions) 10908fae3551SRodney W. Grimes return; 10918fae3551SRodney W. Grimes 10928fae3551SRodney W. Grimes if (! (sp = find_session(pid))) 10938fae3551SRodney W. Grimes return; 10948fae3551SRodney W. Grimes 10958fae3551SRodney W. Grimes clear_session_logs(sp); 10968fae3551SRodney W. Grimes del_session(sp); 10978fae3551SRodney W. Grimes sp->se_process = 0; 10988fae3551SRodney W. Grimes 10998fae3551SRodney W. Grimes if (sp->se_flags & SE_SHUTDOWN) { 11008fae3551SRodney W. Grimes if (sprev = sp->se_prev) 11018fae3551SRodney W. Grimes sprev->se_next = sp->se_next; 11028fae3551SRodney W. Grimes else 11038fae3551SRodney W. Grimes sessions = sp->se_next; 11048fae3551SRodney W. Grimes if (snext = sp->se_next) 11058fae3551SRodney W. Grimes snext->se_prev = sp->se_prev; 11068fae3551SRodney W. Grimes free_session(sp); 11078fae3551SRodney W. Grimes return; 11088fae3551SRodney W. Grimes } 11098fae3551SRodney W. Grimes 11108fae3551SRodney W. Grimes if ((pid = start_getty(sp)) == -1) { 11118fae3551SRodney W. Grimes /* serious trouble */ 11128fae3551SRodney W. Grimes requested_transition = clean_ttys; 11138fae3551SRodney W. Grimes return; 11148fae3551SRodney W. Grimes } 11158fae3551SRodney W. Grimes 11168fae3551SRodney W. Grimes sp->se_process = pid; 11178fae3551SRodney W. Grimes sp->se_started = time((time_t *) 0); 11188fae3551SRodney W. Grimes add_session(sp); 11198fae3551SRodney W. Grimes } 11208fae3551SRodney W. Grimes 11218fae3551SRodney W. Grimes /* 11228fae3551SRodney W. Grimes * Catch a signal and request a state transition. 11238fae3551SRodney W. Grimes */ 11248fae3551SRodney W. Grimes void 11258fae3551SRodney W. Grimes transition_handler(sig) 11268fae3551SRodney W. Grimes int sig; 11278fae3551SRodney W. Grimes { 11288fae3551SRodney W. Grimes 11298fae3551SRodney W. Grimes switch (sig) { 11308fae3551SRodney W. Grimes case SIGHUP: 11318fae3551SRodney W. Grimes requested_transition = clean_ttys; 11328fae3551SRodney W. Grimes break; 11338fae3551SRodney W. Grimes case SIGTERM: 11348fae3551SRodney W. Grimes requested_transition = death; 11358fae3551SRodney W. Grimes break; 11368fae3551SRodney W. Grimes case SIGTSTP: 11378fae3551SRodney W. Grimes requested_transition = catatonia; 11388fae3551SRodney W. Grimes break; 11398fae3551SRodney W. Grimes default: 11408fae3551SRodney W. Grimes requested_transition = 0; 11418fae3551SRodney W. Grimes break; 11428fae3551SRodney W. Grimes } 11438fae3551SRodney W. Grimes } 11448fae3551SRodney W. Grimes 11458fae3551SRodney W. Grimes /* 11468fae3551SRodney W. Grimes * Take the system multiuser. 11478fae3551SRodney W. Grimes */ 11488fae3551SRodney W. Grimes state_func_t 11498fae3551SRodney W. Grimes multi_user() 11508fae3551SRodney W. Grimes { 11518fae3551SRodney W. Grimes pid_t pid; 11528fae3551SRodney W. Grimes register session_t *sp; 11538fae3551SRodney W. Grimes 11548fae3551SRodney W. Grimes requested_transition = 0; 11558fae3551SRodney W. Grimes 11568fae3551SRodney W. Grimes /* 11578fae3551SRodney W. Grimes * If the administrator has not set the security level to -1 11588fae3551SRodney W. Grimes * to indicate that the kernel should not run multiuser in secure 11598fae3551SRodney W. Grimes * mode, and the run script has not set a higher level of security 11608fae3551SRodney W. Grimes * than level 1, then put the kernel into secure mode. 11618fae3551SRodney W. Grimes */ 11628fae3551SRodney W. Grimes if (getsecuritylevel() == 0) 11638fae3551SRodney W. Grimes setsecuritylevel(1); 11648fae3551SRodney W. Grimes 11658fae3551SRodney W. Grimes for (sp = sessions; sp; sp = sp->se_next) { 11668fae3551SRodney W. Grimes if (sp->se_process) 11678fae3551SRodney W. Grimes continue; 11688fae3551SRodney W. Grimes if ((pid = start_getty(sp)) == -1) { 11698fae3551SRodney W. Grimes /* serious trouble */ 11708fae3551SRodney W. Grimes requested_transition = clean_ttys; 11718fae3551SRodney W. Grimes break; 11728fae3551SRodney W. Grimes } 11738fae3551SRodney W. Grimes sp->se_process = pid; 11748fae3551SRodney W. Grimes sp->se_started = time((time_t *) 0); 11758fae3551SRodney W. Grimes add_session(sp); 11768fae3551SRodney W. Grimes } 11778fae3551SRodney W. Grimes 11788fae3551SRodney W. Grimes while (!requested_transition) 11798fae3551SRodney W. Grimes if ((pid = waitpid(-1, (int *) 0, 0)) != -1) 11808fae3551SRodney W. Grimes collect_child(pid); 11818fae3551SRodney W. Grimes 11828fae3551SRodney W. Grimes return (state_func_t) requested_transition; 11838fae3551SRodney W. Grimes } 11848fae3551SRodney W. Grimes 11858fae3551SRodney W. Grimes /* 11868fae3551SRodney W. Grimes * This is an n-squared algorithm. We hope it isn't run often... 11878fae3551SRodney W. Grimes */ 11888fae3551SRodney W. Grimes state_func_t 11898fae3551SRodney W. Grimes clean_ttys() 11908fae3551SRodney W. Grimes { 11918fae3551SRodney W. Grimes register session_t *sp, *sprev; 11928fae3551SRodney W. Grimes register struct ttyent *typ; 11938fae3551SRodney W. Grimes register int session_index = 0; 11948fae3551SRodney W. Grimes register int devlen; 11958fae3551SRodney W. Grimes 11968fae3551SRodney W. Grimes if (! sessions) 11978fae3551SRodney W. Grimes return (state_func_t) multi_user; 11988fae3551SRodney W. Grimes 11998fae3551SRodney W. Grimes devlen = sizeof(_PATH_DEV) - 1; 12008fae3551SRodney W. Grimes while (typ = getttyent()) { 12018fae3551SRodney W. Grimes ++session_index; 12028fae3551SRodney W. Grimes 12038fae3551SRodney W. Grimes for (sprev = 0, sp = sessions; sp; sprev = sp, sp = sp->se_next) 12048fae3551SRodney W. Grimes if (strcmp(typ->ty_name, sp->se_device + devlen) == 0) 12058fae3551SRodney W. Grimes break; 12068fae3551SRodney W. Grimes 12078fae3551SRodney W. Grimes if (sp) { 12088fae3551SRodney W. Grimes if (sp->se_index != session_index) { 12098fae3551SRodney W. Grimes warning("port %s changed utmp index from %d to %d", 12108fae3551SRodney W. Grimes sp->se_device, sp->se_index, 12118fae3551SRodney W. Grimes session_index); 12128fae3551SRodney W. Grimes sp->se_index = session_index; 12138fae3551SRodney W. Grimes } 12148fae3551SRodney W. Grimes if ((typ->ty_status & TTY_ON) == 0 || 12158fae3551SRodney W. Grimes typ->ty_getty == 0) { 12168fae3551SRodney W. Grimes sp->se_flags |= SE_SHUTDOWN; 12178fae3551SRodney W. Grimes kill(sp->se_process, SIGHUP); 12188fae3551SRodney W. Grimes continue; 12198fae3551SRodney W. Grimes } 12208fae3551SRodney W. Grimes sp->se_flags &= ~SE_SHUTDOWN; 12218fae3551SRodney W. Grimes if (setupargv(sp, typ) == 0) { 12228fae3551SRodney W. Grimes warning("can't parse getty for port %s", 12238fae3551SRodney W. Grimes sp->se_device); 12248fae3551SRodney W. Grimes sp->se_flags |= SE_SHUTDOWN; 12258fae3551SRodney W. Grimes kill(sp->se_process, SIGHUP); 12268fae3551SRodney W. Grimes } 12278fae3551SRodney W. Grimes continue; 12288fae3551SRodney W. Grimes } 12298fae3551SRodney W. Grimes 12308fae3551SRodney W. Grimes new_session(sprev, session_index, typ); 12318fae3551SRodney W. Grimes } 12328fae3551SRodney W. Grimes 12338fae3551SRodney W. Grimes endttyent(); 12348fae3551SRodney W. Grimes 12358fae3551SRodney W. Grimes return (state_func_t) multi_user; 12368fae3551SRodney W. Grimes } 12378fae3551SRodney W. Grimes 12388fae3551SRodney W. Grimes /* 12398fae3551SRodney W. Grimes * Block further logins. 12408fae3551SRodney W. Grimes */ 12418fae3551SRodney W. Grimes state_func_t 12428fae3551SRodney W. Grimes catatonia() 12438fae3551SRodney W. Grimes { 12448fae3551SRodney W. Grimes register session_t *sp; 12458fae3551SRodney W. Grimes 12468fae3551SRodney W. Grimes for (sp = sessions; sp; sp = sp->se_next) 12478fae3551SRodney W. Grimes sp->se_flags |= SE_SHUTDOWN; 12488fae3551SRodney W. Grimes 12498fae3551SRodney W. Grimes return (state_func_t) multi_user; 12508fae3551SRodney W. Grimes } 12518fae3551SRodney W. Grimes 12528fae3551SRodney W. Grimes /* 12538fae3551SRodney W. Grimes * Note SIGALRM. 12548fae3551SRodney W. Grimes */ 12558fae3551SRodney W. Grimes void 12568fae3551SRodney W. Grimes alrm_handler(sig) 12578fae3551SRodney W. Grimes int sig; 12588fae3551SRodney W. Grimes { 12598fae3551SRodney W. Grimes clang = 1; 12608fae3551SRodney W. Grimes } 12618fae3551SRodney W. Grimes 12628fae3551SRodney W. Grimes /* 12638fae3551SRodney W. Grimes * Bring the system down to single user. 12648fae3551SRodney W. Grimes */ 12658fae3551SRodney W. Grimes state_func_t 12668fae3551SRodney W. Grimes death() 12678fae3551SRodney W. Grimes { 12688fae3551SRodney W. Grimes register session_t *sp; 12698fae3551SRodney W. Grimes register int i; 12708fae3551SRodney W. Grimes pid_t pid; 12718fae3551SRodney W. Grimes static const int death_sigs[3] = { SIGHUP, SIGTERM, SIGKILL }; 12728fae3551SRodney W. Grimes 12738fae3551SRodney W. Grimes for (sp = sessions; sp; sp = sp->se_next) 12748fae3551SRodney W. Grimes sp->se_flags |= SE_SHUTDOWN; 12758fae3551SRodney W. Grimes 12768fae3551SRodney W. Grimes /* NB: should send a message to the session logger to avoid blocking. */ 12778fae3551SRodney W. Grimes logwtmp("~", "shutdown", ""); 12788fae3551SRodney W. Grimes 12798fae3551SRodney W. Grimes for (i = 0; i < 3; ++i) { 12808fae3551SRodney W. Grimes if (kill(-1, death_sigs[i]) == -1 && errno == ESRCH) 12818fae3551SRodney W. Grimes return (state_func_t) single_user; 12828fae3551SRodney W. Grimes 12838fae3551SRodney W. Grimes clang = 0; 12848fae3551SRodney W. Grimes alarm(DEATH_WATCH); 12858fae3551SRodney W. Grimes do 12868fae3551SRodney W. Grimes if ((pid = waitpid(-1, (int *)0, 0)) != -1) 12878fae3551SRodney W. Grimes collect_child(pid); 12888fae3551SRodney W. Grimes while (clang == 0 && errno != ECHILD); 12898fae3551SRodney W. Grimes 12908fae3551SRodney W. Grimes if (errno == ECHILD) 12918fae3551SRodney W. Grimes return (state_func_t) single_user; 12928fae3551SRodney W. Grimes } 12938fae3551SRodney W. Grimes 12948fae3551SRodney W. Grimes warning("some processes would not die; ps axl advised"); 12958fae3551SRodney W. Grimes 12968fae3551SRodney W. Grimes return (state_func_t) single_user; 12978fae3551SRodney W. Grimes } 1298