112682Ssam #ifndef lint 2*13178Sroot static char *sccsid = "@(#)shutdown.c 4.19 (Berkeley) 83/06/17"; 312682Ssam #endif 42373Swnj 52373Swnj #include <stdio.h> 62373Swnj #include <ctype.h> 72373Swnj #include <signal.h> 82373Swnj #include <utmp.h> 912897Ssam #include <sys/time.h> 1012897Ssam #include <sys/resource.h> 112373Swnj #include <sys/types.h> 122373Swnj /* 132373Swnj * /etc/shutdown when [messages] 142373Swnj * 152373Swnj * allow super users to tell users and remind users 162373Swnj * of iminent shutdown of unix 172373Swnj * and shut it down automatically 182373Swnj * and even reboot or halt the machine if they desire 192373Swnj */ 202818Swnj #ifdef DEBUG 212818Swnj #define LOGFILE "shutdown.log" 222818Swnj #else 232818Swnj #define LOGFILE "/usr/adm/shutdownlog" 242818Swnj #endif 252373Swnj #define REBOOT "/etc/reboot" 262373Swnj #define HALT "/etc/halt" 272373Swnj #define MAXINTS 20 282373Swnj #define HOURS *3600 292373Swnj #define MINUTES *60 302373Swnj #define SECONDS 313880Swnj #define NLOG 20 /* no of args possible for message */ 322373Swnj #define NOLOGTIME 5 MINUTES 333885Sroot #define IGNOREUSER "sleeper" 342373Swnj 356203Sroot char hostname[32]; 366203Sroot 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 608841Smckusick time_t nowtime; 618841Smckusick 622373Swnj struct interval { 632373Swnj int stogo; 642373Swnj int sint; 652373Swnj } interval[] = { 662373Swnj 4 HOURS, 1 HOURS, 672373Swnj 2 HOURS, 30 MINUTES, 682373Swnj 1 HOURS, 15 MINUTES, 692373Swnj 30 MINUTES, 10 MINUTES, 702373Swnj 15 MINUTES, 5 MINUTES, 712818Swnj 10 MINUTES, 5 MINUTES, 722818Swnj 5 MINUTES, 3 MINUTES, 738841Smckusick 2 MINUTES, 1 MINUTES, 748841Smckusick 1 MINUTES, 30 SECONDS, 752373Swnj 0 SECONDS, 0 SECONDS 762373Swnj }; 778841Smckusick 782818Swnj char *shutter, *getlogin(); 798841Smckusick 802373Swnj main(argc,argv) 812373Swnj int argc; 822373Swnj char **argv; 832373Swnj { 842373Swnj register i, ufd; 852373Swnj register char **mess, *f; 862373Swnj char *ts; 878841Smckusick time_t sdt; 882373Swnj int h, m; 898841Smckusick int first; 902373Swnj FILE *termf; 912373Swnj 922818Swnj shutter = getlogin(); 936203Sroot gethostname(hostname, sizeof (hostname)); 942373Swnj argc--, argv++; 952373Swnj while (argc > 0 && (f = argv[0], *f++ == '-')) { 962373Swnj while (i = *f++) switch (i) { 972373Swnj case 'k': 982373Swnj killflg = 0; 992373Swnj continue; 1002373Swnj case 'r': 1012373Swnj reboot = 1; 1022373Swnj continue; 1032373Swnj case 'h': 1042373Swnj halt = 1; 1052373Swnj continue; 1062373Swnj default: 1072373Swnj fprintf(stderr, "shutdown: '%c' - unknown flag\n", i); 1082373Swnj exit(1); 1092373Swnj } 1102373Swnj argc--, argv++; 1112373Swnj } 1122373Swnj if (argc < 1) { 1133880Swnj printf("Usage: %s [ -krh ] shutdowntime [ message ]\n", 1142373Swnj argv[0]); 1152373Swnj finish(); 1162373Swnj } 1173720Sroot if (geteuid()) { 1183720Sroot fprintf(stderr, "NOT super-user\n"); 1193648Stoy finish(); 1203648Stoy } 1218841Smckusick nowtime = time((time_t *)0); 1222373Swnj sdt = getsdt(argv[0]); 1232373Swnj argc--, argv++; 1242373Swnj i = 0; 1252373Swnj while (argc-- > 0) 1262373Swnj if (i < NLOG) 1272373Swnj nolog2[i++] = *argv++; 1282373Swnj nolog2[i] = NULL; 1292373Swnj m = ((stogo = sdt - nowtime) + 30)/60; 1302373Swnj h = m/60; 1312373Swnj m %= 60; 1322373Swnj ts = ctime(&sdt); 1332818Swnj printf("Shutdown at %5.5s (in ", ts+11); 1342373Swnj if (h > 0) 1352373Swnj printf("%d hour%s ", h, h != 1 ? "s" : ""); 1362818Swnj printf("%d minute%s) ", m, m != 1 ? "s" : ""); 1372373Swnj #ifndef DEBUG 1382373Swnj signal(SIGHUP, SIG_IGN); 1392373Swnj signal(SIGQUIT, SIG_IGN); 1402373Swnj signal(SIGINT, SIG_IGN); 1412373Swnj #endif 14212129Sedward signal(SIGTTOU, SIG_IGN); 1432373Swnj signal(SIGTERM, finish); 1442373Swnj signal(SIGALRM, do_nothing); 14512897Ssam setpriority(PRIO_PROCESS, 0, PRIO_MIN); 1463880Swnj fflush(stdout); 1472818Swnj #ifndef DEBUG 1482373Swnj if (i = fork()) { 1492818Swnj printf("[pid %d]\n", i); 1502373Swnj exit(0); 1512373Swnj } 1528841Smckusick #else 1538841Smckusick putc('\n', stdout); 1542818Swnj #endif 1552373Swnj sint = 1 HOURS; 1562373Swnj f = ""; 1578841Smckusick ufd = open("/etc/utmp",0); 1588841Smckusick if (ufd < 0) { 1598841Smckusick perror("shutdown: /etc/utmp"); 1608841Smckusick exit(1); 1618841Smckusick } 1628841Smckusick first = 1; 1632373Swnj for (;;) { 1642373Swnj for (i = 0; stogo <= interval[i].stogo && interval[i].sint; i++) 1652373Swnj sint = interval[i].sint; 1668841Smckusick if (stogo > 0 && (stogo-sint) < interval[i].stogo) 1678841Smckusick sint = stogo - interval[i].stogo; 1682373Swnj if (stogo <= NOLOGTIME && nlflag) { 1692373Swnj nlflag = 0; 1702373Swnj nolog(sdt); 1712373Swnj } 1722373Swnj if (sint >= stogo || sint == 0) 1732373Swnj f = "FINAL "; 1748841Smckusick nowtime = time((time_t *) 0); 1758841Smckusick lseek(ufd, 0L, 0); 1762373Swnj while (read(ufd,&utmp,sizeof utmp)==sizeof utmp) 1773885Sroot if (utmp.ut_name[0] && 1783885Sroot strncmp(utmp.ut_name, IGNOREUSER, sizeof(utmp.ut_name))) { 1792373Swnj strcpy(term, tpath); 1802373Swnj strncat(term, utmp.ut_line, sizeof utmp.ut_line); 1812373Swnj alarm(3); 1822373Swnj #ifdef DEBUG 1832818Swnj if ((termf = stdout) != NULL) 1842373Swnj #else 1852373Swnj if ((termf = fopen(term, "w")) != NULL) 1862373Swnj #endif 1872373Swnj { 1882373Swnj alarm(0); 1892373Swnj setbuf(termf, tbuf); 1908841Smckusick fprintf(termf, "\n\r\n"); 1918841Smckusick warn(termf, sdt, nowtime, f); 1928841Smckusick if (first || sdt - nowtime > 1 MINUTES) { 1938841Smckusick if (*nolog2) 1948841Smckusick fprintf(termf, "\t..."); 1952373Swnj for (mess = nolog2; *mess; mess++) 1968841Smckusick fprintf(termf, " %s", *mess); 1978841Smckusick } 1988841Smckusick fputc('\r', termf); 1992373Swnj fputc('\n', termf); 2002818Swnj alarm(5); 2012818Swnj #ifdef DEBUG 2022818Swnj fflush(termf); 2032818Swnj #else 2042373Swnj fclose(termf); 2052818Swnj #endif 2062373Swnj alarm(0); 2072373Swnj } 2082373Swnj } 2098841Smckusick if (stogo <= 0) { 2102373Swnj printf("\n\007\007System shutdown time has arrived\007\007\n"); 2112818Swnj log_entry(sdt); 2122373Swnj unlink(nologin); 2132373Swnj if (!killflg) { 2142373Swnj printf("but you'll have to do it yourself\n"); 2152373Swnj finish(); 2162373Swnj } 2172373Swnj #ifndef DEBUG 2188841Smckusick kill(-1, SIGTERM); /* terminate everyone */ 2198841Smckusick sleep(5); /* & wait while they die */ 2202373Swnj if (reboot) 2212373Swnj execle(REBOOT, "reboot", 0, 0); 2222373Swnj if (halt) 2232373Swnj execle(HALT, "halt", 0, 0); 2242373Swnj kill(1, SIGTERM); /* sync */ 2252373Swnj kill(1, SIGTERM); /* sync */ 2262373Swnj sleep(20); 2272373Swnj #else 2282373Swnj printf("EXTERMINATE EXTERMINATE\n"); 2292373Swnj #endif 2302373Swnj finish(); 2312373Swnj } 2328841Smckusick stogo = sdt - time((time_t *) 0); 2338841Smckusick if (stogo > 0 && sint > 0) 2342373Swnj sleep(sint<stogo ? sint : stogo); 2352373Swnj stogo -= sint; 2368841Smckusick first = 0; 2372373Swnj } 2382373Swnj } 2392373Swnj 2402373Swnj time_t 2412373Swnj getsdt(s) 2428841Smckusick register char *s; 2432373Swnj { 2442373Swnj time_t t, t1, tim; 2452373Swnj register char c; 2462373Swnj struct tm *lt; 2472373Swnj 2488841Smckusick if (strcmp(s, "now") == 0) 2498841Smckusick return(nowtime); 2502373Swnj if (*s == '+') { 2512373Swnj ++s; 2522373Swnj t = 0; 2532373Swnj for (;;) { 2542373Swnj c = *s++; 2552373Swnj if (!isdigit(c)) 2562373Swnj break; 2572373Swnj t = t * 10 + c - '0'; 2582373Swnj } 2592373Swnj if (t <= 0) 2602373Swnj t = 5; 2612373Swnj t *= 60; 2628841Smckusick tim = time((time_t *) 0) + t; 2632373Swnj return(tim); 2642373Swnj } 2652373Swnj t = 0; 2662373Swnj while (strlen(s) > 2 && isdigit(*s)) 2672373Swnj t = t * 10 + *s++ - '0'; 2682373Swnj if (*s == ':') 2692373Swnj s++; 2702373Swnj if (t > 23) 2712373Swnj goto badform; 2722373Swnj tim = t*60; 2732373Swnj t = 0; 2742373Swnj while (isdigit(*s)) 2752373Swnj t = t * 10 + *s++ - '0'; 2762373Swnj if (t > 59) 2772373Swnj goto badform; 2782373Swnj tim += t; 2792373Swnj tim *= 60; 2808841Smckusick t1 = time((time_t *) 0); 2812373Swnj lt = localtime(&t1); 2822373Swnj t = lt->tm_sec + lt->tm_min*60 + lt->tm_hour*3600; 2832373Swnj if (tim < t || tim >= (24*3600)) { 2842373Swnj /* before now or after midnight */ 2852373Swnj printf("That must be tomorrow\nCan't you wait till then?\n"); 2862373Swnj finish(); 2872373Swnj } 2888841Smckusick return (t1 + tim - t); 2892373Swnj badform: 2902373Swnj printf("Bad time format\n"); 2912373Swnj finish(); 2922373Swnj } 2932373Swnj 2948841Smckusick warn(term, sdt, now, type) 2952373Swnj FILE *term; 2968841Smckusick time_t sdt, now; 2978841Smckusick char *type; 2982373Swnj { 2992373Swnj char *ts; 3008841Smckusick register delay = sdt - now; 3012373Swnj 3023880Swnj if (delay > 8) 3033880Swnj while (delay % 5) 3043880Swnj delay++; 3053880Swnj 3063880Swnj if (shutter) 3073880Swnj fprintf(term, 308*13178Sroot "\007\007\t*** %sSystem shutdown message from %s@%s ***\r\n\n", 309*13178Sroot type, shutter, hostname); 3103880Swnj else 3113880Swnj fprintf(term, 3128841Smckusick "\007\007\t*** %sSystem shutdown message (%s) ***\r\n\n", 3138841Smckusick type, hostname); 3148841Smckusick 3152373Swnj ts = ctime(&sdt); 3168841Smckusick if (delay > 10 MINUTES) 3178841Smckusick fprintf(term, "System going down at %5.5s\r\n", ts+11); 3188841Smckusick else if (delay > 95 SECONDS) { 3198841Smckusick fprintf(term, "System going down in %d minute%s\r\n", 3208841Smckusick (delay+30)/60, (delay+30)/60 != 1 ? "s" : ""); 3218841Smckusick } else if (delay > 0) { 3228841Smckusick fprintf(term, "System going down in %d second%s\r\n", 3238841Smckusick delay, delay != 1 ? "s" : ""); 3242373Swnj } else 3258841Smckusick fprintf(term, "System going down IMMEDIATELY\r\n"); 3262373Swnj } 3272373Swnj 3282373Swnj nolog(sdt) 3298841Smckusick time_t sdt; 3302373Swnj { 3312373Swnj FILE *nologf; 3322373Swnj register char **mess; 3332373Swnj 3348841Smckusick unlink(nologin); /* in case linked to std file */ 3352373Swnj if ((nologf = fopen(nologin, "w")) != NULL) { 3362373Swnj fprintf(nologf, nolog1, (ctime(&sdt)) + 11); 3373880Swnj putc('\t', nologf); 3382373Swnj for (mess = nolog2; *mess; mess++) 3393880Swnj fprintf(nologf, " %s", *mess); 3403880Swnj putc('\n', nologf); 3412373Swnj fclose(nologf); 3422373Swnj } 3432373Swnj } 3442373Swnj 3452373Swnj finish() 3462373Swnj { 3472373Swnj signal(SIGTERM, SIG_IGN); 3482373Swnj unlink(nologin); 3492373Swnj exit(0); 3502373Swnj } 3512373Swnj 3522373Swnj do_nothing() 3532373Swnj { 3542373Swnj 3552373Swnj signal(SIGALRM, do_nothing); 3562373Swnj } 3572818Swnj 3582818Swnj /* 3592818Swnj * make an entry in the shutdown log 3602818Swnj */ 3612818Swnj 3623484Sroot char *days[] = { 3633484Sroot "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" 3643484Sroot }; 3653484Sroot 3663484Sroot char *months[] = { 3673484Sroot "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", 3683484Sroot "Oct", "Nov", "Dec" 3693484Sroot }; 3703484Sroot 3713484Sroot log_entry(now) 3728841Smckusick time_t now; 3732818Swnj { 3743484Sroot register FILE *fp; 3753484Sroot register char **mess; 3763484Sroot struct tm *tm, *localtime(); 3772818Swnj 3783484Sroot tm = localtime(&now); 3793484Sroot fp = fopen(LOGFILE, "a"); 3808841Smckusick if (fp == NULL) { 3818841Smckusick printf("Shutdown: log entry failed\n"); 3823578Sroot return; 3838841Smckusick } 3843484Sroot fseek(fp, 0L, 2); 3853484Sroot fprintf(fp, "%02d:%02d %s %s %2d, %4d. Shutdown:", tm->tm_hour, 3863484Sroot tm->tm_min, days[tm->tm_wday], months[tm->tm_mon], 3873484Sroot tm->tm_mday, tm->tm_year + 1900); 3882818Swnj for (mess = nolog2; *mess; mess++) 3893484Sroot fprintf(fp, " %s", *mess); 3903880Swnj if (shutter) 3918841Smckusick fprintf(fp, " (by %s!%s)", hostname, shutter); 3923484Sroot fputc('\n', fp); 3933484Sroot fclose(fp); 3942818Swnj } 395