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