[BACK]Return to init.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sbin / init

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>