Annotation of 43BSDReno/sbin/init/init.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1980,1986 Regents of the University of California.
                      3:  * All rights reserved.  The Berkeley software License Agreement
                      4:  * specifies the terms and conditions for redistribution.
                      5:  */
                      6: 
                      7: #ifndef lint
                      8: static char sccsid[] = "@(#)init.c     5.18 (Berkeley) 6/26/90";
                      9: #endif not lint
                     10: 
                     11: #include <sys/types.h>
                     12: #include <sys/file.h>
                     13: #include <sys/signal.h>
                     14: #include <sys/reboot.h>
                     15: #include <sys/syslog.h>
                     16: #include <sys/stat.h>
                     17: #include <sys/ioctl.h>
                     18: #include <setjmp.h>
                     19: #include <utmp.h>
                     20: #include <errno.h>
                     21: #include <ttyent.h>
                     22: #include "pathnames.h"
                     23: 
                     24: #define        CMDSIZ  200     /* max string length for getty or window command*/
                     25: #define        ALL     p = itab; p ; p = p->next
                     26: #define        EVER    ;;
                     27: #define SCPYN(a, b)    strncpy(a, b, sizeof(a))
                     28: #define SCMPN(a, b)    strncmp(a, b, sizeof(a))
                     29: 
                     30: char   shell[] = _PATH_BSHELL;
                     31: char   minus[] = "-";
                     32: char   runc[]  = _PATH_RC;
                     33: char   ctty[]  = _PATH_CONSOLE;
                     34: 
                     35: struct tab
                     36: {
                     37:        char    line[UT_LINESIZE];
                     38:        char    comn[CMDSIZ];
                     39:        char    xflag;
                     40:        int     pid;
                     41:        int     wpid;           /* window system pid for SIGHUP */
                     42:        char    wcmd[CMDSIZ];   /* command to start window system process */
                     43:        time_t  gettytime;
                     44:        int     gettycnt;
                     45:        time_t  windtime;
                     46:        int     windcnt;
                     47:        struct  tab *next;
                     48: } *itab;
                     49: 
                     50: int    fi;
                     51: int    mergflag;
                     52: char   tty[20];
                     53: jmp_buf        sjbuf, shutpass;
                     54: 
                     55: char   *strcpy(), *strcat();
                     56: long   lseek();
                     57: void   idle(), merge(), reset();
                     58: 
                     59: struct sigvec rvec = { reset, sigmask(SIGHUP), 0 };
                     60: 
                     61: main(argc, argv)
                     62:        char **argv;
                     63: {
                     64: #if defined(tahoe)
                     65:        register int r12;               /* make sure r11 gets bootflags */
                     66: #endif
                     67: #if defined(vax) || defined(tahoe) || defined(hp300)
                     68:        register int r11;               /* passed thru from boot */
                     69: #endif
                     70: #ifdef __GNUC__
                     71:        /* insure proper semantics for setjmp/longjmp */
                     72:        static
                     73: #endif
                     74:        int howto, oldhowto, started = 0;
                     75: 
                     76: #if defined(vax) || defined(tahoe) || defined(hp300)
                     77:        /* howto passed in high-order register XXX */
                     78: #ifdef __GNUC__
                     79: #ifdef hp300
                     80:        asm("movl d7,%0" : "=rm" (howto));
                     81: #else
                     82:        asm("movl r11,%0" : "=rm" (howto));
                     83: #endif
                     84: #else
                     85:        howto = r11;
                     86: #endif /* __GNUC__ */
                     87: #else  /* defined(vax) || defined(tahoe) || defined(hp300) */
                     88:        /* howto passed as argument */
                     89:        if (argc > 1 && argv[1][0] == '-') {
                     90:                char *cp;
                     91: 
                     92:                howto = 0;
                     93:                cp = &argv[1][1];
                     94:                while (*cp) switch (*cp++) {
                     95:                case 'a':
                     96:                        howto |= RB_ASKNAME;
                     97:                        break;
                     98:                case 's':
                     99:                        howto |= RB_SINGLE;
                    100:                        break;
                    101:                }
                    102:        } else
                    103:                howto = RB_SINGLE;
                    104: #endif
                    105:        if (getuid() != 0)
                    106:                exit(1);
                    107:        openlog("init", LOG_CONS|LOG_ODELAY, LOG_AUTH);
                    108:        if (setsid() < 0)
                    109:                syslog(LOG_ERR, "setsid failed (initial) %m");
                    110:        sigvec(SIGTERM, &rvec, (struct sigvec *)0);
                    111:        signal(SIGTSTP, idle);
                    112:        signal(SIGTTIN, SIG_IGN);
                    113:        signal(SIGTTOU, SIG_IGN);
                    114:        (void) setjmp(sjbuf);
                    115:        for (; ; ) {
                    116:                oldhowto = howto;
                    117:                howto = RB_SINGLE;
                    118:                if (started && setjmp(shutpass) == 0)
                    119:                        shutdown();
                    120:                started = 1;
                    121:                if (oldhowto & RB_SINGLE)
                    122:                        single();
                    123:                if (runcom(oldhowto) == 0) 
                    124:                        continue;
                    125:                merge();
                    126:                multiple();
                    127:        }
                    128: }
                    129: 
                    130: void   shutreset();
                    131: 
                    132: shutdown()
                    133: {
                    134:        register i;
                    135:        register struct tab *p, *p1;
                    136: 
                    137:        signal(SIGHUP, SIG_IGN);
                    138:        for (p = itab; p ; ) {
                    139:                term(p);
                    140:                p1 = p->next;
                    141:                free(p);
                    142:                p = p1;
                    143:        }
                    144:        itab = (struct tab *)0;
                    145:        signal(SIGALRM, shutreset);
                    146:        (void) kill(-1, SIGTERM);       /* one chance to catch it */
                    147:        sleep(5);
                    148:        alarm(30);
                    149:        for (i = 0; i < 5; i++)
                    150:                kill(-1, SIGKILL);
                    151:        while (wait((int *)0) != -1)
                    152:                ;
                    153:        alarm(0);
                    154:        shutend();
                    155: }
                    156: 
                    157: char shutfailm[] = "init: WARNING: something is hung (won't die); ps axl advised\n";
                    158: 
                    159: void
                    160: shutreset()
                    161: {
                    162:        int status;
                    163: 
                    164:        if (fork() == 0) {
                    165:                int ct = open(ctty, 1);
                    166:                write(ct, shutfailm, sizeof (shutfailm));
                    167:                sleep(5);
                    168:                exit(1);
                    169:        }
                    170:        sleep(5);
                    171:        shutend();
                    172:        longjmp(shutpass, 1);
                    173: }
                    174: 
                    175: shutend()
                    176: {
                    177:        register i;
                    178: 
                    179:        acct(0);
                    180:        signal(SIGALRM, SIG_DFL);
                    181:        for (i = 0; i < 10; i++)
                    182:                close(i);
                    183:        logwtmp("~", "shutdown", "");
                    184: }
                    185: 
                    186: single()
                    187: {
                    188:        register pid;
                    189:        register xpid;
                    190:        int fd;
                    191:        extern int errno;
                    192: 
                    193:        do {
                    194:                pid = fork();
                    195:                if (pid == 0) {
                    196:                        signal(SIGTERM, SIG_DFL);
                    197:                        signal(SIGHUP, SIG_DFL);
                    198:                        signal(SIGALRM, SIG_DFL);
                    199:                        signal(SIGTSTP, SIG_IGN);
                    200:                        if (setsid() < 0)
                    201:                                syslog(LOG_ERR, "setsid failed (single): %m");
                    202:                        (void) revoke(ctty);
                    203:                        if ((fd = open(ctty, O_RDWR)) < 0) {
                    204:                                syslog(LOG_ERR, "open %s: %m", ctty);
                    205:                                exit(1);
                    206:                        }
                    207:                        if (ioctl(fd, TIOCSCTTY, 0) < 0)
                    208:                                syslog(LOG_ERR, "TIOCSCTTY failed: %m");
                    209:                        dup2(fd, 0);
                    210:                        dup2(fd, 1);
                    211:                        dup2(fd, 2);
                    212:                        if (fd > 2)
                    213:                                close(fd);
                    214:                        execl(shell, minus, (char *)0);
                    215:                        perror(shell);
                    216:                        exit(0);
                    217:                }
                    218:                while ((xpid = wait((int *)0)) != pid)
                    219:                        if (xpid == -1 && errno == ECHILD)
                    220:                                break;
                    221:        } while (xpid == -1);
                    222: }
                    223: 
                    224: runcom(oldhowto)
                    225:        int oldhowto;
                    226: {
                    227:        register pid;
                    228:        int fd, status;
                    229: 
                    230:        pid = fork();
                    231:        if (pid == 0) {
                    232:                signal(SIGTSTP, SIG_IGN);
                    233:                signal(SIGHUP, SIG_IGN);
                    234:                if ((fd = open(ctty, O_RDWR)) < 0)
                    235:                        syslog(LOG_ERR, "open %s: %m", ctty);
                    236:                else {
                    237:                        dup2(fd, 0);
                    238:                        dup2(fd, 1);
                    239:                        dup2(fd, 2);
                    240:                        if (fd > 2)
                    241:                                close(fd);
                    242:                }
                    243:                if (setsid() < 0)
                    244:                        syslog(LOG_ERR, "setsid failed (runcom) %m");
                    245:                if (ioctl(0, TIOCSCTTY, 0) < 0) 
                    246:                        syslog(LOG_ERR, "TIOCSCTTY failed (runcom) %m");
                    247:                if (oldhowto & RB_SINGLE)
                    248:                        execl(shell, shell, runc, (char *)0);
                    249:                else
                    250:                        execl(shell, shell, runc, "autoboot", (char *)0);
                    251:                exit(1);
                    252:        }
                    253:        while (wait(&status) != pid)
                    254:                ;
                    255:        if (status)
                    256:                return (0);
                    257:        logwtmp("~", "reboot", "");
                    258:        return (1);
                    259: }
                    260: 
                    261: struct sigvec  mvec = { merge, sigmask(SIGTERM), 0 };
                    262: /*
                    263:  * Multi-user.  Listen for users leaving, SIGHUP's
                    264:  * which indicate ttys has changed, and SIGTERM's which
                    265:  * are used to shutdown the system.
                    266:  */
                    267: multiple()
                    268: {
                    269:        extern int errno;
                    270:        register struct tab *p;
                    271:        register pid;
                    272:        int omask;
                    273: 
                    274:        sigvec(SIGHUP, &mvec, (struct sigvec *)0);
                    275:        for (EVER) {
                    276:                pid = wait((int *)0);
                    277: /* SHOULD FIX THIS IN THE KERNEL */
                    278:                if (pid == -1 && errno != EINTR)
                    279:                        return;
                    280:                omask = sigblock(sigmask(SIGHUP));
                    281:                for (ALL) {
                    282:                        /* must restart window system BEFORE emulator */
                    283:                        if (p->wpid == pid || p->wpid == -1)
                    284:                                wstart(p);
                    285:                        if (p->pid == pid || p->pid == -1) {
                    286:                                /* disown the window system */
                    287:                                if (p->wpid)
                    288:                                        kill(p->wpid, SIGHUP);
                    289:                                cleanutmp(p);
                    290:                                dfork(p);
                    291:                        }
                    292:                }
                    293:                sigsetmask(omask);
                    294:        }
                    295: }
                    296: 
                    297: /*
                    298:  * Merge current contents of ttys file
                    299:  * into in-core table of configured tty lines.
                    300:  * Entered as signal handler for SIGHUP.
                    301:  */
                    302: #define        FOUND   1
                    303: #define        CHANGE  2
                    304: #define WCHANGE 4
                    305: 
                    306: void
                    307: merge()
                    308: {
                    309:        register struct tab *p;
                    310:        register struct ttyent *t;
                    311:        register struct tab *p1;
                    312: 
                    313:        for (ALL)
                    314:                p->xflag = 0;
                    315:        setttyent();
                    316:        while (t = getttyent()) {
                    317:                if ((t->ty_status & TTY_ON) == 0)
                    318:                        continue;
                    319:                for (ALL) {
                    320:                        if (SCMPN(p->line, t->ty_name))
                    321:                                continue;
                    322:                        p->xflag |= FOUND;
                    323:                        if (SCMPN(p->comn, t->ty_getty)) {
                    324:                                p->xflag |= CHANGE;
                    325:                                SCPYN(p->comn, t->ty_getty);
                    326:                        }
                    327:                        if (SCMPN(p->wcmd, t->ty_window ? t->ty_window : "")) {
                    328:                                p->xflag |= WCHANGE|CHANGE;
                    329:                                SCPYN(p->wcmd, t->ty_window);
                    330:                        }
                    331:                        goto contin1;
                    332:                }
                    333: 
                    334:                /*
                    335:                 * Make space for a new one
                    336:                 */
                    337:                p1 = (struct tab *)calloc(1, sizeof(*p1));
                    338:                if (!p1) {
                    339:                        syslog(LOG_ERR, "no space for '%s' !?!", t->ty_name);
                    340:                        goto contin1;
                    341:                }
                    342:                /*
                    343:                 * Put new terminal at the end of the linked list.
                    344:                 */
                    345:                if (itab) {
                    346:                        for (p = itab; p->next ; p = p->next)
                    347:                                ;
                    348:                        p->next = p1;
                    349:                } else
                    350:                        itab = p1;
                    351: 
                    352:                p = p1;
                    353:                SCPYN(p->line, t->ty_name);
                    354:                p->xflag |= FOUND|CHANGE;
                    355:                SCPYN(p->comn, t->ty_getty);
                    356:                if (t->ty_window && strcmp(t->ty_window, "") != 0) {
                    357:                        p->xflag |= WCHANGE;
                    358:                        SCPYN(p->wcmd, t->ty_window);
                    359:                }
                    360:        contin1:
                    361:                ;
                    362:        }
                    363:        endttyent();
                    364:        p1 = (struct tab *)0;
                    365:        for (ALL) {
                    366:                if ((p->xflag&FOUND) == 0) {
                    367:                        term(p);
                    368:                        wterm(p);
                    369:                        if (p1)
                    370:                                p1->next = p->next;
                    371:                        else
                    372:                                itab = p->next;
                    373:                        free(p);
                    374:                        p = p1 ? p1 : itab;
                    375:                } else {
                    376:                        /* window system should be started first */
                    377:                        if (p->xflag&WCHANGE) {
                    378:                                wterm(p);
                    379:                                wstart(p);
                    380:                        }
                    381:                        if (p->xflag&CHANGE) {
                    382:                                term(p);
                    383:                                dfork(p);
                    384:                        }
                    385:                }
                    386:                p1 = p;
                    387:        }
                    388: }
                    389: 
                    390: term(p)
                    391:        register struct tab *p;
                    392: {
                    393: 
                    394:        if (p->pid != 0) {
                    395:                cleanutmp(p);
                    396:                kill(p->pid, SIGKILL);
                    397:        }
                    398:        p->pid = 0;
                    399:        /* send SIGHUP to get rid of connections */
                    400:        if (p->wpid > 0)
                    401:                kill(p->wpid, SIGHUP);
                    402: }
                    403: 
                    404: dfork(p)
                    405:        struct tab *p;
                    406: {
                    407:        register pid;
                    408:        time_t t;
                    409:        int dowait = 0;
                    410: 
                    411:        time(&t);
                    412:        p->gettycnt++;
                    413:        if ((t - p->gettytime) >= 60) {
                    414:                p->gettytime = t;
                    415:                p->gettycnt = 1;
                    416:        } else if (p->gettycnt >= 5) {
                    417:                dowait = 1;
                    418:                p->gettytime = t;
                    419:                p->gettycnt = 1;
                    420:        }
                    421:        pid = fork();
                    422:        if (pid == 0) {
                    423:                signal(SIGTERM, SIG_DFL);
                    424:                signal(SIGHUP, SIG_IGN);
                    425:                sigsetmask(0);  /* since can be called from masked code */
                    426:                if (dowait) {
                    427:                        syslog(LOG_ERR, "'%s %s' failing, sleeping", p->comn, p->line);
                    428:                        closelog();
                    429:                        sleep(30);
                    430:                }
                    431:                if (setsid() < 0)
                    432:                        syslog(LOG_ERR, "setsid failed(dfork) %m");
                    433:                execit(p->comn, p->line);
                    434:                exit(0);
                    435:        }
                    436:        p->pid = pid;
                    437: }
                    438: 
                    439: cleanutmp(p)
                    440:        register struct tab *p;
                    441: {
                    442:        if (logout(p->line)) {
                    443:                logwtmp(p->line, "", "");
                    444:                /*
                    445:                 * After a proper login force reset
                    446:                 * of error detection code in dfork.
                    447:                 */
                    448:                p->gettytime = 0;
                    449:                p->windtime = 0;
                    450:        }
                    451: }
                    452: 
                    453: void
                    454: reset()
                    455: {
                    456:        longjmp(sjbuf, 1);
                    457: }
                    458: 
                    459: jmp_buf        idlebuf;
                    460: 
                    461: void
                    462: idlehup()
                    463: {
                    464:        longjmp(idlebuf, 1);
                    465: }
                    466: 
                    467: void
                    468: idle()
                    469: {
                    470:        register struct tab *p;
                    471:        register pid;
                    472: 
                    473:        signal(SIGHUP, idlehup);
                    474:        for (EVER) {
                    475:                if (setjmp(idlebuf))
                    476:                        return;
                    477:                pid = wait((int *) 0);
                    478:                if (pid == -1) {
                    479:                        sigpause(0);
                    480:                        continue;
                    481:                }
                    482:                for (ALL) {
                    483:                        /* if window system dies, mark it for restart */
                    484:                        if (p->wpid == pid)
                    485:                                p->wpid = -1;
                    486:                        if (p->pid == pid) {
                    487:                                cleanutmp(p);
                    488:                                p->pid = -1;
                    489:                        }
                    490:                }
                    491:        }
                    492: }
                    493: 
                    494: wterm(p)
                    495:        register struct tab *p;
                    496: {
                    497:        if (p->wpid != 0) {
                    498:                kill(p->wpid, SIGKILL);
                    499:        }
                    500:        p->wpid = 0;
                    501: }
                    502: 
                    503: wstart(p)
                    504:        register struct tab *p;
                    505: {
                    506:        register pid;
                    507:        time_t t;
                    508:        int dowait = 0;
                    509: 
                    510:        time(&t);
                    511:        p->windcnt++;
                    512:        if ((t - p->windtime) >= 60) {
                    513:                p->windtime = t;
                    514:                p->windcnt = 1;
                    515:        } else if (p->windcnt >= 5) {
                    516:                dowait = 1;
                    517:                p->windtime = t;
                    518:                p->windcnt = 1;
                    519:        }
                    520: 
                    521:        pid = fork();
                    522: 
                    523:        if (pid == 0) {
                    524:                signal(SIGTERM, SIG_DFL);
                    525:                signal(SIGHUP,  SIG_IGN);
                    526:                sigsetmask(0);  /* since can be called from masked code */
                    527:                if (dowait) {
                    528:                        syslog(LOG_ERR, "'%s %s' failing, sleeping", p->wcmd, p->line);
                    529:                        closelog();
                    530:                        sleep(30);
                    531:                }
                    532:                if (setsid() < 0)
                    533:                        syslog(LOG_ERR, "setsid failed (window) %m");
                    534:                execit(p->wcmd, p->line);
                    535:                exit(0);
                    536:        }
                    537:        p->wpid = pid;
                    538: }
                    539: 
                    540: #define NARGS  20      /* must be at least 4 */
                    541: #define ARGLEN 512     /* total size for all the argument strings */
                    542: 
                    543: execit(s, arg)
                    544:        char *s;
                    545:        char *arg;      /* last argument on line */
                    546: {
                    547:        char *argv[NARGS], args[ARGLEN], *envp[1];
                    548:        register char *sp = s;
                    549:        register char *ap = args;
                    550:        register char c;
                    551:        register int i;
                    552: 
                    553:        /*
                    554:         * First we have to set up the argument vector.
                    555:         * "prog arg1 arg2" maps to exec("prog", "-", "arg1", "arg2"). 
                    556:         */
                    557:        for (i = 1; i < NARGS - 2; i++) {
                    558:                argv[i] = ap;
                    559:                for (EVER) {
                    560:                        if ((c = *sp++) == '\0' || ap >= &args[ARGLEN-1]) {
                    561:                                *ap = '\0';
                    562:                                goto done;
                    563:                        }
                    564:                        if (c == ' ') {
                    565:                                *ap++ = '\0';
                    566:                                while (*sp == ' ')
                    567:                                        sp++;
                    568:                                if (*sp == '\0')
                    569:                                        goto done;
                    570:                                break;
                    571:                        }
                    572:                        *ap++ = c;
                    573:                }
                    574:        }
                    575: done:
                    576:        argv[0] = argv[1];
                    577:        argv[1] = "-";
                    578:        argv[i+1] = arg;
                    579:        argv[i+2] = 0;
                    580:        envp[0] = 0;
                    581:        execve(argv[0], &argv[1], envp);
                    582:        /* report failure of exec */
                    583:        syslog(LOG_ERR, "%s: %m", argv[0]);
                    584:        closelog();
                    585:        sleep(10);      /* prevent failures from eating machine */
                    586: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.