[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.84

1.84    ! christos    1: /*     $NetBSD: init.c,v 1.83 2007/01/20 13:25:28 isaki 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.
1.61      agc        18:  * 3. Neither the name of the University nor the names of its contributors
1.8       cgd        19:  *    may be used to endorse or promote products derived from this software
1.1       cgd        20:  *    without specific prior written permission.
                     21:  *
1.8       cgd        22:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
1.1       cgd        23:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     24:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1.8       cgd        25:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
1.1       cgd        26:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     27:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     28:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     29:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     30:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     31:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     32:  * SUCH DAMAGE.
                     33:  */
1.3       cgd        34:
1.26      perry      35: #include <sys/cdefs.h>
1.8       cgd        36: #ifndef lint
1.26      perry      37: __COPYRIGHT("@(#) Copyright (c) 1991, 1993\n"
                     38: "      The Regents of the University of California.  All rights reserved.\n");
1.8       cgd        39: #endif /* not lint */
                     40:
                     41: #ifndef lint
1.19      cgd        42: #if 0
1.25      perry      43: static char sccsid[] = "@(#)init.c     8.2 (Berkeley) 4/28/95";
1.19      cgd        44: #else
1.84    ! christos   45: __RCSID("$NetBSD: init.c,v 1.83 2007/01/20 13:25:28 isaki Exp $");
1.19      cgd        46: #endif
1.8       cgd        47: #endif /* not lint */
                     48:
                     49: #include <sys/param.h>
                     50: #include <sys/sysctl.h>
1.1       cgd        51: #include <sys/wait.h>
1.28      christos   52: #include <sys/mman.h>
                     53: #include <sys/stat.h>
                     54: #include <sys/mount.h>
                     55: #include <machine/cpu.h>
1.8       cgd        56:
                     57: #include <db.h>
                     58: #include <errno.h>
                     59: #include <fcntl.h>
                     60: #include <signal.h>
                     61: #include <stdio.h>
                     62: #include <stdlib.h>
                     63: #include <string.h>
                     64: #include <syslog.h>
                     65: #include <time.h>
1.1       cgd        66: #include <ttyent.h>
                     67: #include <unistd.h>
1.22      jtc        68: #include <util.h>
1.28      christos   69: #include <paths.h>
                     70: #include <err.h>
1.1       cgd        71:
1.8       cgd        72: #include <stdarg.h>
                     73:
                     74: #ifdef SECURE
1.5       cgd        75: #include <pwd.h>
                     76: #endif
                     77:
1.8       cgd        78: #include "pathnames.h"
                     79:
1.62      dsl        80: #define XSTR(x) #x
                     81: #define STR(x) XSTR(x)
                     82:
1.8       cgd        83: /*
                     84:  * Sleep times; used to prevent thrashing.
                     85:  */
                     86: #define        GETTY_SPACING            5      /* N secs minimum getty spacing */
                     87: #define        GETTY_SLEEP             30      /* sleep N secs after spacing problem */
                     88: #define        WINDOW_WAIT              3      /* wait N secs after starting window */
                     89: #define        STALL_TIMEOUT           30      /* wait N secs after warning */
                     90: #define        DEATH_WATCH             10      /* wait N secs for procs to die */
                     91:
1.66      mycroft    92: const struct timespec dtrtime = {.tv_sec = 0, .tv_nsec = 250000};
1.56      lukem      93:
                     94: #if defined(RESCUEDIR)
                     95: #define        INIT_BSHELL     RESCUEDIR "/sh"
                     96: #define        INIT_MOUNT_MFS  RESCUEDIR "/mount_mfs"
                     97: #define        INIT_PATH       RESCUEDIR ":" _PATH_STDPATH
                     98: #else
                     99: #define        INIT_BSHELL     _PATH_BSHELL
                    100: #define        INIT_MOUNT_MFS  "/sbin/mount_mfs"
                    101: #define        INIT_PATH       _PATH_STDPATH
1.52      lukem     102: #endif
                    103:
1.39      wiz       104: int main(int, char *[]);
1.27      perry     105:
1.39      wiz       106: void handle(sig_t, ...);
                    107: void delset(sigset_t *, ...);
1.8       cgd       108:
1.39      wiz       109: void stall(const char *, ...)
1.28      christos  110:     __attribute__((__format__(__printf__,1,2)));
1.39      wiz       111: void warning(const char *, ...)
1.28      christos  112:     __attribute__((__format__(__printf__,1,2)));
1.39      wiz       113: void emergency(const char *, ...)
1.28      christos  114:     __attribute__((__format__(__printf__,1,2)));
1.39      wiz       115: void disaster(int);
                    116: void badsys(int);
1.8       cgd       117:
                    118: /*
                    119:  * We really need a recursive typedef...
                    120:  * The following at least guarantees that the return type of (*state_t)()
                    121:  * is sufficiently wide to hold a function pointer.
                    122:  */
1.39      wiz       123: typedef long (*state_func_t)(void);
                    124: typedef state_func_t (*state_t)(void);
1.8       cgd       125:
1.77      christos  126: #define        DEATH           'd'
                    127: #define        SINGLE_USER     's'
                    128: #define        RUNCOM          'r'
                    129: #define        READ_TTYS       't'
                    130: #define        MULTI_USER      'm'
                    131: #define        CLEAN_TTYS      'T'
                    132: #define        CATATONIA       'c'
                    133:
1.39      wiz       134: state_func_t single_user(void);
                    135: state_func_t runcom(void);
                    136: state_func_t read_ttys(void);
                    137: state_func_t multi_user(void);
                    138: state_func_t clean_ttys(void);
                    139: state_func_t catatonia(void);
                    140: state_func_t death(void);
1.8       cgd       141:
                    142: enum { AUTOBOOT, FASTBOOT } runcom_mode = AUTOBOOT;
                    143:
1.39      wiz       144: void transition(state_t);
1.40      wiz       145: void setctty(const char *);
1.8       cgd       146:
                    147: typedef struct init_session {
                    148:        int     se_index;               /* index of entry in ttys file */
                    149:        pid_t   se_process;             /* controlling process */
1.77      christos  150:        struct timeval  se_started;     /* used to avoid thrashing */
1.8       cgd       151:        int     se_flags;               /* status of session */
                    152: #define        SE_SHUTDOWN     0x1             /* session won't be restarted */
1.21      mycroft   153: #define        SE_PRESENT      0x2             /* session is in /etc/ttys */
1.8       cgd       154:        char    *se_device;             /* filename of port */
                    155:        char    *se_getty;              /* what to run on that port */
                    156:        char    **se_getty_argv;        /* pre-parsed argument array */
                    157:        char    *se_window;             /* window system (started only once) */
                    158:        char    **se_window_argv;       /* pre-parsed argument array */
                    159:        struct  init_session *se_prev;
                    160:        struct  init_session *se_next;
                    161: } session_t;
                    162:
1.39      wiz       163: void free_session(session_t *);
                    164: session_t *new_session(session_t *, int, struct ttyent *);
1.8       cgd       165: session_t *sessions;
                    166:
1.39      wiz       167: char **construct_argv(char *);
                    168: void start_window_system(session_t *);
1.50      christos  169: void collect_child(pid_t, int);
1.39      wiz       170: pid_t start_getty(session_t *);
                    171: void transition_handler(int);
                    172: void alrm_handler(int);
                    173: void setsecuritylevel(int);
                    174: int getsecuritylevel(void);
                    175: int setupargv(session_t *, struct ttyent *);
1.8       cgd       176: int clang;
                    177:
1.39      wiz       178: int start_session_db(void);
                    179: void add_session(session_t *);
                    180: void del_session(session_t *);
                    181: session_t *find_session(pid_t);
1.8       cgd       182: DB *session_db;
                    183:
1.73      salo      184: int do_setttyent(void);
                    185:
                    186: #ifndef LETS_GET_SMALL
                    187: state_t requested_transition = runcom;
                    188:
                    189: void clear_session_logs(session_t *, int);
                    190: state_func_t runetcrc(int);
1.77      christos  191: #ifdef SUPPORT_UTMPX
                    192: static struct timeval boot_time;
                    193: state_t current_state = death;
                    194: static void session_utmpx(const session_t *, int);
                    195: static void make_utmpx(const char *, const char *, int, pid_t,
                    196:     const struct timeval *, int);
                    197: static char get_runlevel(const state_t);
                    198: static void utmpx_set_runlevel(char, char);
                    199: #endif
1.73      salo      200:
                    201: #ifdef CHROOT
                    202: int did_multiuser_chroot = 0;
                    203: char rootdir[PATH_MAX];
                    204: int shouldchroot(void);
                    205: int createsysctlnode(void);
                    206: #endif /* CHROOT */
                    207:
                    208: #else /* LETS_GET_SMALL */
                    209: state_t requested_transition = single_user;
                    210: #endif /* !LETS_GET_SMALL */
                    211:
1.45      abs       212: #ifdef MFS_DEV_IF_NO_CONSOLE
1.58      christos  213:
1.69      xtraeme   214: #define NINODE 1024
1.62      dsl       215: #define FSSIZE ((8192          /* boot area */                         \
                    216:        + 2 * 8192              /* two copies of superblock */          \
                    217:        + 4096                  /* cylinder group info */               \
                    218:        + NINODE * (128 + 18)   /* inode and directory entry */         \
                    219:        + mfile[0].len          /* size of MAKEDEV file */              \
                    220:        + 2 * 4096) / 512)      /* some slack */
                    221:
1.58      christos  222: struct mappedfile {
                    223:        const char *path;
1.62      dsl       224:        char    *buf;
1.84    ! christos  225:        size_t  len;
1.58      christos  226: } mfile[] = {
                    227:        { "/dev/MAKEDEV",       NULL,   0 },
                    228:        { "/dev/MAKEDEV.local", NULL,   0 }
                    229: };
                    230:
1.45      abs       231: static int mfs_dev(void);
1.58      christos  232: static void mapfile(struct mappedfile *);
                    233: static void writefile(struct mappedfile *);
                    234:
1.28      christos  235: #endif
                    236:
1.8       cgd       237: /*
                    238:  * The mother of all processes.
                    239:  */
                    240: int
1.43      lukem     241: main(int argc, char **argv)
1.8       cgd       242: {
                    243:        struct sigaction sa;
                    244:        sigset_t mask;
1.37      soren     245: #ifndef LETS_GET_SMALL
                    246:        int c;
1.8       cgd       247:
1.77      christos  248: #ifdef SUPPORT_UTMPX
                    249:        (void)gettimeofday(&boot_time, NULL);
                    250: #endif /* SUPPORT_UTMPX */
                    251:
1.8       cgd       252:        /* Dispose of random users. */
                    253:        if (getuid() != 0) {
1.28      christos  254:                errno = EPERM;
1.35      drochner  255:                err(1, NULL);
1.8       cgd       256:        }
                    257:
                    258:        /* System V users like to reexec init. */
1.28      christos  259:        if (getpid() != 1)
                    260:                errx(1, "already running");
                    261: #endif
1.8       cgd       262:
                    263:        /*
                    264:         * Create an initial session.
                    265:         */
                    266:        if (setsid() < 0)
1.28      christos  267:                warn("initial setsid() failed");
1.12      cgd       268:
                    269:        /*
                    270:         * Establish an initial user so that programs running
                    271:         * single user do not freak out and die (like passwd).
                    272:         */
                    273:        if (setlogin("root") < 0)
1.28      christos  274:                warn("setlogin() failed");
                    275:
                    276:
1.45      abs       277: #ifdef MFS_DEV_IF_NO_CONSOLE
                    278:        if (mfs_dev() == -1)
                    279:                requested_transition = single_user;
1.28      christos  280: #endif
                    281:
                    282: #ifndef LETS_GET_SMALL
                    283:        /*
                    284:         * Note that this does NOT open a file...
                    285:         * Does 'init' deserve its own facility number?
                    286:         */
1.42      lukem     287:        openlog("init", LOG_CONS, LOG_AUTH);
1.28      christos  288: #endif /* LETS_GET_SMALL */
                    289:
1.8       cgd       290:
1.13      cgd       291: #ifndef LETS_GET_SMALL
1.8       cgd       292:        /*
                    293:         * This code assumes that we always get arguments through flags,
                    294:         * never through bits set in some random machine register.
                    295:         */
                    296:        while ((c = getopt(argc, argv, "sf")) != -1)
                    297:                switch (c) {
                    298:                case 's':
                    299:                        requested_transition = single_user;
                    300:                        break;
                    301:                case 'f':
                    302:                        runcom_mode = FASTBOOT;
                    303:                        break;
                    304:                default:
1.80      christos  305:                        warning("unrecognized flag `%c'", c);
1.8       cgd       306:                        break;
                    307:                }
                    308:
                    309:        if (optind != argc)
                    310:                warning("ignoring excess arguments");
1.13      cgd       311: #else /* LETS_GET_SMALL */
                    312:        requested_transition = single_user;
                    313: #endif /* LETS_GET_SMALL */
1.8       cgd       314:
                    315:        /*
                    316:         * We catch or block signals rather than ignore them,
                    317:         * so that they get reset on exec.
                    318:         */
                    319:        handle(badsys, SIGSYS, 0);
                    320:        handle(disaster, SIGABRT, SIGFPE, SIGILL, SIGSEGV,
                    321:               SIGBUS, SIGXCPU, SIGXFSZ, 0);
                    322:        handle(transition_handler, SIGHUP, SIGTERM, SIGTSTP, 0);
                    323:        handle(alrm_handler, SIGALRM, 0);
1.47      christos  324:        (void)sigfillset(&mask);
1.8       cgd       325:        delset(&mask, SIGABRT, SIGFPE, SIGILL, SIGSEGV, SIGBUS, SIGSYS,
1.47      christos  326:            SIGXCPU, SIGXFSZ, SIGHUP, SIGTERM, SIGTSTP, SIGALRM, 0);
                    327:        (void)sigprocmask(SIG_SETMASK, &mask, NULL);
                    328:        (void)sigemptyset(&sa.sa_mask);
1.8       cgd       329:        sa.sa_flags = 0;
                    330:        sa.sa_handler = SIG_IGN;
1.47      christos  331:        (void)sigaction(SIGTTIN, &sa, NULL);
                    332:        (void)sigaction(SIGTTOU, &sa, NULL);
1.8       cgd       333:
                    334:        /*
                    335:         * Paranoia.
                    336:         */
1.47      christos  337:        (void)close(0);
                    338:        (void)close(1);
                    339:        (void)close(2);
1.8       cgd       340:
1.73      salo      341: #if !defined(LETS_GET_SMALL) && defined(CHROOT)
                    342:        /* Create "init.root" sysctl node. */
1.84    ! christos  343:        (void)createsysctlnode();
1.73      salo      344: #endif /* !LETS_GET_SMALL && CHROOT*/
                    345:
1.8       cgd       346:        /*
                    347:         * Start the state machine.
                    348:         */
                    349:        transition(requested_transition);
                    350:
                    351:        /*
                    352:         * Should never reach here.
                    353:         */
                    354:        return 1;
                    355: }
                    356:
                    357: /*
                    358:  * Associate a function with a signal handler.
                    359:  */
                    360: void
                    361: handle(sig_t handler, ...)
                    362: {
                    363:        int sig;
                    364:        struct sigaction sa;
1.33      thorpej   365:        sigset_t mask_everything;
1.8       cgd       366:        va_list ap;
                    367:
                    368:        va_start(ap, handler);
1.7       cgd       369:
1.8       cgd       370:        sa.sa_handler = handler;
1.47      christos  371:        (void)sigfillset(&mask_everything);
1.1       cgd       372:
1.27      perry     373:        while ((sig = va_arg(ap, int)) != 0) {
1.8       cgd       374:                sa.sa_mask = mask_everything;
                    375:                /* XXX SA_RESTART? */
                    376:                sa.sa_flags = sig == SIGCHLD ? SA_NOCLDSTOP : 0;
1.47      christos  377:                (void)sigaction(sig, &sa, NULL);
1.8       cgd       378:        }
                    379:        va_end(ap);
                    380: }
1.1       cgd       381:
1.8       cgd       382: /*
                    383:  * Delete a set of signals from a mask.
                    384:  */
                    385: void
                    386: delset(sigset_t *maskp, ...)
                    387: {
                    388:        int sig;
                    389:        va_list ap;
                    390:
                    391:        va_start(ap, maskp);
1.1       cgd       392:
1.27      perry     393:        while ((sig = va_arg(ap, int)) != 0)
1.47      christos  394:                (void)sigdelset(maskp, sig);
1.8       cgd       395:        va_end(ap);
                    396: }
                    397:
                    398: /*
                    399:  * Log a message and sleep for a while (to give someone an opportunity
                    400:  * to read it and to save log or hardcopy output if the problem is chronic).
                    401:  * NB: should send a message to the session logger to avoid blocking.
                    402:  */
                    403: void
1.28      christos  404: stall(const char *message, ...)
1.8       cgd       405: {
                    406:        va_list ap;
                    407:
                    408:        va_start(ap, message);
                    409:        vsyslog(LOG_ALERT, message, ap);
                    410:        va_end(ap);
1.24      mycroft   411:        closelog();
1.47      christos  412:        (void)sleep(STALL_TIMEOUT);
1.8       cgd       413: }
                    414:
                    415: /*
                    416:  * Like stall(), but doesn't sleep.
                    417:  * If cpp had variadic macros, the two functions could be #defines for another.
                    418:  * NB: should send a message to the session logger to avoid blocking.
                    419:  */
                    420: void
1.28      christos  421: warning(const char *message, ...)
1.8       cgd       422: {
                    423:        va_list ap;
                    424:
                    425:        va_start(ap, message);
                    426:        vsyslog(LOG_ALERT, message, ap);
                    427:        va_end(ap);
1.24      mycroft   428:        closelog();
1.73      salo      429:
                    430: #if 0
                    431:        /*
                    432:         * XXX: syslog seems to just plain not work in console-only
                    433:         * XXX: situation... that should be fixed.  Let's leave this
                    434:         * XXX: note + code here in case someone gets in trouble and
                    435:         * XXX: wants to debug. -- Jachym Holecek <freza@liberouter.org>
                    436:         */
                    437:        {
                    438:                char errbuf[1024];
                    439:                int fd, len;
                    440:
                    441:                /* We can't do anything on errors, anyway... */
                    442:                fd = open(_PATH_CONSOLE, O_WRONLY);
                    443:                if (fd == -1)
                    444:                        return ;
                    445:
                    446:                /* %m will get lost... */
                    447:                len = vsnprintf(errbuf, sizeof(errbuf), message, ap);
                    448:                (void)write(fd, (void *)errbuf, len);
                    449:                (void)close(fd);
                    450:        }
                    451: #endif
1.8       cgd       452: }
1.1       cgd       453:
1.8       cgd       454: /*
                    455:  * Log an emergency message.
                    456:  * NB: should send a message to the session logger to avoid blocking.
                    457:  */
                    458: void
1.28      christos  459: emergency(const char *message, ...)
1.8       cgd       460: {
                    461:        va_list ap;
                    462:
                    463:        va_start(ap, message);
                    464:        vsyslog(LOG_EMERG, message, ap);
                    465:        va_end(ap);
1.24      mycroft   466:        closelog();
1.8       cgd       467: }
1.1       cgd       468:
1.8       cgd       469: /*
                    470:  * Catch a SIGSYS signal.
                    471:  *
                    472:  * These may arise if a system does not support sysctl.
                    473:  * We tolerate up to 25 of these, then throw in the towel.
                    474:  */
1.1       cgd       475: void
1.39      wiz       476: badsys(int sig)
1.1       cgd       477: {
1.8       cgd       478:        static int badcount = 0;
                    479:
                    480:        if (badcount++ < 25)
                    481:                return;
                    482:        disaster(sig);
1.1       cgd       483: }
                    484:
1.8       cgd       485: /*
                    486:  * Catch an unexpected signal.
                    487:  */
1.1       cgd       488: void
1.39      wiz       489: disaster(int sig)
1.8       cgd       490: {
1.43      lukem     491:
1.20      jtc       492:        emergency("fatal signal: %s", strsignal(sig));
1.47      christos  493:        (void)sleep(STALL_TIMEOUT);
1.8       cgd       494:        _exit(sig);             /* reboot */
                    495: }
                    496:
                    497: /*
                    498:  * Get the security level of the kernel.
                    499:  */
                    500: int
1.39      wiz       501: getsecuritylevel(void)
1.1       cgd       502: {
1.8       cgd       503: #ifdef KERN_SECURELVL
                    504:        int name[2], curlevel;
                    505:        size_t len;
                    506:
                    507:        name[0] = CTL_KERN;
                    508:        name[1] = KERN_SECURELVL;
                    509:        len = sizeof curlevel;
                    510:        if (sysctl(name, 2, &curlevel, &len, NULL, 0) == -1) {
1.47      christos  511:                emergency("cannot get kernel security level: %m");
1.8       cgd       512:                return (-1);
                    513:        }
                    514:        return (curlevel);
                    515: #else
                    516:        return (-1);
                    517: #endif
1.1       cgd       518: }
                    519:
1.8       cgd       520: /*
                    521:  * Set the security level of the kernel.
                    522:  */
1.1       cgd       523: void
1.39      wiz       524: setsecuritylevel(int newlevel)
1.1       cgd       525: {
1.8       cgd       526: #ifdef KERN_SECURELVL
                    527:        int name[2], curlevel;
1.1       cgd       528:
1.8       cgd       529:        curlevel = getsecuritylevel();
                    530:        if (newlevel == curlevel)
                    531:                return;
                    532:        name[0] = CTL_KERN;
                    533:        name[1] = KERN_SECURELVL;
                    534:        if (sysctl(name, 2, NULL, NULL, &newlevel, sizeof newlevel) == -1) {
1.80      christos  535:                emergency("cannot change kernel security level from"
1.47      christos  536:                    " %d to %d: %m", curlevel, newlevel);
1.8       cgd       537:                return;
1.1       cgd       538:        }
1.8       cgd       539: #ifdef SECURE
                    540:        warning("kernel security level changed from %d to %d",
                    541:            curlevel, newlevel);
                    542: #endif
                    543: #endif
1.1       cgd       544: }
                    545:
1.8       cgd       546: /*
                    547:  * Change states in the finite state machine.
                    548:  * The initial state is passed as an argument.
                    549:  */
1.1       cgd       550: void
1.39      wiz       551: transition(state_t s)
1.1       cgd       552: {
1.43      lukem     553:
1.55      christos  554:        if (s == NULL)
                    555:                return;
1.77      christos  556:        for (;;) {
1.78      he        557: #ifdef SUPPORT_UTMPX
1.77      christos  558: #ifndef LETS_GET_SMALL
                    559:                utmpx_set_runlevel(get_runlevel(current_state),
                    560:                    get_runlevel(s));
1.79      he        561:                current_state = s;
1.77      christos  562: #endif
                    563: #endif
1.47      christos  564:                s = (state_t)(*s)();
1.77      christos  565:        }
1.1       cgd       566: }
                    567:
1.64      christos  568: #ifndef LETS_GET_SMALL
1.8       cgd       569: /*
                    570:  * Close out the accounting files for a login session.
                    571:  * NB: should send a message to the session logger to avoid blocking.
                    572:  */
                    573: void
1.50      christos  574: clear_session_logs(session_t *sp, int status)
1.8       cgd       575: {
1.83      isaki     576: #if defined(SUPPORT_UTMP) || defined(SUPPORT_UTMPX)
1.8       cgd       577:        char *line = sp->se_device + sizeof(_PATH_DEV) - 1;
1.83      isaki     578: #endif
1.55      christos  579:
1.50      christos  580: #ifdef SUPPORT_UTMPX
1.51      christos  581:        if (logoutx(line, status, DEAD_PROCESS))
1.50      christos  582:                logwtmpx(line, "", "", status, DEAD_PROCESS);
                    583: #endif
                    584: #ifdef SUPPORT_UTMP
1.8       cgd       585:        if (logout(line))
                    586:                logwtmp(line, "", "");
1.50      christos  587: #endif
1.8       cgd       588: }
1.64      christos  589: #endif
1.1       cgd       590:
1.8       cgd       591: /*
                    592:  * Start a session and allocate a controlling terminal.
                    593:  * Only called by children of init after forking.
                    594:  */
                    595: void
1.40      wiz       596: setctty(const char *name)
1.1       cgd       597: {
1.8       cgd       598:        int fd;
1.1       cgd       599:
1.84    ! christos  600:        (void)revoke(name);
        !           601:        (void)nanosleep(&dtrtime, NULL);        /* leave DTR low for a bit */
1.8       cgd       602:        if ((fd = open(name, O_RDWR)) == -1) {
                    603:                stall("can't open %s: %m", name);
                    604:                _exit(1);
1.7       cgd       605:        }
1.8       cgd       606:        if (login_tty(fd) == -1) {
                    607:                stall("can't get %s for controlling terminal: %m", name);
                    608:                _exit(1);
                    609:        }
                    610: }
                    611:
                    612: /*
                    613:  * Bring the system up single user.
                    614:  */
                    615: state_func_t
1.39      wiz       616: single_user(void)
1.8       cgd       617: {
                    618:        pid_t pid, wpid;
                    619:        int status;
1.34      tls       620:        int from_securitylevel;
1.8       cgd       621:        sigset_t mask;
1.55      christos  622:        struct sigaction sa, satstp, sahup;
1.31      perry     623: #ifdef ALTSHELL
1.56      lukem     624:        const char *shell = INIT_BSHELL;
1.31      perry     625: #endif
1.70      christos  626:        const char *argv[2];
1.8       cgd       627: #ifdef SECURE
                    628:        struct ttyent *typ;
1.10      cgd       629:        struct passwd *pp;
1.8       cgd       630:        char *clear, *password;
1.7       cgd       631: #endif
1.26      perry     632: #ifdef ALTSHELL
                    633:        char altshell[128];
                    634: #endif /* ALTSHELL */
1.7       cgd       635:
1.73      salo      636: #if !defined(LETS_GET_SMALL) && defined(CHROOT)
                    637:        /* Clear previous idea, just in case. */
                    638:        did_multiuser_chroot = 0;
                    639: #endif /* !LETS_GET_SMALL && CHROOT */
                    640:
1.8       cgd       641:        /*
                    642:         * If the kernel is in secure mode, downgrade it to insecure mode.
                    643:         */
1.34      tls       644:        from_securitylevel = getsecuritylevel();
                    645:        if (from_securitylevel > 0)
1.8       cgd       646:                setsecuritylevel(0);
                    647:
1.55      christos  648:        (void)sigemptyset(&sa.sa_mask);
                    649:        sa.sa_flags = 0;
                    650:        sa.sa_handler = SIG_IGN;
                    651:        (void)sigaction(SIGTSTP, &sa, &satstp);
                    652:        (void)sigaction(SIGHUP, &sa, &sahup);
1.8       cgd       653:        if ((pid = fork()) == 0) {
                    654:                /*
                    655:                 * Start the single user session.
                    656:                 */
1.63      dsl       657:                if (access(_PATH_CONSTTY, F_OK) == 0)
                    658:                        setctty(_PATH_CONSTTY);
                    659:                else
                    660:                        setctty(_PATH_CONSOLE);
1.8       cgd       661:
                    662: #ifdef SECURE
                    663:                /*
                    664:                 * Check the root password.
                    665:                 * We don't care if the console is 'on' by default;
                    666:                 * it's the only tty that can be 'off' and 'secure'.
                    667:                 */
1.10      cgd       668:                typ = getttynam("console");
                    669:                pp = getpwnam("root");
1.34      tls       670:                if (typ && (from_securitylevel >=2 || (typ->ty_status
                    671:                    & TTY_SECURE) == 0) && pp && *pp->pw_passwd != '\0') {
1.47      christos  672:                        (void)fprintf(stderr,
1.26      perry     673:                            "Enter root password, or ^D to go multi-user\n");
1.8       cgd       674:                        for (;;) {
                    675:                                clear = getpass("Password:");
                    676:                                if (clear == 0 || *clear == '\0')
                    677:                                        _exit(0);
                    678:                                password = crypt(clear, pp->pw_passwd);
1.47      christos  679:                                (void)memset(clear, 0, _PASSWORD_LEN);
1.8       cgd       680:                                if (strcmp(password, pp->pw_passwd) == 0)
                    681:                                        break;
1.80      christos  682:                                warning("single-user login failed");
1.1       cgd       683:                        }
1.8       cgd       684:                }
1.84    ! christos  685:                (void)endttyent();
1.10      cgd       686:                endpwent();
1.9       cgd       687: #endif /* SECURE */
1.1       cgd       688:
1.26      perry     689: #ifdef ALTSHELL
1.47      christos  690:                (void)fprintf(stderr,
1.52      lukem     691:                    "Enter pathname of shell or RETURN for %s: ", shell);
1.38      wiz       692:                if (fgets(altshell, sizeof(altshell), stdin) == NULL) {
                    693:                        altshell[0] = '\0';
                    694:                } else {
                    695:                        /* nuke \n */
                    696:                        char *p;
                    697:
1.41      wiz       698:                        if ((p = strchr(altshell, '\n')) != NULL)
1.38      wiz       699:                                *p = '\0';
                    700:                }
1.26      perry     701:
                    702:                if (altshell[0])
                    703:                        shell = altshell;
                    704: #endif /* ALTSHELL */
1.8       cgd       705:
                    706:                /*
                    707:                 * Unblock signals.
                    708:                 * We catch all the interesting ones,
                    709:                 * and those are reset to SIG_DFL on exec.
                    710:                 */
1.47      christos  711:                (void)sigemptyset(&mask);
                    712:                (void)sigprocmask(SIG_SETMASK, &mask, NULL);
1.8       cgd       713:
                    714:                /*
                    715:                 * Fire off a shell.
                    716:                 * If the default one doesn't work, try the Bourne shell.
                    717:                 */
                    718:                argv[0] = "-sh";
                    719:                argv[1] = 0;
1.84    ! christos  720:                (void)setenv("PATH", INIT_PATH, 1);
1.26      perry     721: #ifdef ALTSHELL
                    722:                if (altshell[0])
                    723:                        argv[0] = altshell;
1.70      christos  724:                (void)execv(shell, __UNCONST(argv));
1.80      christos  725:                emergency("can't exec `%s' for single user: %m", shell);
1.26      perry     726:                argv[0] = "-sh";
                    727: #endif /* ALTSHELL */
1.70      christos  728:                (void)execv(INIT_BSHELL, __UNCONST(argv));
1.80      christos  729:                emergency("can't exec `%s' for single user: %m", INIT_BSHELL);
1.67      mycroft   730:                (void)sleep(STALL_TIMEOUT);
1.8       cgd       731:                _exit(1);
                    732:        }
                    733:
                    734:        if (pid == -1) {
                    735:                /*
                    736:                 * We are seriously hosed.  Do our best.
                    737:                 */
1.80      christos  738:                emergency("can't fork single-user shell: %m, trying again");
1.47      christos  739:                while (waitpid(-1, NULL, WNOHANG) > 0)
1.8       cgd       740:                        continue;
1.55      christos  741:                (void)sigaction(SIGTSTP, &satstp, NULL);
                    742:                (void)sigaction(SIGHUP, &sahup, NULL);
1.8       cgd       743:                return (state_func_t) single_user;
1.1       cgd       744:        }
1.8       cgd       745:
                    746:        requested_transition = 0;
                    747:        do {
                    748:                if ((wpid = waitpid(-1, &status, WUNTRACED)) != -1)
1.50      christos  749:                        collect_child(wpid, status);
1.8       cgd       750:                if (wpid == -1) {
                    751:                        if (errno == EINTR)
                    752:                                continue;
1.47      christos  753:                        warning("wait for single-user shell failed: %m; "
                    754:                            "restarting");
                    755:                        return (state_func_t)single_user;
1.8       cgd       756:                }
                    757:                if (wpid == pid && WIFSTOPPED(status)) {
1.80      christos  758:                        warning("shell stopped, restarting");
1.84    ! christos  759:                        (void)kill(pid, SIGCONT);
1.8       cgd       760:                        wpid = -1;
                    761:                }
                    762:        } while (wpid != pid && !requested_transition);
1.1       cgd       763:
1.55      christos  764:        if (requested_transition) {
                    765:                (void)sigaction(SIGTSTP, &satstp, NULL);
                    766:                (void)sigaction(SIGHUP, &sahup, NULL);
1.47      christos  767:                return (state_func_t)requested_transition;
1.55      christos  768:        }
1.1       cgd       769:
1.49      mycroft   770:        if (WIFSIGNALED(status)) {
                    771:                if (WTERMSIG(status) == SIGKILL) {
                    772:                        /* executed /sbin/reboot; wait for the end quietly */
                    773:                        sigset_t s;
                    774:
                    775:                        (void)sigfillset(&s);
                    776:                        for (;;)
                    777:                                (void)sigsuspend(&s);
1.8       cgd       778:                } else {
                    779:                        warning("single user shell terminated, restarting");
1.55      christos  780:                        (void)sigaction(SIGTSTP, &satstp, NULL);
                    781:                        (void)sigaction(SIGHUP, &sahup, NULL);
1.8       cgd       782:                        return (state_func_t) single_user;
1.1       cgd       783:                }
1.8       cgd       784:        }
                    785:
                    786:        runcom_mode = FASTBOOT;
1.55      christos  787:        (void)sigaction(SIGTSTP, &satstp, NULL);
                    788:        (void)sigaction(SIGHUP, &sahup, NULL);
1.13      cgd       789: #ifndef LETS_GET_SMALL
1.8       cgd       790:        return (state_func_t) runcom;
1.13      cgd       791: #else /* LETS_GET_SMALL */
                    792:        return (state_func_t) single_user;
                    793: #endif /* LETS_GET_SMALL */
1.8       cgd       794: }
                    795:
1.13      cgd       796: #ifndef LETS_GET_SMALL
1.73      salo      797:
                    798: /* ARGSUSED */
1.8       cgd       799: state_func_t
1.73      salo      800: runetcrc(int trychroot)
1.8       cgd       801: {
                    802:        pid_t pid, wpid;
                    803:        int status;
1.70      christos  804:        const char *argv[4];
1.8       cgd       805:        struct sigaction sa;
                    806:
1.47      christos  807:        switch ((pid = fork())) {
                    808:        case 0:
                    809:                (void)sigemptyset(&sa.sa_mask);
1.8       cgd       810:                sa.sa_flags = 0;
                    811:                sa.sa_handler = SIG_IGN;
1.47      christos  812:                (void)sigaction(SIGTSTP, &sa, NULL);
                    813:                (void)sigaction(SIGHUP, &sa, NULL);
1.8       cgd       814:
                    815:                setctty(_PATH_CONSOLE);
                    816:
                    817:                argv[0] = "sh";
                    818:                argv[1] = _PATH_RUNCOM;
1.73      salo      819:                argv[2] = (runcom_mode == AUTOBOOT ? "autoboot" : 0);
1.8       cgd       820:                argv[3] = 0;
                    821:
1.47      christos  822:                (void)sigprocmask(SIG_SETMASK, &sa.sa_mask, NULL);
1.8       cgd       823:
1.73      salo      824: #ifdef CHROOT
                    825:                if (trychroot)
                    826:                        if (chroot(rootdir) != 0) {
1.80      christos  827:                                warning("failed to chroot to `%s': %m",
1.73      salo      828:                                    rootdir);
                    829:                                _exit(1);       /* force single user mode */
                    830:                        }
                    831: #endif /* CHROOT */
                    832:
1.70      christos  833:                (void)execv(INIT_BSHELL, __UNCONST(argv));
1.80      christos  834:                stall("can't exec `%s' for `%s': %m", INIT_BSHELL, _PATH_RUNCOM);
1.8       cgd       835:                _exit(1);       /* force single user mode */
1.47      christos  836:                /*NOTREACHED*/
                    837:        case -1:
1.80      christos  838:                emergency("can't fork for `%s' on `%s': %m", INIT_BSHELL,
1.47      christos  839:                    _PATH_RUNCOM);
                    840:                while (waitpid(-1, NULL, WNOHANG) > 0)
1.1       cgd       841:                        continue;
1.47      christos  842:                (void)sleep(STALL_TIMEOUT);
                    843:                return (state_func_t)single_user;
                    844:        default:
                    845:                break;
1.8       cgd       846:        }
                    847:
                    848:        /*
                    849:         * Copied from single_user().  This is a bit paranoid.
                    850:         */
                    851:        do {
                    852:                if ((wpid = waitpid(-1, &status, WUNTRACED)) != -1)
1.50      christos  853:                        collect_child(wpid, status);
1.8       cgd       854:                if (wpid == -1) {
                    855:                        if (errno == EINTR)
                    856:                                continue;
1.80      christos  857:                        warning("wait for `%s' on `%s' failed: %m; going to "
1.56      lukem     858:                            "single user mode", INIT_BSHELL, _PATH_RUNCOM);
1.47      christos  859:                        return (state_func_t)single_user;
1.8       cgd       860:                }
                    861:                if (wpid == pid && WIFSTOPPED(status)) {
1.80      christos  862:                        warning("`%s' on `%s' stopped, restarting",
1.56      lukem     863:                            INIT_BSHELL, _PATH_RUNCOM);
1.47      christos  864:                        (void)kill(pid, SIGCONT);
1.8       cgd       865:                        wpid = -1;
                    866:                }
                    867:        } while (wpid != pid);
                    868:
                    869:        if (WIFSIGNALED(status) && WTERMSIG(status) == SIGTERM &&
                    870:            requested_transition == catatonia) {
                    871:                /* /etc/rc executed /sbin/reboot; wait for the end quietly */
                    872:                sigset_t s;
                    873:
1.47      christos  874:                (void)sigfillset(&s);
1.8       cgd       875:                for (;;)
1.47      christos  876:                        (void)sigsuspend(&s);
1.8       cgd       877:        }
                    878:
                    879:        if (!WIFEXITED(status)) {
1.80      christos  880:                warning("`%s' on `%s' terminated abnormally, going to "
1.56      lukem     881:                    "single user mode", INIT_BSHELL, _PATH_RUNCOM);
1.47      christos  882:                return (state_func_t)single_user;
1.8       cgd       883:        }
                    884:
                    885:        if (WEXITSTATUS(status))
1.47      christos  886:                return (state_func_t)single_user;
1.8       cgd       887:
1.73      salo      888:        return (state_func_t) read_ttys;
                    889: }
                    890:
                    891: /*
                    892:  * Run the system startup script.
                    893:  */
                    894: state_func_t
                    895: runcom(void)
                    896: {
                    897:        state_func_t next_step;
                    898:
                    899:        /* Run /etc/rc and choose next state depending on the result. */
                    900:        next_step = runetcrc(0);
                    901:        if (next_step != (state_func_t) read_ttys)
                    902:                return (state_func_t) next_step;
                    903:
                    904: #ifdef CHROOT
                    905:        /*
                    906:         * If init.root sysctl does not point to "/", we'll chroot and run
                    907:         * The Real(tm) /etc/rc now.  Global variable rootdir will tell us
                    908:         * where to go.
                    909:         */
                    910:        if (shouldchroot()) {
                    911:                next_step = runetcrc(1);
                    912:                if (next_step != (state_func_t) read_ttys)
                    913:                        return (state_func_t) next_step;
                    914:
                    915:                did_multiuser_chroot = 1;
                    916:        } else {
                    917:                did_multiuser_chroot = 0;
                    918:        }
                    919: #endif /* CHROOT */
                    920:
                    921:        /*
                    922:         * Regardless of whether in chroot or not, we booted successfuly.
                    923:         * It's time to spawn gettys (ie. next_step's value at this point).
                    924:         */
1.8       cgd       925:        runcom_mode = AUTOBOOT;         /* the default */
                    926:        /* NB: should send a message to the session logger to avoid blocking. */
1.51      christos  927: #ifdef SUPPORT_UTMPX
1.50      christos  928:        logwtmpx("~", "reboot", "", 0, INIT_PROCESS);
                    929: #endif
1.51      christos  930: #ifdef SUPPORT_UTMP
1.8       cgd       931:        logwtmp("~", "reboot", "");
1.50      christos  932: #endif
1.8       cgd       933:        return (state_func_t) read_ttys;
                    934: }
                    935:
                    936: /*
                    937:  * Open the session database.
                    938:  *
                    939:  * NB: We could pass in the size here; is it necessary?
                    940:  */
                    941: int
1.39      wiz       942: start_session_db(void)
1.8       cgd       943: {
1.43      lukem     944:
1.8       cgd       945:        if (session_db && (*session_db->close)(session_db))
1.47      christos  946:                emergency("session database close: %m");
1.8       cgd       947:        if ((session_db = dbopen(NULL, O_RDWR, 0, DB_HASH, NULL)) == 0) {
1.47      christos  948:                emergency("session database open: %m");
1.8       cgd       949:                return (1);
                    950:        }
                    951:        return (0);
                    952:
                    953: }
                    954:
                    955: /*
                    956:  * Add a new login session.
                    957:  */
                    958: void
1.39      wiz       959: add_session(session_t *sp)
1.8       cgd       960: {
                    961:        DBT key;
                    962:        DBT data;
                    963:
1.55      christos  964:        if (session_db == NULL)
                    965:                return;
                    966:
1.8       cgd       967:        key.data = &sp->se_process;
                    968:        key.size = sizeof sp->se_process;
                    969:        data.data = &sp;
                    970:        data.size = sizeof sp;
                    971:
                    972:        if ((*session_db->put)(session_db, &key, &data, 0))
1.47      christos  973:                emergency("insert %d: %m", sp->se_process);
1.77      christos  974: #ifdef SUPPORT_UTMPX
                    975:        session_utmpx(sp, 1);
                    976: #endif
1.8       cgd       977: }
                    978:
                    979: /*
                    980:  * Delete an old login session.
                    981:  */
                    982: void
1.39      wiz       983: del_session(session_t *sp)
1.8       cgd       984: {
                    985:        DBT key;
                    986:
                    987:        key.data = &sp->se_process;
                    988:        key.size = sizeof sp->se_process;
                    989:
                    990:        if ((*session_db->del)(session_db, &key, 0))
1.47      christos  991:                emergency("delete %d: %m", sp->se_process);
1.77      christos  992: #ifdef SUPPORT_UTMPX
                    993:        session_utmpx(sp, 0);
                    994: #endif
1.8       cgd       995: }
                    996:
                    997: /*
                    998:  * Look up a login session by pid.
                    999:  */
                   1000: session_t *
                   1001: find_session(pid_t pid)
                   1002: {
                   1003:        DBT key;
                   1004:        DBT data;
                   1005:        session_t *ret;
                   1006:
1.55      christos 1007:        if (session_db == NULL)
                   1008:                return NULL;
                   1009:
1.8       cgd      1010:        key.data = &pid;
                   1011:        key.size = sizeof pid;
                   1012:        if ((*session_db->get)(session_db, &key, &data, 0) != 0)
                   1013:                return 0;
1.47      christos 1014:        (void)memmove(&ret, data.data, sizeof(ret));
1.8       cgd      1015:        return ret;
                   1016: }
                   1017:
                   1018: /*
                   1019:  * Construct an argument vector from a command line.
                   1020:  */
                   1021: char **
1.39      wiz      1022: construct_argv(char *command)
1.8       cgd      1023: {
1.27      perry    1024:        int argc = 0;
1.47      christos 1025:        char **argv = malloc(((strlen(command) + 1) / 2 + 1) * sizeof (char *));
1.8       cgd      1026:        static const char separators[] = " \t";
                   1027:
1.71      chris    1028:        if (argv == NULL)
1.27      perry    1029:                return (NULL);
1.71      chris    1030:
                   1031:        if ((argv[argc++] = strtok(command, separators)) == 0) {
                   1032:                free(argv);
                   1033:                return (NULL);
                   1034:        }
1.47      christos 1035:        while ((argv[argc++] = strtok(NULL, separators)) != NULL)
1.8       cgd      1036:                continue;
1.27      perry    1037:        return (argv);
1.8       cgd      1038: }
                   1039:
                   1040: /*
                   1041:  * Deallocate a session descriptor.
                   1042:  */
                   1043: void
1.39      wiz      1044: free_session(session_t *sp)
1.8       cgd      1045: {
1.43      lukem    1046:
1.8       cgd      1047:        free(sp->se_device);
                   1048:        if (sp->se_getty) {
                   1049:                free(sp->se_getty);
                   1050:                free(sp->se_getty_argv);
                   1051:        }
                   1052:        if (sp->se_window) {
                   1053:                free(sp->se_window);
                   1054:                free(sp->se_window_argv);
                   1055:        }
                   1056:        free(sp);
                   1057: }
                   1058:
                   1059: /*
                   1060:  * Allocate a new session descriptor.
                   1061:  */
                   1062: session_t *
1.39      wiz      1063: new_session(session_t *sprev, int session_index, struct ttyent *typ)
1.8       cgd      1064: {
1.27      perry    1065:        session_t *sp;
1.8       cgd      1066:
1.47      christos 1067:        if ((typ->ty_status & TTY_ON) == 0 || typ->ty_name == NULL ||
1.27      perry    1068:            typ->ty_getty == NULL)
                   1069:                return (NULL);
1.8       cgd      1070:
1.47      christos 1071:        sp = malloc(sizeof (session_t));
1.55      christos 1072:        if (sp == NULL)
                   1073:                return NULL;
1.84    ! christos 1074:        (void)memset(sp, 0, sizeof *sp);
1.8       cgd      1075:
1.21      mycroft  1076:        sp->se_flags = SE_PRESENT;
1.8       cgd      1077:        sp->se_index = session_index;
                   1078:
1.59      itojun   1079:        (void)asprintf(&sp->se_device, "%s%s", _PATH_DEV, typ->ty_name);
                   1080:        if (!sp->se_device)
                   1081:                return NULL;
1.8       cgd      1082:
                   1083:        if (setupargv(sp, typ) == 0) {
                   1084:                free_session(sp);
1.27      perry    1085:                return (NULL);
1.8       cgd      1086:        }
                   1087:
1.27      perry    1088:        sp->se_next = NULL;
                   1089:        if (sprev == NULL) {
1.8       cgd      1090:                sessions = sp;
1.27      perry    1091:                sp->se_prev = NULL;
1.8       cgd      1092:        } else {
                   1093:                sprev->se_next = sp;
                   1094:                sp->se_prev = sprev;
                   1095:        }
                   1096:
1.27      perry    1097:        return (sp);
1.8       cgd      1098: }
                   1099:
                   1100: /*
                   1101:  * Calculate getty and if useful window argv vectors.
                   1102:  */
                   1103: int
1.39      wiz      1104: setupargv(session_t *sp, struct ttyent *typ)
1.8       cgd      1105: {
                   1106:
                   1107:        if (sp->se_getty) {
                   1108:                free(sp->se_getty);
                   1109:                free(sp->se_getty_argv);
                   1110:        }
1.59      itojun   1111:        (void)asprintf(&sp->se_getty, "%s %s", typ->ty_getty, typ->ty_name);
                   1112:        if (!sp->se_getty)
                   1113:                return (0);
1.8       cgd      1114:        sp->se_getty_argv = construct_argv(sp->se_getty);
1.27      perry    1115:        if (sp->se_getty_argv == NULL) {
1.80      christos 1116:                warning("can't parse getty for port `%s'", sp->se_device);
1.8       cgd      1117:                free(sp->se_getty);
1.27      perry    1118:                sp->se_getty = NULL;
1.8       cgd      1119:                return (0);
                   1120:        }
                   1121:        if (typ->ty_window) {
                   1122:                if (sp->se_window)
                   1123:                        free(sp->se_window);
                   1124:                sp->se_window = strdup(typ->ty_window);
                   1125:                sp->se_window_argv = construct_argv(sp->se_window);
1.27      perry    1126:                if (sp->se_window_argv == NULL) {
1.80      christos 1127:                        warning("can't parse window for port `%s'",
1.47      christos 1128:                            sp->se_device);
1.8       cgd      1129:                        free(sp->se_window);
1.27      perry    1130:                        sp->se_window = NULL;
1.8       cgd      1131:                        return (0);
1.1       cgd      1132:                }
1.8       cgd      1133:        }
                   1134:        return (1);
                   1135: }
                   1136:
                   1137: /*
                   1138:  * Walk the list of ttys and create sessions for each active line.
                   1139:  */
                   1140: state_func_t
1.39      wiz      1141: read_ttys(void)
1.8       cgd      1142: {
                   1143:        int session_index = 0;
1.27      perry    1144:        session_t *sp, *snext;
                   1145:        struct ttyent *typ;
1.8       cgd      1146:
1.77      christos 1147: #ifdef SUPPORT_UTMPX
                   1148:        if (sessions == NULL) {
                   1149:                struct stat st;
                   1150:
                   1151:                make_utmpx("", BOOT_MSG, BOOT_TIME, 0, &boot_time, 0);
                   1152:
                   1153:                /*
                   1154:                 * If wtmpx is not empty, pick the the down time from there
                   1155:                 */
                   1156:                if (stat(_PATH_WTMPX, &st) != -1 && st.st_size != 0) {
                   1157:                        struct timeval down_time;
                   1158:
                   1159:                        TIMESPEC_TO_TIMEVAL(&down_time,
                   1160:                            st.st_atime > st.st_mtime ?
                   1161:                            &st.st_atimespec : &st.st_mtimespec);
                   1162:                        make_utmpx("", DOWN_MSG, DOWN_TIME, 0, &down_time, 0);
                   1163:                }
                   1164:        }
                   1165: #endif
1.8       cgd      1166:        /*
                   1167:         * Destroy any previous session state.
                   1168:         * There shouldn't be any, but just in case...
                   1169:         */
                   1170:        for (sp = sessions; sp; sp = snext) {
1.64      christos 1171: #ifndef LETS_GET_SMALL
1.8       cgd      1172:                if (sp->se_process)
1.50      christos 1173:                        clear_session_logs(sp, 0);
1.64      christos 1174: #endif
1.8       cgd      1175:                snext = sp->se_next;
                   1176:                free_session(sp);
                   1177:        }
1.27      perry    1178:        sessions = NULL;
1.73      salo     1179:
                   1180:        if (start_session_db()) {
1.80      christos 1181:                warning("start_session_db failed, death");
1.73      salo     1182: #ifdef CHROOT
                   1183:                /* If /etc/rc ran in chroot, we want to kill any survivors. */
                   1184:                if (did_multiuser_chroot)
                   1185:                        return (state_func_t)death;
                   1186:                else
                   1187: #endif /* CHROOT */
                   1188:                        return (state_func_t)single_user;
                   1189:        }
                   1190:
1.84    ! christos 1191:        (void)do_setttyent();
1.8       cgd      1192:
                   1193:        /*
                   1194:         * Allocate a session entry for each active port.
                   1195:         * Note that sp starts at 0.
                   1196:         */
1.27      perry    1197:        while ((typ = getttyent()) != NULL)
                   1198:                if ((snext = new_session(sp, ++session_index, typ)) != NULL)
1.8       cgd      1199:                        sp = snext;
1.84    ! christos 1200:        (void)endttyent();
1.8       cgd      1201:
1.47      christos 1202:        return (state_func_t)multi_user;
1.8       cgd      1203: }
                   1204:
                   1205: /*
                   1206:  * Start a window system running.
                   1207:  */
                   1208: void
1.39      wiz      1209: start_window_system(session_t *sp)
1.8       cgd      1210: {
                   1211:        pid_t pid;
                   1212:        sigset_t mask;
                   1213:
                   1214:        if ((pid = fork()) == -1) {
1.80      christos 1215:                emergency("can't fork for window system on port `%s': %m",
1.47      christos 1216:                    sp->se_device);
1.8       cgd      1217:                /* hope that getty fails and we can try again */
                   1218:                return;
                   1219:        }
                   1220:
                   1221:        if (pid)
                   1222:                return;
                   1223:
1.84    ! christos 1224:        (void)sigemptyset(&mask);
        !          1225:        (void)sigprocmask(SIG_SETMASK, &mask, NULL);
1.8       cgd      1226:
                   1227:        if (setsid() < 0)
1.80      christos 1228:                emergency("setsid failed (window): %m");
1.8       cgd      1229:
1.47      christos 1230:        (void)execv(sp->se_window_argv[0], sp->se_window_argv);
1.80      christos 1231:        stall("can't exec window system `%s' for port `%s': %m",
1.47      christos 1232:            sp->se_window_argv[0], sp->se_device);
1.8       cgd      1233:        _exit(1);
                   1234: }
                   1235:
                   1236: /*
                   1237:  * Start a login session running.
                   1238:  */
                   1239: pid_t
1.39      wiz      1240: start_getty(session_t *sp)
1.8       cgd      1241: {
                   1242:        pid_t pid;
                   1243:        sigset_t mask;
1.47      christos 1244:        time_t current_time = time(NULL);
1.8       cgd      1245:
                   1246:        /*
                   1247:         * fork(), not vfork() -- we can't afford to block.
                   1248:         */
                   1249:        if ((pid = fork()) == -1) {
1.80      christos 1250:                emergency("can't fork for getty on port `%s': %m",
                   1251:                    sp->se_device);
1.8       cgd      1252:                return -1;
                   1253:        }
                   1254:
                   1255:        if (pid)
                   1256:                return pid;
                   1257:
1.73      salo     1258: #ifdef CHROOT
                   1259:        /* If /etc/rc did proceed inside chroot, we have to try as well. */
                   1260:        if (did_multiuser_chroot)
                   1261:                if (chroot(rootdir) != 0) {
1.80      christos 1262:                        stall("can't chroot getty `%s' inside `%s': %m",
1.73      salo     1263:                            sp->se_getty_argv[0], rootdir);
                   1264:                        _exit(1);
                   1265:                }
                   1266: #endif /* CHROOT */
                   1267:
1.77      christos 1268:        if (current_time > sp->se_started.tv_sec &&
                   1269:            current_time - sp->se_started.tv_sec < GETTY_SPACING) {
1.80      christos 1270:                warning("getty repeating too quickly on port `%s', sleeping",
1.47      christos 1271:                    sp->se_device);
                   1272:                (void)sleep(GETTY_SLEEP);
1.8       cgd      1273:        }
                   1274:
                   1275:        if (sp->se_window) {
                   1276:                start_window_system(sp);
1.47      christos 1277:                (void)sleep(WINDOW_WAIT);
1.1       cgd      1278:        }
1.8       cgd      1279:
1.47      christos 1280:        (void)sigemptyset(&mask);
                   1281:        (void)sigprocmask(SIG_SETMASK, &mask, (sigset_t *) 0);
1.8       cgd      1282:
1.47      christos 1283:        (void)execv(sp->se_getty_argv[0], sp->se_getty_argv);
1.80      christos 1284:        stall("can't exec getty `%s' for port `%s': %m",
1.47      christos 1285:            sp->se_getty_argv[0], sp->se_device);
1.8       cgd      1286:        _exit(1);
1.47      christos 1287:        /*NOTREACHED*/
1.1       cgd      1288: }
1.77      christos 1289: #ifdef SUPPORT_UTMPX
                   1290: static void
                   1291: session_utmpx(const session_t *sp, int add)
                   1292: {
                   1293:        const char *name = sp->se_getty ? sp->se_getty :
                   1294:            (sp->se_window ? sp->se_window : "");
                   1295:        const char *line = sp->se_device + sizeof(_PATH_DEV) - 1;
                   1296:
                   1297:        make_utmpx(name, line, add ? LOGIN_PROCESS : DEAD_PROCESS,
                   1298:            sp->se_process, &sp->se_started, sp->se_index);
                   1299: }
                   1300:
                   1301: static void
                   1302: make_utmpx(const char *name, const char *line, int type, pid_t pid,
                   1303:     const struct timeval *tv, int session)
                   1304: {
                   1305:        struct utmpx ut;
                   1306:        const char *eline;
                   1307:
                   1308:        (void)memset(&ut, 0, sizeof(ut));
                   1309:        (void)strlcpy(ut.ut_name, name, sizeof(ut.ut_name));
                   1310:        ut.ut_type = type;
                   1311:        (void)strlcpy(ut.ut_line, line, sizeof(ut.ut_line));
                   1312:        ut.ut_pid = pid;
                   1313:        if (tv)
                   1314:                ut.ut_tv = *tv;
                   1315:        else
                   1316:                (void)gettimeofday(&ut.ut_tv, NULL);
                   1317:        ut.ut_session = session;
                   1318:
                   1319:        eline = line + strlen(line);
                   1320:        if (eline - line >= sizeof(ut.ut_id))
                   1321:                line = eline - sizeof(ut.ut_id);
                   1322:        (void)strncpy(ut.ut_id, line, sizeof(ut.ut_id));
                   1323:
                   1324:        if (pututxline(&ut) == NULL)
1.80      christos 1325:                warning("can't add utmpx record for `%s': %m", ut.ut_line);
1.84    ! christos 1326:        endutxent();
1.77      christos 1327: }
                   1328:
                   1329: static char
                   1330: get_runlevel(const state_t s)
                   1331: {
                   1332:        if (s == (state_t)single_user)
                   1333:                return SINGLE_USER;
                   1334:        if (s == (state_t)runcom)
                   1335:                return RUNCOM;
                   1336:        if (s == (state_t)read_ttys)
                   1337:                return READ_TTYS;
                   1338:        if (s == (state_t)multi_user)
                   1339:                return MULTI_USER;
                   1340:        if (s == (state_t)clean_ttys)
                   1341:                return CLEAN_TTYS;
                   1342:        if (s == (state_t)catatonia)
                   1343:                return CATATONIA;
                   1344:        return DEATH;
                   1345: }
                   1346:
                   1347: static void
                   1348: utmpx_set_runlevel(char old, char new)
                   1349: {
                   1350:        struct utmpx ut;
                   1351:
1.81      christos 1352:        /*
                   1353:         * Don't record any transitions until we did the first transition
                   1354:         * to read ttys, which is when we are guaranteed to have a read-write
                   1355:         * /var. Perhaps use a different variable for this?
                   1356:         */
                   1357:        if (sessions == NULL)
                   1358:                return;
                   1359:
1.77      christos 1360:        (void)memset(&ut, 0, sizeof(ut));
                   1361:        (void)snprintf(ut.ut_line, sizeof(ut.ut_line), RUNLVL_MSG, new);
                   1362:        ut.ut_type = RUN_LVL;
                   1363:        (void)gettimeofday(&ut.ut_tv, NULL);
                   1364:        ut.ut_exit.e_exit = old;
                   1365:        ut.ut_exit.e_termination = new;
                   1366:        if (pututxline(&ut) == NULL)
1.80      christos 1367:                warning("can't add utmpx record for `runlevel': %m");
1.84    ! christos 1368:        endutxent();
1.77      christos 1369: }
                   1370: #endif /* SUPPORT_UTMPX */
                   1371:
1.13      cgd      1372: #endif /* LETS_GET_SMALL */
1.1       cgd      1373:
1.8       cgd      1374: /*
                   1375:  * Collect exit status for a child.
                   1376:  * If an exiting login, start a new login running.
                   1377:  */
                   1378: void
1.50      christos 1379: collect_child(pid_t pid, int status)
1.1       cgd      1380: {
1.13      cgd      1381: #ifndef LETS_GET_SMALL
1.27      perry    1382:        session_t *sp, *sprev, *snext;
1.8       cgd      1383:
                   1384:        if (! sessions)
                   1385:                return;
                   1386:
1.47      christos 1387:        if ((sp = find_session(pid)) == NULL)
1.8       cgd      1388:                return;
1.1       cgd      1389:
1.50      christos 1390:        clear_session_logs(sp, status);
1.8       cgd      1391:        del_session(sp);
                   1392:        sp->se_process = 0;
                   1393:
                   1394:        if (sp->se_flags & SE_SHUTDOWN) {
1.27      perry    1395:                if ((sprev = sp->se_prev) != NULL)
1.8       cgd      1396:                        sprev->se_next = sp->se_next;
                   1397:                else
                   1398:                        sessions = sp->se_next;
1.27      perry    1399:                if ((snext = sp->se_next) != NULL)
1.8       cgd      1400:                        snext->se_prev = sp->se_prev;
                   1401:                free_session(sp);
1.1       cgd      1402:                return;
                   1403:        }
1.8       cgd      1404:
                   1405:        if ((pid = start_getty(sp)) == -1) {
                   1406:                /* serious trouble */
                   1407:                requested_transition = clean_ttys;
1.1       cgd      1408:                return;
                   1409:        }
1.8       cgd      1410:
                   1411:        sp->se_process = pid;
1.77      christos 1412:        (void)gettimeofday(&sp->se_started, NULL);
1.8       cgd      1413:        add_session(sp);
1.13      cgd      1414: #endif /* LETS_GET_SMALL */
1.8       cgd      1415: }
                   1416:
                   1417: /*
                   1418:  * Catch a signal and request a state transition.
                   1419:  */
                   1420: void
1.39      wiz      1421: transition_handler(int sig)
1.8       cgd      1422: {
                   1423:
                   1424:        switch (sig) {
1.13      cgd      1425: #ifndef LETS_GET_SMALL
1.8       cgd      1426:        case SIGHUP:
                   1427:                requested_transition = clean_ttys;
                   1428:                break;
                   1429:        case SIGTERM:
                   1430:                requested_transition = death;
                   1431:                break;
                   1432:        case SIGTSTP:
                   1433:                requested_transition = catatonia;
                   1434:                break;
1.13      cgd      1435: #endif /* LETS_GET_SMALL */
1.8       cgd      1436:        default:
                   1437:                requested_transition = 0;
                   1438:                break;
                   1439:        }
                   1440: }
                   1441:
1.13      cgd      1442: #ifndef LETS_GET_SMALL
1.8       cgd      1443: /*
                   1444:  * Take the system multiuser.
                   1445:  */
                   1446: state_func_t
1.39      wiz      1447: multi_user(void)
1.8       cgd      1448: {
                   1449:        pid_t pid;
1.50      christos 1450:        int status;
1.27      perry    1451:        session_t *sp;
1.8       cgd      1452:
                   1453:        requested_transition = 0;
                   1454:
                   1455:        /*
                   1456:         * If the administrator has not set the security level to -1
                   1457:         * to indicate that the kernel should not run multiuser in secure
                   1458:         * mode, and the run script has not set a higher level of security
                   1459:         * than level 1, then put the kernel into secure mode.
                   1460:         */
                   1461:        if (getsecuritylevel() == 0)
                   1462:                setsecuritylevel(1);
                   1463:
                   1464:        for (sp = sessions; sp; sp = sp->se_next) {
                   1465:                if (sp->se_process)
                   1466:                        continue;
                   1467:                if ((pid = start_getty(sp)) == -1) {
                   1468:                        /* serious trouble */
                   1469:                        requested_transition = clean_ttys;
1.1       cgd      1470:                        break;
1.8       cgd      1471:                }
                   1472:                sp->se_process = pid;
1.77      christos 1473:                (void)gettimeofday(&sp->se_started, NULL);
1.8       cgd      1474:                add_session(sp);
1.1       cgd      1475:        }
1.8       cgd      1476:
                   1477:        while (!requested_transition)
1.50      christos 1478:                if ((pid = waitpid(-1, &status, 0)) != -1)
                   1479:                        collect_child(pid, status);
1.8       cgd      1480:
1.47      christos 1481:        return (state_func_t)requested_transition;
1.1       cgd      1482: }
                   1483:
1.8       cgd      1484: /*
                   1485:  * This is an n-squared algorithm.  We hope it isn't run often...
                   1486:  */
                   1487: state_func_t
1.39      wiz      1488: clean_ttys(void)
1.1       cgd      1489: {
1.27      perry    1490:        session_t *sp, *sprev;
                   1491:        struct ttyent *typ;
                   1492:        int session_index = 0;
                   1493:        int devlen;
1.8       cgd      1494:
1.21      mycroft  1495:        for (sp = sessions; sp; sp = sp->se_next)
                   1496:                sp->se_flags &= ~SE_PRESENT;
                   1497:
1.84    ! christos 1498:        (void)do_setttyent();
1.73      salo     1499:
1.8       cgd      1500:        devlen = sizeof(_PATH_DEV) - 1;
1.27      perry    1501:        while ((typ = getttyent()) != NULL) {
1.8       cgd      1502:                ++session_index;
                   1503:
                   1504:                for (sprev = 0, sp = sessions; sp; sprev = sp, sp = sp->se_next)
                   1505:                        if (strcmp(typ->ty_name, sp->se_device + devlen) == 0)
                   1506:                                break;
                   1507:
                   1508:                if (sp) {
1.21      mycroft  1509:                        sp->se_flags |= SE_PRESENT;
1.8       cgd      1510:                        if (sp->se_index != session_index) {
1.80      christos 1511:                                warning("port `%s' changed utmp index from "
1.47      christos 1512:                                    "%d to %d", sp->se_device, sp->se_index,
                   1513:                                    session_index);
1.8       cgd      1514:                                sp->se_index = session_index;
                   1515:                        }
                   1516:                        if ((typ->ty_status & TTY_ON) == 0 ||
                   1517:                            typ->ty_getty == 0) {
                   1518:                                sp->se_flags |= SE_SHUTDOWN;
1.55      christos 1519:                                if (sp->se_process != 0)
                   1520:                                        (void)kill(sp->se_process, SIGHUP);
1.8       cgd      1521:                                continue;
                   1522:                        }
                   1523:                        sp->se_flags &= ~SE_SHUTDOWN;
                   1524:                        if (setupargv(sp, typ) == 0) {
1.80      christos 1525:                                warning("can't parse getty for port `%s'",
1.47      christos 1526:                                    sp->se_device);
1.8       cgd      1527:                                sp->se_flags |= SE_SHUTDOWN;
1.55      christos 1528:                                if (sp->se_process != 0)
                   1529:                                        (void)kill(sp->se_process, SIGHUP);
1.8       cgd      1530:                        }
                   1531:                        continue;
                   1532:                }
                   1533:
1.84    ! christos 1534:                (void)new_session(sprev, session_index, typ);
1.8       cgd      1535:        }
                   1536:
1.84    ! christos 1537:        (void)endttyent();
1.21      mycroft  1538:
                   1539:        for (sp = sessions; sp; sp = sp->se_next)
                   1540:                if ((sp->se_flags & SE_PRESENT) == 0) {
                   1541:                        sp->se_flags |= SE_SHUTDOWN;
1.55      christos 1542:                        if (sp->se_process != 0)
                   1543:                                (void)kill(sp->se_process, SIGHUP);
1.21      mycroft  1544:                }
1.1       cgd      1545:
1.47      christos 1546:        return (state_func_t)multi_user;
1.1       cgd      1547: }
                   1548:
1.8       cgd      1549: /*
                   1550:  * Block further logins.
                   1551:  */
                   1552: state_func_t
1.39      wiz      1553: catatonia(void)
1.1       cgd      1554: {
1.27      perry    1555:        session_t *sp;
1.8       cgd      1556:
                   1557:        for (sp = sessions; sp; sp = sp->se_next)
                   1558:                sp->se_flags |= SE_SHUTDOWN;
1.1       cgd      1559:
1.47      christos 1560:        return (state_func_t)multi_user;
1.1       cgd      1561: }
1.13      cgd      1562: #endif /* LETS_GET_SMALL */
1.1       cgd      1563:
1.8       cgd      1564: /*
                   1565:  * Note SIGALRM.
                   1566:  */
                   1567: void
1.47      christos 1568: /*ARGSUSED*/
1.39      wiz      1569: alrm_handler(int sig)
1.1       cgd      1570: {
1.43      lukem    1571:
1.8       cgd      1572:        clang = 1;
1.1       cgd      1573: }
                   1574:
1.13      cgd      1575: #ifndef LETS_GET_SMALL
1.8       cgd      1576: /*
                   1577:  * Bring the system down to single user.
                   1578:  */
                   1579: state_func_t
1.39      wiz      1580: death(void)
1.1       cgd      1581: {
1.27      perry    1582:        session_t *sp;
1.50      christos 1583:        int i, status;
1.8       cgd      1584:        pid_t pid;
                   1585:        static const int death_sigs[3] = { SIGHUP, SIGTERM, SIGKILL };
                   1586:
                   1587:        for (sp = sessions; sp; sp = sp->se_next)
                   1588:                sp->se_flags |= SE_SHUTDOWN;
                   1589:
                   1590:        /* NB: should send a message to the session logger to avoid blocking. */
1.50      christos 1591: #ifdef SUPPORT_UTMPX
                   1592:        logwtmpx("~", "shutdown", "", 0, INIT_PROCESS);
                   1593: #endif
                   1594: #ifdef SUPPORT_UTMP
1.8       cgd      1595:        logwtmp("~", "shutdown", "");
1.50      christos 1596: #endif
1.8       cgd      1597:
                   1598:        for (i = 0; i < 3; ++i) {
                   1599:                if (kill(-1, death_sigs[i]) == -1 && errno == ESRCH)
1.47      christos 1600:                        return (state_func_t)single_user;
1.8       cgd      1601:
                   1602:                clang = 0;
1.84    ! christos 1603:                (void)alarm(DEATH_WATCH);
1.8       cgd      1604:                do
1.50      christos 1605:                        if ((pid = waitpid(-1, &status, 0)) != -1)
                   1606:                                collect_child(pid, status);
1.8       cgd      1607:                while (clang == 0 && errno != ECHILD);
                   1608:
                   1609:                if (errno == ECHILD)
1.47      christos 1610:                        return (state_func_t)single_user;
1.8       cgd      1611:        }
                   1612:
                   1613:        warning("some processes would not die; ps axl advised");
                   1614:
1.47      christos 1615:        return (state_func_t)single_user;
1.1       cgd      1616: }
1.13      cgd      1617: #endif /* LETS_GET_SMALL */
1.28      christos 1618:
1.45      abs      1619: #ifdef MFS_DEV_IF_NO_CONSOLE
1.28      christos 1620:
1.58      christos 1621: static void
                   1622: mapfile(struct mappedfile *mf)
                   1623: {
                   1624:        int fd;
                   1625:        struct stat st;
1.84    ! christos 1626:        size_t len;
1.58      christos 1627:
1.62      dsl      1628:        if (lstat(mf->path, &st) == -1)
                   1629:                return;
                   1630:
1.84    ! christos 1631:        len = (size_t)st.st_size;
1.62      dsl      1632:        if ((st.st_mode & S_IFMT) == S_IFLNK) {
1.84    ! christos 1633:                mf->buf = malloc(len + 1);
1.72      rumble   1634:                if (mf->buf == NULL)
                   1635:                        return;
1.84    ! christos 1636:                mf->buf[len] = 0;
        !          1637:                if (readlink(mf->path, mf->buf, len) != len)
1.62      dsl      1638:                        return;
1.84    ! christos 1639:                mf->len = (size_t)-1;
1.62      dsl      1640:                return;
1.58      christos 1641:        }
1.62      dsl      1642:
                   1643:        if ((fd = open(mf->path, O_RDONLY)) == -1)
                   1644:                return;
1.84    ! christos 1645:        mf->buf = mmap(0, len, PROT_READ, MAP_FILE|MAP_SHARED, fd, (off_t)0);
1.62      dsl      1646:        (void)close(fd);
                   1647:        if (mf->buf == MAP_FAILED)
                   1648:                return;
1.84    ! christos 1649:        mf->len = len;
1.58      christos 1650: }
                   1651:
                   1652: static void
                   1653: writefile(struct mappedfile *mf)
                   1654: {
                   1655:        int fd;
                   1656:
1.84    ! christos 1657:        if (mf->len == (size_t)-1) {
        !          1658:                (void)symlink(mf->buf, mf->path);
1.62      dsl      1659:                free(mf->buf);
                   1660:                return;
1.58      christos 1661:        }
1.62      dsl      1662:
                   1663:        if (mf->len == 0)
                   1664:                return;
                   1665:        fd = open(mf->path, O_WRONLY | O_CREAT | O_TRUNC, 0755);
                   1666:        if (fd == -1)
                   1667:                return;
                   1668:        (void)write(fd, mf->buf, mf->len);
                   1669:        (void)munmap(mf->buf, mf->len);
                   1670:        (void)close(fd);
1.58      christos 1671: }
                   1672:
1.45      abs      1673: static int
                   1674: mfs_dev(void)
1.28      christos 1675: {
                   1676:        /*
                   1677:         * We cannot print errors so we bail out silently...
                   1678:         */
                   1679:        pid_t pid;
1.30      drochner 1680:        int status;
1.45      abs      1681:        dev_t dev;
1.62      dsl      1682:        char *fs_size;
1.46      lukem    1683: #ifdef CPU_CONSDEV
                   1684:        static int name[2] = { CTL_MACHDEP, CPU_CONSDEV };
                   1685:        size_t olen;
                   1686: #endif
                   1687:
1.45      abs      1688:        /* If we have /dev/console, assume all is OK  */
1.28      christos 1689:        if (access(_PATH_CONSOLE, F_OK) != -1)
1.45      abs      1690:                return(0);
1.28      christos 1691:
                   1692:        /* Grab the contents of MAKEDEV */
1.58      christos 1693:        mapfile(&mfile[0]);
1.28      christos 1694:
1.45      abs      1695:        /* Grab the contents of MAKEDEV.local */
1.58      christos 1696:        mapfile(&mfile[1]);
1.28      christos 1697:
                   1698:        /* Mount an mfs over /dev so we can create devices */
                   1699:        switch ((pid = fork())) {
                   1700:        case 0:
1.84    ! christos 1701:                (void)asprintf(&fs_size, "%d", FSSIZE);
1.72      rumble   1702:                if (fs_size == NULL)
                   1703:                        return(-1);
1.62      dsl      1704:                (void)execl(INIT_MOUNT_MFS, "mount_mfs",
                   1705:                    "-b", "4096", "-f", "512",
                   1706:                    "-s", fs_size, "-n", STR(NINODE),
1.68      dan      1707:                    "-p", "0755",
1.62      dsl      1708:                    "swap", "/dev", NULL);
1.47      christos 1709:                _exit(1);
                   1710:                /*NOTREACHED*/
1.28      christos 1711:
                   1712:        case -1:
1.45      abs      1713:                return(-1);
1.28      christos 1714:
                   1715:        default:
                   1716:                if (waitpid(pid, &status, 0) == -1)
1.45      abs      1717:                        return(-1);
1.28      christos 1718:                if (status != 0)
1.45      abs      1719:                        return(-1);
1.28      christos 1720:                break;
                   1721:        }
                   1722:
                   1723: #ifdef CPU_CONSDEV
1.46      lukem    1724:        olen = sizeof(dev);
                   1725:        if (sysctl(name, sizeof(name) / sizeof(name[0]), &dev, &olen,
1.45      abs      1726:            NULL, 0) == -1)
1.46      lukem    1727: #endif
1.45      abs      1728:                dev = makedev(0, 0);
1.28      christos 1729:
1.45      abs      1730:        /* Make a console for us, so we can see things happening */
                   1731:        if (mknod(_PATH_CONSOLE, 0666 | S_IFCHR, dev) == -1)
1.47      christos 1732:                return(-1);
1.45      abs      1733:
1.47      christos 1734:        (void)freopen(_PATH_CONSOLE, "a", stderr);
1.45      abs      1735:
1.62      dsl      1736:        warnx("Creating mfs /dev (%d blocks, %d inodes)", FSSIZE, NINODE);
1.45      abs      1737:
                   1738:        /* Create a MAKEDEV script in the mfs /dev */
1.58      christos 1739:        writefile(&mfile[0]);
1.45      abs      1740:
                   1741:        /* Create a MAKEDEV.local script in the mfs /dev */
1.58      christos 1742:        writefile(&mfile[1]);
1.28      christos 1743:
                   1744:        /* Run the makedev script to create devices */
                   1745:        switch ((pid = fork())) {
                   1746:        case 0:
1.84    ! christos 1747:                (void)dup2(2, 1);       /* Give the script stdout */
1.60      dsl      1748:                if (chdir("/dev") == 0)
1.62      dsl      1749:                        (void)execl(INIT_BSHELL, "sh",
                   1750:                            mfile[0].len ? "./MAKEDEV" : "/etc/MAKEDEV",
                   1751:                            "init", NULL);
1.60      dsl      1752:                _exit(1);
1.73      salo     1753:                /* NOTREACHED */
1.28      christos 1754:
                   1755:        case -1:
1.60      dsl      1756:                break;
1.28      christos 1757:
                   1758:        default:
                   1759:                if (waitpid(pid, &status, 0) == -1)
1.60      dsl      1760:                        break;
1.47      christos 1761:                if (status != 0) {
                   1762:                        errno = EINVAL;
1.60      dsl      1763:                        break;
1.47      christos 1764:                }
1.60      dsl      1765:                return 0;
1.28      christos 1766:        }
1.47      christos 1767:        warn("Unable to run MAKEDEV");
1.60      dsl      1768:        return (-1);
1.28      christos 1769: }
                   1770: #endif
1.73      salo     1771:
                   1772: int
                   1773: do_setttyent(void)
                   1774: {
1.84    ! christos 1775:        (void)endttyent();
1.73      salo     1776: #ifdef CHROOT
                   1777:        if (did_multiuser_chroot) {
                   1778:                char path[PATH_MAX];
                   1779:
1.84    ! christos 1780:                (void)snprintf(path, sizeof(path), "%s/%s", rootdir, _PATH_TTYS);
1.73      salo     1781:
                   1782:                return setttyentpath(path);
                   1783:        } else
                   1784: #endif /* CHROOT */
                   1785:                return setttyent();
                   1786: }
                   1787:
                   1788: #if !defined(LETS_GET_SMALL) && defined(CHROOT)
                   1789:
                   1790: int
                   1791: createsysctlnode()
                   1792: {
                   1793:        struct sysctlnode node;
                   1794:        int mib[2];
                   1795:        size_t len;
                   1796:
                   1797:        /*
                   1798:         * Create top-level dynamic sysctl node.  Its child nodes will only
                   1799:         * be readable by the superuser, since regular mortals should not
1.76      elad     1800:         * care ("Sssh, it's a secret!").
1.73      salo     1801:         */
                   1802:        len = sizeof(struct sysctlnode);
                   1803:        mib[0] = CTL_CREATE;
                   1804:
1.84    ! christos 1805:        (void)memset(&node, 0, len);
1.73      salo     1806:        node.sysctl_flags = SYSCTL_VERSION | CTLFLAG_READWRITE |
1.74      elad     1807:            CTLFLAG_PRIVATE | CTLTYPE_NODE;
1.73      salo     1808:        node.sysctl_num = CTL_CREATE;
1.84    ! christos 1809:        (void)snprintf(node.sysctl_name, SYSCTL_NAMELEN, "init");
1.73      salo     1810:        if (sysctl(&mib[0], 1, &node, &len, &node, len) == -1) {
1.80      christos 1811:                warning("could not create init node: %m");
1.73      salo     1812:                return (-1);
                   1813:        }
                   1814:
                   1815:        /*
                   1816:         * Create second level dynamic node capable of holding pathname.
                   1817:         * Provide "/" as the default value.
                   1818:         */
                   1819:        len = sizeof(struct sysctlnode);
                   1820:        mib[0] = node.sysctl_num;
                   1821:        mib[1] = CTL_CREATE;
                   1822:
1.84    ! christos 1823:        (void)memset(&node, 0, len);
1.73      salo     1824:        node.sysctl_flags = SYSCTL_VERSION | CTLFLAG_READWRITE |
1.75      elad     1825:            CTLTYPE_STRING | CTLFLAG_OWNDATA;
1.73      salo     1826:        node.sysctl_size = _POSIX_PATH_MAX;
                   1827:        node.sysctl_data = __UNCONST("/");
                   1828:        node.sysctl_num = CTL_CREATE;
1.84    ! christos 1829:        (void)snprintf(node.sysctl_name, SYSCTL_NAMELEN, "root");
1.73      salo     1830:        if (sysctl(&mib[0], 2, NULL, NULL, &node, len) == -1) {
1.80      christos 1831:                warning("could not create init.root node: %m");
1.73      salo     1832:                return (-1);
                   1833:        }
                   1834:
                   1835:        return (0);
                   1836: }
                   1837:
                   1838: int
                   1839: shouldchroot()
                   1840: {
                   1841:        struct sysctlnode node;
                   1842:        size_t len, cnt;
                   1843:        int mib;
                   1844:
                   1845:        len = sizeof(struct sysctlnode);
                   1846:
                   1847:        if (sysctlbyname("init.root", rootdir, &len, NULL, 0) == -1) {
1.80      christos 1848:                warning("could not read init.root: %m");
1.73      salo     1849:
                   1850:                /* Child killed our node. Recreate it. */
                   1851:                if (errno == ENOENT) {
                   1852:                        /* Destroy whatever is left, recreate from scratch. */
                   1853:                        if (sysctlnametomib("init", &mib, &cnt) != -1) {
1.84    ! christos 1854:                                (void)memset(&node, 0, sizeof(node));
1.73      salo     1855:                                node.sysctl_flags = SYSCTL_VERSION;
                   1856:                                node.sysctl_num = mib;
                   1857:                                mib = CTL_DESTROY;
                   1858:
                   1859:                                (void)sysctl(&mib, 1, NULL, NULL, &node,
                   1860:                                    sizeof(node));
                   1861:                        }
                   1862:
1.84    ! christos 1863:                        (void)createsysctlnode();
1.73      salo     1864:                }
                   1865:
                   1866:                /* We certainly won't chroot. */
                   1867:                return (0);
                   1868:        }
                   1869:
                   1870:        if (rootdir[len] != '\0' || strlen(rootdir) != len - 1) {
                   1871:                warning("init.root is not a string");
                   1872:                return (0);
                   1873:        }
                   1874:
                   1875:        if (strcmp(rootdir, "/") == 0)
                   1876:                return (0);
                   1877:
                   1878:        return (1);
                   1879: }
                   1880:
                   1881: #endif /* !LETS_GET_SMALL && CHROOT */

CVSweb <webmaster@jp.NetBSD.org>