1: static char *sccsid = "@(#)shutdown.c 4.7 (Berkeley) 81/05/11"; 2: 3: #include <stdio.h> 4: #include <ctype.h> 5: #include <signal.h> 6: #include <utmp.h> 7: #include <time.h> 8: #include <sys/types.h> 9: #include <pwd.h> 10: /* 11: * /etc/shutdown when [messages] 12: * 13: * allow super users to tell users and remind users 14: * of imminent shutdown of unix 15: * and shut it down automatically 16: * and even reboot or halt the machine if they desire 17: * 18: * Ian Johnstone, Sydney, 1977 19: * Robert Elz, Melbourne, 1978 20: * Peter Lamb, Melbourne, 1980 21: * William Joy, Berkeley, 1981 22: * Michael Toy, Berkeley, 1981 23: * Dave Presotto, Berkeley, 1981 24: * 25: */ 26: #ifdef DEBUG 27: #define LOGFILE "shutdown.log" 28: #else 29: #define LOGFILE "/usr/adm/shutdownlog" 30: #endif 31: #define REBOOT "/etc/reboot" 32: #define HALT_OPT "-h" /* option to reboot to halt */ 33: #define MAXINTS 20 34: #define HOURS *3600 35: #define MINUTES *60 36: #define SECONDS 37: #define NLOG 20 /* no of lines possible for message */ 38: #define NOLOGTIME 5 MINUTES 39: #define IGNOREUSER "sleeper" 40: 41: int finish (); 42: int do_nothing(); 43: time_t getsdt(); 44: 45: extern char *ctime(); 46: extern time_t time(); 47: extern struct tm *localtime(); 48: 49: struct utmp utmp; 50: int sint; 51: int stogo; 52: char tpath[] = "/dev/"; 53: int nlflag = 1; /* nolog yet to be done */ 54: int killflg = 1; 55: int reboot = 0; 56: int halt = 0; 57: char term[sizeof tpath + sizeof utmp.ut_line]; 58: char tbuf[BUFSIZ]; 59: char nolog1[] = "\n\nNO LOGINS: System going down at %5.5s\n\n"; 60: char *nolog2[NLOG+1]; 61: #ifdef DEBUG 62: char nologin[] = "nologin"; 63: #else 64: char nologin[] = "/etc/nologin"; 65: #endif 66: int slots; 67: struct interval { 68: int stogo; 69: int sint; 70: } interval[] = { 71: 4 HOURS, 1 HOURS, 72: 2 HOURS, 30 MINUTES, 73: 1 HOURS, 15 MINUTES, 74: 30 MINUTES, 10 MINUTES, 75: 15 MINUTES, 5 MINUTES, 76: 10 MINUTES, 5 MINUTES, 77: 5 MINUTES, 3 MINUTES, 78: 2 MINUTES, 30 SECONDS, 79: 0 SECONDS, 0 SECONDS 80: }; 81: char *shutter; 82: struct passwd *pwent, *getpwuid(); 83: main(argc,argv) 84: int argc; 85: char **argv; 86: { 87: register i, ufd; 88: register char **mess, *f; 89: char *ts; 90: time_t sdt; 91: int h, m; 92: time_t nowtime; 93: FILE *termf; 94: 95: pwent = getpwuid(getuid()); 96: if (pwent != (struct passwd *) NULL) 97: shutter = pwent->pw_name; 98: 99: argc--, argv++; 100: while (argc > 0 && (f = argv[0], *f++ == '-')) { 101: while (i = *f++) switch (i) { 102: case 'k': 103: killflg = 0; 104: continue; 105: case 'r': 106: reboot = 1; 107: continue; 108: case 'h': 109: halt = 1; 110: continue; 111: default: 112: fprintf(stderr, "shutdown: '%c' - unknown flag\n", i); 113: exit(1); 114: } 115: argc--, argv++; 116: } 117: if (argc < 1) { 118: printf("Usage: shutdown [ -krd ] shutdowntime [ message ]\n"); 119: finish(); 120: } 121: if (geteuid()) { 122: fprintf(stderr, "NOT super-user\n"); 123: finish(); 124: } 125: sdt = getsdt(argv[0]); 126: argc--, argv++; 127: i = 0; 128: while (argc-- > 0) 129: if (i < NLOG) 130: nolog2[i++] = *argv++; 131: nolog2[i] = NULL; 132: nowtime = time((time_t *)0); 133: m = ((stogo = sdt - nowtime) + 30)/60; 134: h = m/60; 135: m %= 60; 136: ts = ctime(&sdt); 137: printf("Shutdown at %5.5s (in ", ts+11); 138: if (h > 0) 139: printf("%d hour%s ", h, h != 1 ? "s" : ""); 140: printf("%d minute%s) ", m, m != 1 ? "s" : ""); 141: #ifndef DEBUG 142: signal(SIGHUP, SIG_IGN); 143: signal(SIGQUIT, SIG_IGN); 144: signal(SIGINT, SIG_IGN); 145: #endif 146: signal(SIGTERM, finish); 147: signal(SIGALRM, do_nothing); 148: nice(-20); 149: #ifndef DEBUG 150: if (i = fork()) { 151: printf("[pid %d]\n", i); 152: exit(0); 153: } 154: #endif 155: sint = 1 HOURS; 156: f = ""; 157: for (;;) { 158: for (i = 0; stogo <= interval[i].stogo && interval[i].sint; i++) 159: sint = interval[i].sint; 160: if (stogo <= NOLOGTIME && nlflag) { 161: nlflag = 0; 162: nolog(sdt); 163: } 164: if (sint >= stogo || sint == 0) 165: f = "FINAL "; 166: ufd = open("/etc/utmp",0); 167: nowtime = time((time_t *) 0); 168: while (read(ufd,&utmp,sizeof utmp)==sizeof utmp) 169: if (utmp.ut_name[0] && strncmp(utmp.ut_name, IGNOREUSER, sizeof(utmp.ut_name)) ){ 170: strcpy(term, tpath); 171: strncat(term, utmp.ut_line, sizeof utmp.ut_line); 172: alarm(3); 173: #ifdef DEBUG 174: if ((termf = stdout) != NULL) 175: #else 176: if ((termf = fopen(term, "w")) != NULL) 177: #endif 178: { 179: alarm(0); 180: setbuf(termf, tbuf); 181: fprintf(termf, "\n\n"); 182: warn(termf, sdt, nowtime); 183: if (sdt - nowtime > 1 MINUTES) 184: for (mess = nolog2; *mess; mess++) 185: fprintf(termf, "%s ", *mess); 186: fputc('\n', termf); 187: alarm(5); 188: #ifdef DEBUG 189: fflush(termf); 190: #else 191: fclose(termf); 192: #endif 193: alarm(0); 194: } 195: } 196: if (stogo < 0) { 197: printf("\n\007\007System shutdown time has arrived\007\007\n"); 198: log_entry(sdt); 199: unlink(nologin); 200: if (!killflg) { 201: printf("but you'll have to do it yourself\n"); 202: finish(); 203: } 204: #ifndef DEBUG 205: if (reboot) 206: execle(REBOOT, "reboot", 0, 0); 207: if (halt) 208: execle(REBOOT, "reboot", HALT_OPT, 0, 0); 209: kill(1, SIGTERM); /* sync */ 210: kill(1, SIGTERM); /* sync */ 211: sleep(20); 212: #else 213: printf("EXTERMINATE EXTERMINATE\n"); 214: #endif 215: finish(); 216: } 217: stogo = sdt - time((time_t *) 0); 218: if (stogo > 0) 219: sleep(sint<stogo ? sint : stogo); 220: stogo -= sint; 221: } 222: } 223: 224: time_t 225: getsdt(s) 226: register char *s; 227: { 228: time_t t, t1, tim; 229: register char c; 230: struct tm *lt; 231: 232: if (*s == '+') { 233: ++s; 234: t = 0; 235: for (;;) { 236: c = *s++; 237: if (!isdigit(c)) 238: break; 239: t = t * 10 + c - '0'; 240: } 241: if (t <= 0) 242: t = 5; 243: t *= 60; 244: tim = time((time_t *) 0) + t; 245: return(tim); 246: } 247: t = 0; 248: while (strlen(s) > 2 && isdigit(*s)) 249: t = t * 10 + *s++ - '0'; 250: if (*s == ':') 251: s++; 252: if (t > 23) 253: goto badform; 254: tim = t*60; 255: t = 0; 256: while (isdigit(*s)) 257: t = t * 10 + *s++ - '0'; 258: if (t > 59) 259: goto badform; 260: tim += t; 261: tim *= 60; 262: t1 = time((time_t *) 0); 263: lt = localtime(&t1); 264: t = lt->tm_sec + lt->tm_min*60L + lt->tm_hour*3600L; 265: if (tim < t || tim >= (24*3600L)) { 266: /* before now or after midnight */ 267: printf("That must be tomorrow\nCan't you wait till then?\n"); 268: finish(); 269: } 270: return (t1 + tim -t); 271: badform: 272: printf("Bad time format\n"); 273: finish(); 274: } 275: 276: warn(term, sdt, nowtime) 277: FILE *term; 278: time_t sdt, nowtime; 279: { 280: char *ts; 281: 282: if (shutter) 283: fprintf(term, 284: "\007\007*** System shutdown message from %s ***\n", 285: shutter); 286: else 287: fprintf(term, 288: "\007\007*** System shutdown message ***\n"); 289: ts = ctime(&sdt); 290: if (sdt - nowtime > 10 MINUTES) 291: fprintf(term, "System going down at %5.5s\n", ts+11); 292: else if ( sdt - nowtime > 60 SECONDS ) { 293: fprintf(term, "System going down in %d minute%s\n", 294: (int)((sdt-nowtime+30)/60), 295: (sdt-nowtime+30)/60 != 1 ? "s" : ""); 296: } else if ( sdt - nowtime > 0 ) { 297: fprintf(term, "System going down in %d second%s\n", 298: (int)(sdt-nowtime), sdt-nowtime != 1 ? "s" : ""); 299: } else 300: fprintf(term, "System going down IMMEDIATELY\n"); 301: } 302: 303: nolog(sdt) 304: time_t sdt; 305: { 306: FILE *nologf; 307: register char **mess; 308: 309: if ((nologf = fopen(nologin, "w")) != NULL) { 310: fprintf(nologf, nolog1, (ctime(&sdt)) + 11); 311: for (mess = nolog2; *mess; mess++) 312: fprintf(nologf, "\t%s\n", *mess); 313: fclose(nologf); 314: } 315: } 316: 317: finish() 318: { 319: signal(SIGTERM, SIG_IGN); 320: unlink(nologin); 321: exit(0); 322: } 323: 324: do_nothing() 325: { 326: signal(SIGALRM, do_nothing); 327: } 328: 329: /* 330: * make an entry in the shutdown log 331: */ 332: 333: char *days[] = { 334: "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" 335: }; 336: 337: char *months[] = { 338: "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", 339: "Oct", "Nov", "Dec" 340: }; 341: 342: log_entry(now) 343: time_t now; 344: { 345: register FILE *fp; 346: register char **mess; 347: struct tm *tm, *localtime(); 348: 349: tm = localtime(&now); 350: fp = fopen(LOGFILE, "a"); 351: if (fp==0) 352: return; 353: fseek(fp, 0L, 2); 354: fprintf(fp, "%02d:%02d %s %s %2d, %4d. Shutdown:", tm->tm_hour, 355: tm->tm_min, days[tm->tm_wday], months[tm->tm_mon], 356: tm->tm_mday, tm->tm_year + 1900); 357: for (mess = nolog2; *mess; mess++) 358: fprintf(fp, " %s", *mess); 359: if (shutter) 360: fprintf(fp, " (by %s)", shutter); 361: fputc('\n', fp); 362: fclose(fp); 363: }