|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.