1: /* 2: * Copyright (c) 1983,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: #if defined(DOSCCS) && !defined(lint) 8: char copyright[] = 9: "@(#) Copyright (c) 1983,1986 Regents of the University of California.\n\ 10: All rights reserved.\n"; 11: 12: static char sccsid[] = "@(#)shutdown.c 5.6.3 (2.11BSD GTE) 1997/10/3"; 13: #endif 14: 15: #include <stdio.h> 16: #include <ctype.h> 17: #include <signal.h> 18: #include <setjmp.h> 19: #include <utmp.h> 20: #include <pwd.h> 21: #include <paths.h> 22: #include <string.h> 23: #include <stdlib.h> 24: #include <unistd.h> 25: #include <sys/time.h> 26: #include <sys/resource.h> 27: #include <sys/param.h> 28: #include <sys/syslog.h> 29: 30: /* 31: * shutdown when [messages] 32: * 33: * allow super users to tell users and remind users 34: * of imminent shutdown of unix 35: * and shut it down automatically 36: * and even reboot or halt the machine if they desire 37: */ 38: 39: #define REBOOT "/sbin/reboot" 40: #define HALT "/sbin/halt" 41: #define MAXINTS 20 42: #define HOURS *3600 43: #define MINUTES *60 44: #define SECONDS 45: #define NLOG 600 /* no of bytes possible for message */ 46: #define NOLOGTIME 5 MINUTES 47: #define IGNOREUSER "sleeper" 48: 49: char hostname[MAXHOSTNAMELEN]; 50: 51: int timeout(); 52: time_t getsdt(); 53: 54: struct utmp utmp; 55: int sint; 56: long stogo; 57: char tpath[] = "/dev/"; 58: int nlflag = 1; /* nolog yet to be done */ 59: int killflg = 1; 60: int doreboot = 0; 61: int halt = 0; 62: int fast = 0; 63: char *nosync = NULL; 64: char nosyncflag[] = "-n"; 65: char term[sizeof tpath + sizeof utmp.ut_line]; 66: char tbuf[BUFSIZ]; 67: char nolog1[] = "\n\nNO LOGINS: System going down at %5.5s\n\n"; 68: char nolog2[NLOG+1]; 69: #ifdef DEBUG 70: char nologin[] = "nologin"; 71: char fastboot[] = "fastboot"; 72: #else 73: char nologin[] = _PATH_NOLOGIN; 74: char fastboot[] = "/fastboot"; 75: #endif 76: time_t nowtime; 77: jmp_buf alarmbuf; 78: 79: struct interval { 80: int stogo; 81: int sint; 82: } interval[] = { 83: 4 HOURS, 1 HOURS, 84: 2 HOURS, 30 MINUTES, 85: 1 HOURS, 15 MINUTES, 86: 30 MINUTES, 10 MINUTES, 87: 15 MINUTES, 5 MINUTES, 88: 10 MINUTES, 5 MINUTES, 89: 5 MINUTES, 3 MINUTES, 90: 2 MINUTES, 1 MINUTES, 91: 1 MINUTES, 30 SECONDS, 92: 0 SECONDS, 0 SECONDS 93: }; 94: 95: char *shutter; 96: 97: main(argc,argv) 98: int argc; 99: char **argv; 100: { 101: register i, ufd; 102: register char *f; 103: char *ts; 104: time_t sdt; 105: int h, m; 106: int first; 107: FILE *termf; 108: struct passwd *pw; 109: 110: shutter = getlogin(); 111: if (shutter == 0 && (pw = getpwuid(getuid()))) 112: shutter = pw->pw_name; 113: if (shutter == 0) 114: shutter = "???"; 115: (void) gethostname(hostname, sizeof (hostname)); 116: openlog("shutdown", 0, LOG_AUTH); 117: argc--, argv++; 118: while (argc > 0 && (f = argv[0], *f++ == '-')) { 119: while (i = *f++) switch (i) { 120: case 'k': 121: killflg = 0; 122: continue; 123: case 'n': 124: nosync = nosyncflag; 125: continue; 126: case 'f': 127: fast = 1; 128: continue; 129: case 'r': 130: doreboot = 1; 131: continue; 132: case 'h': 133: halt = 1; 134: continue; 135: default: 136: fprintf(stderr, "shutdown: '%c' - unknown flag\n", i); 137: exit(1); 138: } 139: argc--, argv++; 140: } 141: if (argc < 1) { 142: /* argv[0] is not available after the argument handling. */ 143: printf("Usage: shutdown [ -krhfn ] shutdowntime [ message ]\n"); 144: finish(); 145: } 146: if (fast && (nosync == nosyncflag)) { 147: printf ("shutdown: Incompatible switches 'fast' & 'nosync'\n"); 148: finish(); 149: } 150: if (geteuid()) { 151: fprintf(stderr, "NOT super-user\n"); 152: finish(); 153: } 154: nowtime = time((long *)0); 155: sdt = getsdt(argv[0]); 156: argc--, argv++; 157: nolog2[0] = '\0'; 158: while (argc-- > 0) { 159: (void) strcat(nolog2, " "); 160: (void) strcat(nolog2, *argv++); 161: } 162: m = ((stogo = sdt - nowtime) + 30)/60; 163: h = m/60; 164: m %= 60; 165: ts = ctime(&sdt); 166: printf("Shutdown at %5.5s (in ", ts+11); 167: if (h > 0) 168: printf("%d hour%s ", h, h != 1 ? "s" : ""); 169: printf("%d minute%s) ", m, m != 1 ? "s" : ""); 170: #ifndef DEBUG 171: (void) signal(SIGHUP, SIG_IGN); 172: (void) signal(SIGQUIT, SIG_IGN); 173: (void) signal(SIGINT, SIG_IGN); 174: #endif 175: (void) signal(SIGTTOU, SIG_IGN); 176: (void) signal(SIGTERM, finish); 177: (void) signal(SIGALRM, timeout); 178: (void) setpriority(PRIO_PROCESS, 0, PRIO_MIN); 179: (void) fflush(stdout); 180: #ifndef DEBUG 181: if (i = fork()) { 182: printf("[pid %d]\n", i); 183: exit(0); 184: } 185: #else 186: (void) putc('\n', stdout); 187: #endif 188: sint = 1 HOURS; 189: f = ""; 190: ufd = open(_PATH_UTMP,0); 191: if (ufd < 0) { 192: err(1, "%s", _PATH_UTMP); 193: /* NOTREACHED */ 194: } 195: first = 1; 196: for (;;) { 197: for (i = 0; stogo <= interval[i].stogo && interval[i].sint; i++) 198: sint = interval[i].sint; 199: if (stogo > 0 && (stogo-sint) < interval[i].stogo) 200: sint = stogo - interval[i].stogo; 201: if (stogo <= NOLOGTIME && nlflag) { 202: nlflag = 0; 203: nolog(sdt); 204: } 205: if (sint >= stogo || sint == 0) 206: f = "FINAL "; 207: nowtime = time((long *)0); 208: (void) lseek(ufd, 0L, 0); 209: while (read(ufd,(char *)&utmp,sizeof utmp)==sizeof utmp) 210: if (utmp.ut_name[0] && 211: strncmp(utmp.ut_name, IGNOREUSER, sizeof(utmp.ut_name))) { 212: if (setjmp(alarmbuf)) 213: continue; 214: (void) strcpy(term, tpath); 215: (void) strncat(term, utmp.ut_line, sizeof utmp.ut_line); 216: (void) alarm(3); 217: #ifdef DEBUG 218: if ((termf = stdout) != NULL) 219: #else 220: if ((termf = fopen(term, "w")) != NULL) 221: #endif 222: { 223: (void) alarm(0); 224: setbuf(termf, tbuf); 225: fprintf(termf, "\n\r\n"); 226: warn(termf, sdt, nowtime, f); 227: if (first || sdt - nowtime > 1 MINUTES) { 228: if (*nolog2) 229: fprintf(termf, "\t...%s", nolog2); 230: } 231: (void) fputc('\r', termf); 232: (void) fputc('\n', termf); 233: (void) alarm(5); 234: #ifdef DEBUG 235: (void) fflush(termf); 236: #else 237: (void) fclose(termf); 238: #endif 239: (void) alarm(0); 240: } 241: } 242: if (stogo <= 0) { 243: printf("\n\007\007System shutdown time has arrived\007\007\n"); 244: syslog(LOG_CRIT, "%s by %s: %s", 245: doreboot ? "reboot" : halt ? "halt" : "shutdown", 246: shutter, nolog2); 247: sleep(2); 248: (void) unlink(nologin); 249: if (!killflg) { 250: printf("but you'll have to do it yourself\n"); 251: finish(); 252: } 253: if (fast) 254: doitfast(); 255: #ifndef DEBUG 256: if (doreboot) 257: execle(REBOOT, "reboot", "-l", nosync, 0, 0); 258: if (halt) 259: execle(HALT, "halt", "-l", nosync, 0, 0); 260: (void) kill(1, SIGTERM); /* to single user */ 261: #else 262: if (doreboot) 263: printf("REBOOT"); 264: if (halt) 265: printf(" HALT"); 266: if (fast) 267: printf(" -l %s (without fsck's)\n", nosync); 268: else 269: printf(" -l %s\n", nosync); 270: else 271: printf("kill -HUP 1\n"); 272: 273: #endif 274: finish(); 275: } 276: stogo = sdt - time((long *) 0); 277: if (stogo > 0 && sint > 0) 278: sleep((unsigned)(sint<stogo ? sint : stogo)); 279: stogo -= sint; 280: first = 0; 281: } 282: } 283: 284: time_t 285: getsdt(s) 286: register char *s; 287: { 288: time_t t, t1, tim; 289: register char c; 290: struct tm *lt; 291: 292: if (strcmp(s, "now") == 0) 293: return(nowtime); 294: if (*s == '+') { 295: ++s; 296: t = 0; 297: for (;;) { 298: c = *s++; 299: if (!isdigit(c)) 300: break; 301: t = t * 10 + c - '0'; 302: } 303: if (t <= 0) 304: t = 5; 305: t *= 60; 306: tim = time((long *) 0) + t; 307: return(tim); 308: } 309: t = 0; 310: while (strlen(s) > 2 && isdigit(*s)) 311: t = t * 10 + *s++ - '0'; 312: if (*s == ':') 313: s++; 314: if (t > 23) 315: goto badform; 316: tim = t*60; 317: t = 0; 318: while (isdigit(*s)) 319: t = t * 10 + *s++ - '0'; 320: if (t > 59) 321: goto badform; 322: tim += t; 323: tim *= 60; 324: t1 = time((long *) 0); 325: lt = localtime(&t1); 326: t = lt->tm_sec + lt->tm_min*60 + (long)lt->tm_hour*3600; 327: if (tim < t || tim >= ((long)24*3600)) { 328: /* before now or after midnight */ 329: printf("That must be tomorrow\nCan't you wait till then?\n"); 330: finish(); 331: } 332: return (t1 + tim - t); 333: badform: 334: printf("Bad time format\n"); 335: finish(); 336: /*NOTREACHED*/ 337: } 338: 339: warn(term, sdt, now, type) 340: FILE *term; 341: time_t sdt, now; 342: char *type; 343: { 344: char *ts; 345: register delay = sdt - now; 346: 347: if (delay > 8) 348: while (delay % 5) 349: delay++; 350: 351: fprintf(term, 352: "\007\007\t*** %sSystem shutdown message from %s@%s ***\r\n\n", 353: type, shutter, hostname); 354: 355: ts = ctime(&sdt); 356: if (delay > 10 MINUTES) 357: fprintf(term, "System going down at %5.5s\r\n", ts+11); 358: else if (delay > 95 SECONDS) { 359: fprintf(term, "System going down in %d minute%s\r\n", 360: (delay+30)/60, (delay+30)/60 != 1 ? "s" : ""); 361: } else if (delay > 0) { 362: fprintf(term, "System going down in %d second%s\r\n", 363: delay, delay != 1 ? "s" : ""); 364: } else 365: fprintf(term, "System going down IMMEDIATELY\r\n"); 366: } 367: 368: doitfast() 369: { 370: register FILE *fastd; 371: 372: if ((fastd = fopen(fastboot, "w")) != NULL) { 373: putc('\n', fastd); 374: (void) fclose(fastd); 375: } 376: } 377: 378: nolog(sdt) 379: time_t sdt; 380: { 381: register FILE *nologf; 382: 383: (void) unlink(nologin); /* in case linked to std file */ 384: if ((nologf = fopen(nologin, "w")) != NULL) { 385: fprintf(nologf, nolog1, (ctime(&sdt)) + 11); 386: if (*nolog2) 387: fprintf(nologf, "\t%s\n", nolog2 + 1); 388: (void) fclose(nologf); 389: } 390: } 391: 392: finish() 393: { 394: (void) signal(SIGTERM, SIG_IGN); 395: (void) unlink(nologin); 396: exit(0); 397: } 398: 399: timeout() 400: { 401: longjmp(alarmbuf, 1); 402: }