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

1.1       root        1: /*
                      2:  * Copyright (c) 1988, 1990 Regents of the University of California.
                      3:  * All rights reserved.
                      4:  *
                      5:  * Redistribution and use in source and binary forms are permitted provided
                      6:  * that: (1) source distributions retain this entire copyright notice and
                      7:  * comment, and (2) distributions including binaries display the following
                      8:  * acknowledgement:  ``This product includes software developed by the
                      9:  * University of California, Berkeley and its contributors'' in the
                     10:  * documentation or other materials provided with the distribution and in
                     11:  * all advertising materials mentioning features or use of this software.
                     12:  * Neither the name of the University nor the names of its contributors may
                     13:  * be used to endorse or promote products derived from this software without
                     14:  * specific prior written permission.
                     15:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
                     16:  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
                     17:  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
                     18:  */
                     19: 
                     20: #ifndef lint
                     21: char copyright[] =
                     22: "@(#) Copyright (c) 1988 Regents of the University of California.\n\
                     23:  All rights reserved.\n";
                     24: #endif /* not lint */
                     25: 
                     26: #ifndef lint
                     27: static char sccsid[] = "@(#)shutdown.c 5.15 (Berkeley) 6/22/90";
                     28: #endif /* not lint */
                     29: 
                     30: #include <sys/param.h>
                     31: #include <sys/time.h>
                     32: #include <sys/file.h>
                     33: #include <sys/resource.h>
                     34: #include <sys/syslog.h>
                     35: #include <sys/signal.h>
                     36: #include <setjmp.h>
                     37: #include <tzfile.h>
                     38: #include <pwd.h>
                     39: #include <stdio.h>
                     40: #include <ctype.h>
                     41: #include "pathnames.h"
                     42: 
                     43: #ifdef DEBUG
                     44: #undef _PATH_NOLOGIN
                     45: #define        _PATH_NOLOGIN   "./nologin"
                     46: #undef _PATH_FASTBOOT
                     47: #define        _PATH_FASTBOOT  "./fastboot"
                     48: #endif
                     49: 
                     50: #define        H               *60*60
                     51: #define        M               *60
                     52: #define        S               *1
                     53: #define        NOLOG_TIME      5*60
                     54: struct interval {
                     55:        int timeleft, timetowait;
                     56: } tlist[] = {
                     57:        10 H,  5 H,      5 H,  3 H,      2 H,  1 H,     1 H, 30 M,
                     58:        30 M, 10 M,     20 M, 10 M,     10 M,  5 M,     5 M,  3 M,
                     59:         2 M,  1 M,      1 M, 30 S,     30 S, 30 S,
                     60:         0, 0,
                     61: }, *tp = tlist;
                     62: #undef H
                     63: #undef M
                     64: #undef S
                     65: 
                     66: static time_t offset, shuttime;
                     67: static int dofast, dohalt, doreboot, killflg, mbuflen;
                     68: static char *nosync, *whom, mbuf[BUFSIZ];
                     69: 
                     70: main(argc, argv)
                     71:        int argc;
                     72:        char **argv;
                     73: {
                     74:        extern int optind;
                     75:        register char *p, *endp;
                     76:        int arglen, ch, len, readstdin;
                     77:        struct passwd *pw, *getpwuid();
                     78:        char *strcat(), *getlogin();
                     79:        uid_t geteuid();
                     80: 
                     81: #ifndef DEBUG
                     82:        if (geteuid()) {
                     83:                (void)fprintf(stderr, "shutdown: NOT super-user\n");
                     84:                exit(1);
                     85:        }
                     86: #endif
                     87:        nosync = NULL;
                     88:        readstdin = 0;
                     89:        while ((ch = getopt(argc, argv, "-fhknr")) != EOF)
                     90:                switch (ch) {
                     91:                case '-':
                     92:                        readstdin = 1;
                     93:                        break;
                     94:                case 'f':
                     95:                        dofast = 1;
                     96:                        break;
                     97:                case 'h':
                     98:                        dohalt = 1;
                     99:                        break;
                    100:                case 'k':
                    101:                        killflg = 1;
                    102:                        break;
                    103:                case 'n':
                    104:                        nosync = "-n";
                    105:                        break;
                    106:                case 'r':
                    107:                        doreboot = 1;
                    108:                        break;
                    109:                case '?':
                    110:                default:
                    111:                        usage();
                    112:                }
                    113:        argc -= optind;
                    114:        argv += optind;
                    115: 
                    116:        if (argc < 1)
                    117:                usage();
                    118: 
                    119:        if (dofast && nosync) {
                    120:                (void)fprintf(stderr,
                    121:                    "shutdown: incompatible switches -f and -n.\n");
                    122:                usage();
                    123:        }
                    124:        if (doreboot && dohalt) {
                    125:                (void)fprintf(stderr,
                    126:                    "shutdown: incompatible switches -h and -r.\n");
                    127:                usage();
                    128:        }
                    129:        getoffset(*argv++);
                    130: 
                    131:        if (*argv) {
                    132:                for (p = mbuf, len = sizeof(mbuf); *argv; ++argv) {
                    133:                        arglen = strlen(*argv);
                    134:                        if ((len -= arglen) <= 2)
                    135:                                break;
                    136:                        if (p != mbuf)
                    137:                                *p++ = ' ';
                    138:                        bcopy(*argv, p, arglen);
                    139:                        p += arglen;
                    140:                }
                    141:                *p = '\n';
                    142:                *++p = '\0';
                    143:        }
                    144: 
                    145:        if (readstdin) {
                    146:                p = mbuf;
                    147:                endp = mbuf + sizeof(mbuf) - 2;
                    148:                for (;;) {
                    149:                        if (!fgets(p, endp - p + 1, stdin))
                    150:                                break;
                    151:                        for (; *p &&  p < endp; ++p);
                    152:                        if (p == endp) {
                    153:                                *p = '\n';
                    154:                                *++p = '\0';
                    155:                                break;
                    156:                        }
                    157:                }
                    158:        }
                    159:        mbuflen = strlen(mbuf);
                    160: 
                    161:        if (offset)
                    162:                (void)printf("Shutdown at %.24s.\n", ctime(&shuttime));
                    163:        else
                    164:                (void)printf("Shutdown NOW!\n");
                    165: 
                    166:        if (!(whom = getlogin()))
                    167:                whom = (pw = getpwuid(getuid())) ? pw->pw_name : "???";
                    168: 
                    169: #ifdef DEBUG
                    170:        (void)putc('\n', stdout);
                    171: #else
                    172:        (void)setpriority(PRIO_PROCESS, 0, PRIO_MIN);
                    173:        {
                    174:                int forkpid;
                    175: 
                    176:                forkpid = fork();
                    177:                if (forkpid == -1) {
                    178:                        perror("shutdown: fork");
                    179:                        exit(1);
                    180:                }
                    181:                if (forkpid) {
                    182:                        (void)printf("shutdown: [pid %d]\n", forkpid);
                    183:                        exit(0);
                    184:                }
                    185:        }
                    186: #endif
                    187:        openlog("shutdown", LOG_CONS, LOG_AUTH);
                    188:        loop();
                    189:        /*NOTREACHED*/
                    190: }
                    191: 
                    192: loop()
                    193: {
                    194:        u_int sltime;
                    195:        int logged;
                    196: 
                    197:        if (offset <= NOLOG_TIME) {
                    198:                logged = 1;
                    199:                nolog();
                    200:        }
                    201:        else
                    202:                logged = 0;
                    203:        tp = tlist;
                    204:        if (tp->timeleft < offset)
                    205:                (void)sleep((u_int)(offset - tp->timeleft));
                    206:        else {
                    207:                while (offset < tp->timeleft)
                    208:                        ++tp;
                    209:                /*
                    210:                 * warn now, if going to sleep more than a fifth of
                    211:                 * the next wait time.
                    212:                 */
                    213:                if (sltime = offset - tp->timeleft) {
                    214:                        if (sltime > tp->timetowait / 5)
                    215:                                warn();
                    216:                        (void)sleep(sltime);
                    217:                }
                    218:        }
                    219:        for (;; ++tp) {
                    220:                warn();
                    221:                if (!logged && tp->timeleft <= NOLOG_TIME) {
                    222:                        logged = 1;
                    223:                        nolog();
                    224:                }
                    225:                (void)sleep((u_int)tp->timetowait);
                    226:                if (!tp->timeleft)
                    227:                        break;
                    228:        }
                    229:        die_you_gravy_sucking_pig_dog();
                    230: }
                    231: 
                    232: static jmp_buf alarmbuf;
                    233: 
                    234: warn()
                    235: {
                    236:        static int first;
                    237:        static char hostname[MAXHOSTNAMELEN + 1];
                    238:        char wcmd[MAXPATHLEN + 4];
                    239:        FILE *pf;
                    240:        char *ctime();
                    241:        void timeout();
                    242: 
                    243:        if (!first++)
                    244:                (void)gethostname(hostname, sizeof(hostname));
                    245: 
                    246:        /* undoc -n option to wall suppresses normal wall banner */
                    247:        (void)sprintf(wcmd, "%s -n", _PATH_WALL);
                    248:        if (!(pf = popen(wcmd, "w"))) {
                    249:                syslog(LOG_ERR, "shutdown: can't find %s: %m", _PATH_WALL);
                    250:                return;
                    251:        }
                    252: 
                    253:        (void)fprintf(pf,
                    254:            "\007*** %sSystem shutdown message from %s@%s ***\007\n",
                    255:            tp->timeleft ? "": "FINAL ", whom, hostname);
                    256: 
                    257:        if (tp->timeleft > 10*60)
                    258:                (void)fprintf(pf, "System going down at %5.5s\n\n",
                    259:                    ctime(&shuttime) + 11);
                    260:        else if (tp->timeleft > 59)
                    261:                (void)fprintf(pf, "System going down in %d minute%s\n\n",
                    262:                    tp->timeleft / 60, (tp->timeleft > 60) ? "s" : "");
                    263:        else if (tp->timeleft)
                    264:                (void)fprintf(pf, "System going down in 30 seconds\n\n");
                    265:        else
                    266:                (void)fprintf(pf, "System going down IMMEDIATELY\n\n");
                    267: 
                    268:        if (mbuflen)
                    269:                (void)fwrite(mbuf, sizeof(*mbuf), mbuflen, pf);
                    270: 
                    271:        /*
                    272:         * play some games, just in case wall doesn't come back
                    273:         * probably unecessary, given that wall is careful.
                    274:         */
                    275:        if (!setjmp(alarmbuf)) {
                    276:                (void)signal(SIGALRM, timeout);
                    277:                (void)alarm((u_int)30);
                    278:                (void)pclose(pf);
                    279:                (void)alarm((u_int)0);
                    280:                (void)signal(SIGALRM, SIG_DFL);
                    281:        }
                    282: }
                    283: 
                    284: void
                    285: timeout()
                    286: {
                    287:        longjmp(alarmbuf, 1);
                    288: }
                    289: 
                    290: die_you_gravy_sucking_pig_dog()
                    291: {
                    292:        void finish();
                    293: 
                    294:        syslog(LOG_NOTICE, "%s by %s: %s",
                    295:            doreboot ? "reboot" : dohalt ? "halt" : "shutdown", whom, mbuf);
                    296:        (void)sleep(2);
                    297: 
                    298:        (void)printf("\r\nSystem shutdown time has arrived\007\007\r\n");
                    299:        if (killflg) {
                    300:                (void)printf("\rbut you'll have to do it yourself\r\n");
                    301:                finish();
                    302:        }
                    303:        if (dofast)
                    304:                doitfast();
                    305: #ifdef DEBUG
                    306:        if (doreboot)
                    307:                (void)printf("reboot");
                    308:        else if (dohalt)
                    309:                (void)printf("halt");
                    310:        if (nosync)
                    311:                (void)printf(" no sync");
                    312:        if (dofast)
                    313:                (void)printf(" no fsck");
                    314:        (void)printf("\nkill -HUP 1\n");
                    315: #else
                    316:        if (doreboot) {
                    317:                execle(_PATH_REBOOT, "reboot", "-l", nosync, 0);
                    318:                syslog(LOG_ERR, "shutdown: can't exec %s: %m.", _PATH_REBOOT);
                    319:                perror("shutdown");
                    320:        }
                    321:        else if (dohalt) {
                    322:                execle(_PATH_HALT, "halt", "-l", nosync, 0);
                    323:                syslog(LOG_ERR, "shutdown: can't exec %s: %m.", _PATH_HALT);
                    324:                perror("shutdown");
                    325:        }
                    326:        (void)kill(1, SIGTERM);         /* to single user */
                    327: #endif
                    328:        finish();
                    329: }
                    330: 
                    331: #define        ATOI2(p)        (p[0] - '0') * 10 + (p[1] - '0'); p += 2;
                    332: 
                    333: getoffset(timearg)
                    334:        register char *timearg;
                    335: {
                    336:        register struct tm *lt;
                    337:        register char *p;
                    338:        time_t now, time();
                    339: 
                    340:        if (!strcasecmp(timearg, "now")) {              /* now */
                    341:                offset = 0;
                    342:                return;
                    343:        }
                    344: 
                    345:        (void)time(&now);
                    346:        if (*timearg == '+') {                          /* +minutes */
                    347:                if (!isdigit(*++timearg))
                    348:                        badtime();
                    349:                offset = atoi(timearg) * 60;
                    350:                shuttime = now + offset;
                    351:                return;
                    352:        }
                    353: 
                    354:        /* handle hh:mm by getting rid of the colon */
                    355:        for (p = timearg; *p; ++p)
                    356:                if (!isascii(*p) || !isdigit(*p))
                    357:                        if (*p == ':' && strlen(p) == 3) {
                    358:                                p[0] = p[1];
                    359:                                p[1] = p[2];
                    360:                                p[2] = '\0';
                    361:                        }
                    362:                        else
                    363:                                badtime();
                    364: 
                    365:        unsetenv("TZ");                                 /* OUR timezone */
                    366:        lt = localtime(&now);                           /* current time val */
                    367: 
                    368:        switch(strlen(timearg)) {
                    369:        case 10:
                    370:                lt->tm_year = ATOI2(timearg);
                    371:                /* FALLTHROUGH */
                    372:        case 8:
                    373:                lt->tm_mon = ATOI2(timearg);
                    374:                if (--lt->tm_mon < 0 || lt->tm_mon > 11)
                    375:                        badtime();
                    376:                /* FALLTHROUGH */
                    377:        case 6:
                    378:                lt->tm_mday = ATOI2(timearg);
                    379:                if (lt->tm_mday < 1 || lt->tm_mday > 31)
                    380:                        badtime();
                    381:                /* FALLTHROUGH */
                    382:        case 4:
                    383:                lt->tm_hour = ATOI2(timearg);
                    384:                if (lt->tm_hour < 0 || lt->tm_hour > 23)
                    385:                        badtime();
                    386:                lt->tm_min = ATOI2(timearg);
                    387:                if (lt->tm_min < 0 || lt->tm_min > 59)
                    388:                        badtime();
                    389:                lt->tm_sec = 0;
                    390:                if ((shuttime = mktime(lt)) == -1)
                    391:                        badtime();
                    392:                if ((offset = shuttime - now) < 0) {
                    393:                        (void)fprintf(stderr,
                    394:                            "shutdown: that time is already past.\n");
                    395:                        exit(1);
                    396:                }
                    397:                break;
                    398:        default:
                    399:                badtime();
                    400:        }
                    401: }
                    402: 
                    403: #define        FSMSG   "fastboot file for fsck\n"
                    404: doitfast()
                    405: {
                    406:        int fastfd;
                    407: 
                    408:        if ((fastfd = open(_PATH_FASTBOOT, O_WRONLY|O_CREAT|O_TRUNC,
                    409:            0664)) >= 0) {
                    410:                (void)write(fastfd, FSMSG, sizeof(FSMSG) - 1);
                    411:                (void)close(fastfd);
                    412:        }
                    413: }
                    414: 
                    415: #define        NOMSG   "\n\nNO LOGINS: System going down at "
                    416: nolog()
                    417: {
                    418:        int logfd;
                    419:        char *ct, *ctime();
                    420:        void finish();
                    421: 
                    422:        (void)unlink(_PATH_NOLOGIN);    /* in case linked to another file */
                    423:        (void)signal(SIGINT, finish);
                    424:        (void)signal(SIGHUP, finish);
                    425:        (void)signal(SIGQUIT, finish);
                    426:        (void)signal(SIGTERM, finish);
                    427:        if ((logfd = open(_PATH_NOLOGIN, O_WRONLY|O_CREAT|O_TRUNC,
                    428:            0664)) >= 0) {
                    429:                (void)write(logfd, NOMSG, sizeof(NOMSG) - 1);
                    430:                ct = ctime(&shuttime);
                    431:                (void)write(logfd, ct + 11, 5);
                    432:                (void)write(logfd, "\n\n", 2);
                    433:                (void)write(logfd, mbuf, strlen(mbuf));
                    434:                (void)close(logfd);
                    435:        }
                    436: }
                    437: 
                    438: void
                    439: finish()
                    440: {
                    441:        (void)unlink(_PATH_NOLOGIN);
                    442:        exit(0);
                    443: }
                    444: 
                    445: badtime()
                    446: {
                    447:        (void)fprintf(stderr, "shutdown: bad time format.\n");
                    448:        exit(1);
                    449: }
                    450: 
                    451: usage()
                    452: {
                    453:        fprintf(stderr, "usage: shutdown [-fhknr] shutdowntime [ message ]\n");
                    454:        exit(1);
                    455: }

unix.superglobalmegacorp.com

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