1*3484Sroot /* @(#)shutdown.c 4.3 (Berkeley/Melbourne) 81/04/03 */ 22373Swnj 32373Swnj #include <stdio.h> 42373Swnj #include <ctype.h> 52373Swnj #include <signal.h> 62373Swnj #include <utmp.h> 72373Swnj #include <time.h> 82373Swnj #include <sys/types.h> 92373Swnj /* 102373Swnj * /etc/shutdown when [messages] 112373Swnj * 122373Swnj * allow super users to tell users and remind users 132373Swnj * of iminent shutdown of unix 142373Swnj * and shut it down automatically 152373Swnj * and even reboot or halt the machine if they desire 162373Swnj * 172373Swnj * Ian Johnstone, Sydney, 1977 182373Swnj * Robert Elz, Melbourne, 1978 192373Swnj * Peter Lamb, Melbourne, 1980 202373Swnj * William Joy, Berkeley, 1981 212818Swnj * Michael Toy, Berkeley, 1981 222373Swnj */ 232818Swnj #ifdef DEBUG 242818Swnj #define LOGFILE "shutdown.log" 252818Swnj #else 262818Swnj #define LOGFILE "/usr/adm/shutdownlog" 272818Swnj #endif 282373Swnj #define REBOOT "/etc/reboot" 292373Swnj #define HALT "/etc/halt" 302373Swnj #define MAXINTS 20 312373Swnj #define HOURS *3600 322373Swnj #define MINUTES *60 332373Swnj #define SECONDS 342373Swnj #define NLOG 20 /* no of lines possible for message */ 352373Swnj #define NOLOGTIME 5 MINUTES 362373Swnj 372373Swnj int do_nothing(); 382373Swnj time_t getsdt(); 392373Swnj 402373Swnj extern char *ctime(); 412373Swnj extern struct tm *localtime(); 422373Swnj 432373Swnj struct utmp utmp; 442373Swnj int sint; 452373Swnj int stogo; 462373Swnj char tpath[] = "/dev/"; 472373Swnj int nlflag = 1; /* nolog yet to be done */ 482373Swnj int killflg = 1; 492373Swnj int reboot = 0; 502373Swnj int halt = 0; 512373Swnj char term[sizeof tpath + sizeof utmp.ut_line]; 522373Swnj char tbuf[BUFSIZ]; 532373Swnj char nolog1[] = "\n\nNO LOGINS: System going down at %5.5s\n\n"; 542373Swnj char *nolog2[NLOG+1]; 552373Swnj #ifdef DEBUG 562373Swnj char nologin[] = "nologin"; 572373Swnj #else 582373Swnj char nologin[] = "/etc/nologin"; 592373Swnj #endif 602373Swnj int slots; 612373Swnj struct interval { 622373Swnj int stogo; 632373Swnj int sint; 642373Swnj } interval[] = { 652373Swnj 4 HOURS, 1 HOURS, 662373Swnj 2 HOURS, 30 MINUTES, 672373Swnj 1 HOURS, 15 MINUTES, 682373Swnj 30 MINUTES, 10 MINUTES, 692373Swnj 15 MINUTES, 5 MINUTES, 702818Swnj 10 MINUTES, 5 MINUTES, 712818Swnj 5 MINUTES, 3 MINUTES, 722373Swnj 2 MINUTES, 30 SECONDS, 732373Swnj 0 SECONDS, 0 SECONDS 742373Swnj }; 752818Swnj char *shutter, *getlogin(); 762373Swnj main(argc,argv) 772373Swnj int argc; 782373Swnj char **argv; 792373Swnj { 802373Swnj register i, ufd; 812373Swnj register char **mess, *f; 822373Swnj char *ts; 832373Swnj long sdt; 842373Swnj int h, m; 852373Swnj long nowtime; 862373Swnj FILE *termf; 872373Swnj 882818Swnj shutter = getlogin(); 892373Swnj argc--, argv++; 902373Swnj while (argc > 0 && (f = argv[0], *f++ == '-')) { 912373Swnj while (i = *f++) switch (i) { 922373Swnj case 'k': 932373Swnj killflg = 0; 942373Swnj continue; 952373Swnj case 'r': 962373Swnj reboot = 1; 972373Swnj continue; 982373Swnj case 'h': 992373Swnj halt = 1; 1002373Swnj continue; 1012373Swnj default: 1022373Swnj fprintf(stderr, "shutdown: '%c' - unknown flag\n", i); 1032373Swnj exit(1); 1042373Swnj } 1052373Swnj argc--, argv++; 1062373Swnj } 1072373Swnj if (argc < 1) { 1082373Swnj printf("Usage: %s [-krd] shutdowntime [nologmessage]\n", 1092373Swnj argv[0]); 1102373Swnj finish(); 1112373Swnj } 1122373Swnj sdt = getsdt(argv[0]); 1132373Swnj argc--, argv++; 1142373Swnj i = 0; 1152373Swnj while (argc-- > 0) 1162373Swnj if (i < NLOG) 1172373Swnj nolog2[i++] = *argv++; 1182373Swnj nolog2[i] = NULL; 1192373Swnj nowtime = time((long *)0); 1202373Swnj m = ((stogo = sdt - nowtime) + 30)/60; 1212373Swnj h = m/60; 1222373Swnj m %= 60; 1232373Swnj ts = ctime(&sdt); 1242818Swnj printf("Shutdown at %5.5s (in ", ts+11); 1252373Swnj if (h > 0) 1262373Swnj printf("%d hour%s ", h, h != 1 ? "s" : ""); 1272818Swnj printf("%d minute%s) ", m, m != 1 ? "s" : ""); 1282373Swnj #ifndef DEBUG 1292373Swnj signal(SIGHUP, SIG_IGN); 1302373Swnj signal(SIGQUIT, SIG_IGN); 1312373Swnj signal(SIGINT, SIG_IGN); 1322373Swnj #endif 1332373Swnj signal(SIGTERM, finish); 1342373Swnj signal(SIGALRM, do_nothing); 1352373Swnj nice(-20); 1362818Swnj #ifndef DEBUG 1372373Swnj if (i = fork()) { 1382818Swnj printf("[pid %d]\n", i); 1392373Swnj exit(0); 1402373Swnj } 1412818Swnj #endif 1422373Swnj sint = 1 HOURS; 1432373Swnj f = ""; 1442373Swnj for (;;) { 1452373Swnj for (i = 0; stogo <= interval[i].stogo && interval[i].sint; i++) 1462373Swnj sint = interval[i].sint; 1472373Swnj if (stogo <= NOLOGTIME && nlflag) { 1482373Swnj nlflag = 0; 1492373Swnj nolog(sdt); 1502373Swnj } 1512373Swnj if (sint >= stogo || sint == 0) 1522373Swnj f = "FINAL "; 1532373Swnj ufd = open("/etc/utmp",0); 1542373Swnj nowtime = time((long *) 0); 1552373Swnj while (read(ufd,&utmp,sizeof utmp)==sizeof utmp) 1562373Swnj if (utmp.ut_name[0]) { 1572373Swnj strcpy(term, tpath); 1582373Swnj strncat(term, utmp.ut_line, sizeof utmp.ut_line); 1592373Swnj alarm(3); 1602373Swnj #ifdef DEBUG 1612818Swnj if ((termf = stdout) != NULL) 1622373Swnj #else 1632373Swnj if ((termf = fopen(term, "w")) != NULL) 1642373Swnj #endif 1652373Swnj { 1662373Swnj alarm(0); 1672373Swnj setbuf(termf, tbuf); 1682373Swnj fprintf(termf, "\n\n"); 1692373Swnj warn(termf, sdt, nowtime); 1702373Swnj if (sdt - nowtime > 1 MINUTES) 1712373Swnj for (mess = nolog2; *mess; mess++) 1722373Swnj fprintf(termf, "%s ", *mess); 1732373Swnj fputc('\n', termf); 1742818Swnj alarm(5); 1752818Swnj #ifdef DEBUG 1762818Swnj fflush(termf); 1772818Swnj #else 1782373Swnj fclose(termf); 1792818Swnj #endif 1802373Swnj alarm(0); 1812373Swnj } 1822373Swnj } 1832373Swnj if (stogo < 0) { 1842373Swnj printf("\n\007\007System shutdown time has arrived\007\007\n"); 1852818Swnj log_entry(sdt); 1862373Swnj unlink(nologin); 1872373Swnj if (!killflg) { 1882373Swnj printf("but you'll have to do it yourself\n"); 1892373Swnj finish(); 1902373Swnj } 1912373Swnj #ifndef DEBUG 1922373Swnj if (reboot) 1932373Swnj execle(REBOOT, "reboot", 0, 0); 1942373Swnj if (halt) 1952373Swnj execle(HALT, "halt", 0, 0); 1962373Swnj kill(1, SIGTERM); /* sync */ 1972373Swnj kill(1, SIGTERM); /* sync */ 1982373Swnj sleep(20); 1992373Swnj #else 2002373Swnj printf("EXTERMINATE EXTERMINATE\n"); 2012373Swnj #endif 2022373Swnj finish(); 2032373Swnj } 2042373Swnj stogo = sdt - time((long *) 0); 2052373Swnj if (stogo > 0) 2062373Swnj sleep(sint<stogo ? sint : stogo); 2072373Swnj stogo -= sint; 2082373Swnj } 2092373Swnj } 2102373Swnj 2112373Swnj time_t 2122373Swnj getsdt(s) 2132373Swnj register char *s; 2142373Swnj { 2152373Swnj time_t t, t1, tim; 2162373Swnj register char c; 2172373Swnj struct tm *lt; 2182373Swnj 2192373Swnj if (*s == '+') { 2202373Swnj ++s; 2212373Swnj t = 0; 2222373Swnj for (;;) { 2232373Swnj c = *s++; 2242373Swnj if (!isdigit(c)) 2252373Swnj break; 2262373Swnj t = t * 10 + c - '0'; 2272373Swnj } 2282373Swnj if (t <= 0) 2292373Swnj t = 5; 2302373Swnj t *= 60; 2312373Swnj tim = time((long *) 0) + t; 2322373Swnj return(tim); 2332373Swnj } 2342373Swnj t = 0; 2352373Swnj while (strlen(s) > 2 && isdigit(*s)) 2362373Swnj t = t * 10 + *s++ - '0'; 2372373Swnj if (*s == ':') 2382373Swnj s++; 2392373Swnj if (t > 23) 2402373Swnj goto badform; 2412373Swnj tim = t*60; 2422373Swnj t = 0; 2432373Swnj while (isdigit(*s)) 2442373Swnj t = t * 10 + *s++ - '0'; 2452373Swnj if (t > 59) 2462373Swnj goto badform; 2472373Swnj tim += t; 2482373Swnj tim *= 60; 2492373Swnj t1 = time((long *) 0); 2502373Swnj lt = localtime(&t1); 2512373Swnj t = lt->tm_sec + lt->tm_min*60 + lt->tm_hour*3600; 2522373Swnj if (tim < t || tim >= (24*3600)) { 2532373Swnj /* before now or after midnight */ 2542373Swnj printf("That must be tomorrow\nCan't you wait till then?\n"); 2552373Swnj finish(); 2562373Swnj } 2572373Swnj return (t1 + tim -t); 2582373Swnj badform: 2592373Swnj printf("Bad time format\n"); 2602373Swnj finish(); 2612373Swnj } 2622373Swnj 2632373Swnj warn(term, sdt, nowtime) 2642373Swnj FILE *term; 2652373Swnj long sdt, nowtime; 2662373Swnj { 2672373Swnj char *ts; 2682373Swnj 2692818Swnj fprintf(term, "\007\007*** System shutdown message from %s ***\n", shutter); 2702373Swnj ts = ctime(&sdt); 2712373Swnj if (sdt - nowtime > 10 MINUTES) 2722373Swnj fprintf(term, "System going down at %5.5s\n", ts+11); 2732373Swnj else if ( sdt - nowtime > 60 SECONDS ) { 2742373Swnj fprintf(term, "System going down in %d minute%s\n", 2752373Swnj (sdt-nowtime+30)/60, (sdt-nowtime+30)/60 != 1 ? "s" : ""); 2762373Swnj } else if ( sdt - nowtime > 0 ) { 2772818Swnj fprintf(term, "System going down in %d second%s\n", 2782373Swnj sdt-nowtime, sdt-nowtime != 1 ? "s" : ""); 2792373Swnj } else 2802373Swnj fprintf(term, "System going down IMMEDIATELY\n"); 2812373Swnj } 2822373Swnj 2832373Swnj nolog(sdt) 2842373Swnj long sdt; 2852373Swnj { 2862373Swnj FILE *nologf; 2872373Swnj register char **mess; 2882373Swnj 2892373Swnj if ((nologf = fopen(nologin, "w")) != NULL) { 2902373Swnj fprintf(nologf, nolog1, (ctime(&sdt)) + 11); 2912373Swnj for (mess = nolog2; *mess; mess++) 2922373Swnj fprintf(nologf, "\t%s\n", *mess); 2932373Swnj fclose(nologf); 2942373Swnj } 2952373Swnj } 2962373Swnj 2972373Swnj finish() 2982373Swnj { 2992373Swnj signal(SIGTERM, SIG_IGN); 3002373Swnj unlink(nologin); 3012373Swnj exit(0); 3022373Swnj } 3032373Swnj 3042373Swnj do_nothing() 3052373Swnj { 3062373Swnj 3072373Swnj signal(SIGALRM, do_nothing); 3082373Swnj } 3092818Swnj 3102818Swnj /* 3112818Swnj * make an entry in the shutdown log 3122818Swnj */ 3132818Swnj 314*3484Sroot char *days[] = { 315*3484Sroot "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" 316*3484Sroot }; 317*3484Sroot 318*3484Sroot char *months[] = { 319*3484Sroot "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", 320*3484Sroot "Oct", "Nov", "Dec" 321*3484Sroot }; 322*3484Sroot 323*3484Sroot log_entry(now) 324*3484Sroot time_t now; 3252818Swnj { 326*3484Sroot register FILE *fp; 327*3484Sroot register char **mess; 328*3484Sroot struct tm *tm, *localtime(); 3292818Swnj 330*3484Sroot tm = localtime(&now); 331*3484Sroot fp = fopen(LOGFILE, "a"); 332*3484Sroot fseek(fp, 0L, 2); 333*3484Sroot fprintf(fp, "%02d:%02d %s %s %2d, %4d. Shutdown:", tm->tm_hour, 334*3484Sroot tm->tm_min, days[tm->tm_wday], months[tm->tm_mon], 335*3484Sroot tm->tm_mday, tm->tm_year + 1900); 3362818Swnj for (mess = nolog2; *mess; mess++) 337*3484Sroot fprintf(fp, " %s", *mess); 338*3484Sroot fputc('\n', fp); 339*3484Sroot fclose(fp); 3402818Swnj } 341