112682Ssam #ifndef lint 2*15920Skarels static char *sccsid = "@(#)shutdown.c 4.20 (Berkeley) 84/02/02"; 312682Ssam #endif 42373Swnj 52373Swnj #include <stdio.h> 62373Swnj #include <ctype.h> 72373Swnj #include <signal.h> 8*15920Skarels #include <setjmp.h> 92373Swnj #include <utmp.h> 1012897Ssam #include <sys/time.h> 1112897Ssam #include <sys/resource.h> 122373Swnj #include <sys/types.h> 132373Swnj /* 142373Swnj * /etc/shutdown when [messages] 152373Swnj * 162373Swnj * allow super users to tell users and remind users 172373Swnj * of iminent shutdown of unix 182373Swnj * and shut it down automatically 192373Swnj * and even reboot or halt the machine if they desire 202373Swnj */ 212818Swnj #ifdef DEBUG 222818Swnj #define LOGFILE "shutdown.log" 232818Swnj #else 242818Swnj #define LOGFILE "/usr/adm/shutdownlog" 252818Swnj #endif 262373Swnj #define REBOOT "/etc/reboot" 272373Swnj #define HALT "/etc/halt" 282373Swnj #define MAXINTS 20 292373Swnj #define HOURS *3600 302373Swnj #define MINUTES *60 312373Swnj #define SECONDS 323880Swnj #define NLOG 20 /* no of args possible for message */ 332373Swnj #define NOLOGTIME 5 MINUTES 343885Sroot #define IGNOREUSER "sleeper" 352373Swnj 366203Sroot char hostname[32]; 376203Sroot 38*15920Skarels int timeout(); 392373Swnj time_t getsdt(); 402373Swnj 412373Swnj extern char *ctime(); 422373Swnj extern struct tm *localtime(); 432373Swnj 442373Swnj struct utmp utmp; 452373Swnj int sint; 462373Swnj int stogo; 472373Swnj char tpath[] = "/dev/"; 482373Swnj int nlflag = 1; /* nolog yet to be done */ 492373Swnj int killflg = 1; 502373Swnj int reboot = 0; 512373Swnj int halt = 0; 522373Swnj char term[sizeof tpath + sizeof utmp.ut_line]; 532373Swnj char tbuf[BUFSIZ]; 542373Swnj char nolog1[] = "\n\nNO LOGINS: System going down at %5.5s\n\n"; 552373Swnj char *nolog2[NLOG+1]; 562373Swnj #ifdef DEBUG 572373Swnj char nologin[] = "nologin"; 582373Swnj #else 592373Swnj char nologin[] = "/etc/nologin"; 602373Swnj #endif 618841Smckusick time_t nowtime; 62*15920Skarels jmp_buf alarmbuf; 638841Smckusick 642373Swnj struct interval { 652373Swnj int stogo; 662373Swnj int sint; 672373Swnj } interval[] = { 682373Swnj 4 HOURS, 1 HOURS, 692373Swnj 2 HOURS, 30 MINUTES, 702373Swnj 1 HOURS, 15 MINUTES, 712373Swnj 30 MINUTES, 10 MINUTES, 722373Swnj 15 MINUTES, 5 MINUTES, 732818Swnj 10 MINUTES, 5 MINUTES, 742818Swnj 5 MINUTES, 3 MINUTES, 758841Smckusick 2 MINUTES, 1 MINUTES, 768841Smckusick 1 MINUTES, 30 SECONDS, 772373Swnj 0 SECONDS, 0 SECONDS 782373Swnj }; 798841Smckusick 802818Swnj char *shutter, *getlogin(); 818841Smckusick 822373Swnj main(argc,argv) 832373Swnj int argc; 842373Swnj char **argv; 852373Swnj { 862373Swnj register i, ufd; 872373Swnj register char **mess, *f; 882373Swnj char *ts; 898841Smckusick time_t sdt; 902373Swnj int h, m; 918841Smckusick int first; 922373Swnj FILE *termf; 932373Swnj 942818Swnj shutter = getlogin(); 956203Sroot gethostname(hostname, sizeof (hostname)); 962373Swnj argc--, argv++; 972373Swnj while (argc > 0 && (f = argv[0], *f++ == '-')) { 982373Swnj while (i = *f++) switch (i) { 992373Swnj case 'k': 1002373Swnj killflg = 0; 1012373Swnj continue; 1022373Swnj case 'r': 1032373Swnj reboot = 1; 1042373Swnj continue; 1052373Swnj case 'h': 1062373Swnj halt = 1; 1072373Swnj continue; 1082373Swnj default: 1092373Swnj fprintf(stderr, "shutdown: '%c' - unknown flag\n", i); 1102373Swnj exit(1); 1112373Swnj } 1122373Swnj argc--, argv++; 1132373Swnj } 1142373Swnj if (argc < 1) { 1153880Swnj printf("Usage: %s [ -krh ] shutdowntime [ message ]\n", 1162373Swnj argv[0]); 1172373Swnj finish(); 1182373Swnj } 1193720Sroot if (geteuid()) { 1203720Sroot fprintf(stderr, "NOT super-user\n"); 1213648Stoy finish(); 1223648Stoy } 1238841Smckusick nowtime = time((time_t *)0); 1242373Swnj sdt = getsdt(argv[0]); 1252373Swnj argc--, argv++; 1262373Swnj i = 0; 1272373Swnj while (argc-- > 0) 1282373Swnj if (i < NLOG) 1292373Swnj nolog2[i++] = *argv++; 1302373Swnj nolog2[i] = NULL; 1312373Swnj m = ((stogo = sdt - nowtime) + 30)/60; 1322373Swnj h = m/60; 1332373Swnj m %= 60; 1342373Swnj ts = ctime(&sdt); 1352818Swnj printf("Shutdown at %5.5s (in ", ts+11); 1362373Swnj if (h > 0) 1372373Swnj printf("%d hour%s ", h, h != 1 ? "s" : ""); 1382818Swnj printf("%d minute%s) ", m, m != 1 ? "s" : ""); 1392373Swnj #ifndef DEBUG 1402373Swnj signal(SIGHUP, SIG_IGN); 1412373Swnj signal(SIGQUIT, SIG_IGN); 1422373Swnj signal(SIGINT, SIG_IGN); 1432373Swnj #endif 14412129Sedward signal(SIGTTOU, SIG_IGN); 1452373Swnj signal(SIGTERM, finish); 146*15920Skarels signal(SIGALRM, timeout); 14712897Ssam setpriority(PRIO_PROCESS, 0, PRIO_MIN); 1483880Swnj fflush(stdout); 1492818Swnj #ifndef DEBUG 1502373Swnj if (i = fork()) { 1512818Swnj printf("[pid %d]\n", i); 1522373Swnj exit(0); 1532373Swnj } 1548841Smckusick #else 1558841Smckusick putc('\n', stdout); 1562818Swnj #endif 1572373Swnj sint = 1 HOURS; 1582373Swnj f = ""; 1598841Smckusick ufd = open("/etc/utmp",0); 1608841Smckusick if (ufd < 0) { 1618841Smckusick perror("shutdown: /etc/utmp"); 1628841Smckusick exit(1); 1638841Smckusick } 1648841Smckusick first = 1; 1652373Swnj for (;;) { 1662373Swnj for (i = 0; stogo <= interval[i].stogo && interval[i].sint; i++) 1672373Swnj sint = interval[i].sint; 1688841Smckusick if (stogo > 0 && (stogo-sint) < interval[i].stogo) 1698841Smckusick sint = stogo - interval[i].stogo; 1702373Swnj if (stogo <= NOLOGTIME && nlflag) { 1712373Swnj nlflag = 0; 1722373Swnj nolog(sdt); 1732373Swnj } 1742373Swnj if (sint >= stogo || sint == 0) 1752373Swnj f = "FINAL "; 1768841Smckusick nowtime = time((time_t *) 0); 1778841Smckusick lseek(ufd, 0L, 0); 1782373Swnj while (read(ufd,&utmp,sizeof utmp)==sizeof utmp) 1793885Sroot if (utmp.ut_name[0] && 1803885Sroot strncmp(utmp.ut_name, IGNOREUSER, sizeof(utmp.ut_name))) { 181*15920Skarels if (setjmp(alarmbuf)) 182*15920Skarels continue; 1832373Swnj strcpy(term, tpath); 1842373Swnj strncat(term, utmp.ut_line, sizeof utmp.ut_line); 1852373Swnj alarm(3); 1862373Swnj #ifdef DEBUG 1872818Swnj if ((termf = stdout) != NULL) 1882373Swnj #else 1892373Swnj if ((termf = fopen(term, "w")) != NULL) 1902373Swnj #endif 1912373Swnj { 1922373Swnj alarm(0); 1932373Swnj setbuf(termf, tbuf); 1948841Smckusick fprintf(termf, "\n\r\n"); 1958841Smckusick warn(termf, sdt, nowtime, f); 1968841Smckusick if (first || sdt - nowtime > 1 MINUTES) { 1978841Smckusick if (*nolog2) 1988841Smckusick fprintf(termf, "\t..."); 1992373Swnj for (mess = nolog2; *mess; mess++) 2008841Smckusick fprintf(termf, " %s", *mess); 2018841Smckusick } 2028841Smckusick fputc('\r', termf); 2032373Swnj fputc('\n', termf); 2042818Swnj alarm(5); 2052818Swnj #ifdef DEBUG 2062818Swnj fflush(termf); 2072818Swnj #else 2082373Swnj fclose(termf); 2092818Swnj #endif 2102373Swnj alarm(0); 2112373Swnj } 2122373Swnj } 2138841Smckusick if (stogo <= 0) { 2142373Swnj printf("\n\007\007System shutdown time has arrived\007\007\n"); 2152818Swnj log_entry(sdt); 2162373Swnj unlink(nologin); 2172373Swnj if (!killflg) { 2182373Swnj printf("but you'll have to do it yourself\n"); 2192373Swnj finish(); 2202373Swnj } 2212373Swnj #ifndef DEBUG 2228841Smckusick kill(-1, SIGTERM); /* terminate everyone */ 2238841Smckusick sleep(5); /* & wait while they die */ 2242373Swnj if (reboot) 2252373Swnj execle(REBOOT, "reboot", 0, 0); 2262373Swnj if (halt) 2272373Swnj execle(HALT, "halt", 0, 0); 2282373Swnj kill(1, SIGTERM); /* sync */ 2292373Swnj kill(1, SIGTERM); /* sync */ 2302373Swnj sleep(20); 2312373Swnj #else 2322373Swnj printf("EXTERMINATE EXTERMINATE\n"); 2332373Swnj #endif 2342373Swnj finish(); 2352373Swnj } 2368841Smckusick stogo = sdt - time((time_t *) 0); 2378841Smckusick if (stogo > 0 && sint > 0) 2382373Swnj sleep(sint<stogo ? sint : stogo); 2392373Swnj stogo -= sint; 2408841Smckusick first = 0; 2412373Swnj } 2422373Swnj } 2432373Swnj 2442373Swnj time_t 2452373Swnj getsdt(s) 2468841Smckusick register char *s; 2472373Swnj { 2482373Swnj time_t t, t1, tim; 2492373Swnj register char c; 2502373Swnj struct tm *lt; 2512373Swnj 2528841Smckusick if (strcmp(s, "now") == 0) 2538841Smckusick return(nowtime); 2542373Swnj if (*s == '+') { 2552373Swnj ++s; 2562373Swnj t = 0; 2572373Swnj for (;;) { 2582373Swnj c = *s++; 2592373Swnj if (!isdigit(c)) 2602373Swnj break; 2612373Swnj t = t * 10 + c - '0'; 2622373Swnj } 2632373Swnj if (t <= 0) 2642373Swnj t = 5; 2652373Swnj t *= 60; 2668841Smckusick tim = time((time_t *) 0) + t; 2672373Swnj return(tim); 2682373Swnj } 2692373Swnj t = 0; 2702373Swnj while (strlen(s) > 2 && isdigit(*s)) 2712373Swnj t = t * 10 + *s++ - '0'; 2722373Swnj if (*s == ':') 2732373Swnj s++; 2742373Swnj if (t > 23) 2752373Swnj goto badform; 2762373Swnj tim = t*60; 2772373Swnj t = 0; 2782373Swnj while (isdigit(*s)) 2792373Swnj t = t * 10 + *s++ - '0'; 2802373Swnj if (t > 59) 2812373Swnj goto badform; 2822373Swnj tim += t; 2832373Swnj tim *= 60; 2848841Smckusick t1 = time((time_t *) 0); 2852373Swnj lt = localtime(&t1); 2862373Swnj t = lt->tm_sec + lt->tm_min*60 + lt->tm_hour*3600; 2872373Swnj if (tim < t || tim >= (24*3600)) { 2882373Swnj /* before now or after midnight */ 2892373Swnj printf("That must be tomorrow\nCan't you wait till then?\n"); 2902373Swnj finish(); 2912373Swnj } 2928841Smckusick return (t1 + tim - t); 2932373Swnj badform: 2942373Swnj printf("Bad time format\n"); 2952373Swnj finish(); 2962373Swnj } 2972373Swnj 2988841Smckusick warn(term, sdt, now, type) 2992373Swnj FILE *term; 3008841Smckusick time_t sdt, now; 3018841Smckusick char *type; 3022373Swnj { 3032373Swnj char *ts; 3048841Smckusick register delay = sdt - now; 3052373Swnj 3063880Swnj if (delay > 8) 3073880Swnj while (delay % 5) 3083880Swnj delay++; 3093880Swnj 3103880Swnj if (shutter) 3113880Swnj fprintf(term, 31213178Sroot "\007\007\t*** %sSystem shutdown message from %s@%s ***\r\n\n", 31313178Sroot type, shutter, hostname); 3143880Swnj else 3153880Swnj fprintf(term, 3168841Smckusick "\007\007\t*** %sSystem shutdown message (%s) ***\r\n\n", 3178841Smckusick type, hostname); 3188841Smckusick 3192373Swnj ts = ctime(&sdt); 3208841Smckusick if (delay > 10 MINUTES) 3218841Smckusick fprintf(term, "System going down at %5.5s\r\n", ts+11); 3228841Smckusick else if (delay > 95 SECONDS) { 3238841Smckusick fprintf(term, "System going down in %d minute%s\r\n", 3248841Smckusick (delay+30)/60, (delay+30)/60 != 1 ? "s" : ""); 3258841Smckusick } else if (delay > 0) { 3268841Smckusick fprintf(term, "System going down in %d second%s\r\n", 3278841Smckusick delay, delay != 1 ? "s" : ""); 3282373Swnj } else 3298841Smckusick fprintf(term, "System going down IMMEDIATELY\r\n"); 3302373Swnj } 3312373Swnj 3322373Swnj nolog(sdt) 3338841Smckusick time_t sdt; 3342373Swnj { 3352373Swnj FILE *nologf; 3362373Swnj register char **mess; 3372373Swnj 3388841Smckusick unlink(nologin); /* in case linked to std file */ 3392373Swnj if ((nologf = fopen(nologin, "w")) != NULL) { 3402373Swnj fprintf(nologf, nolog1, (ctime(&sdt)) + 11); 3413880Swnj putc('\t', nologf); 3422373Swnj for (mess = nolog2; *mess; mess++) 3433880Swnj fprintf(nologf, " %s", *mess); 3443880Swnj putc('\n', nologf); 3452373Swnj fclose(nologf); 3462373Swnj } 3472373Swnj } 3482373Swnj 3492373Swnj finish() 3502373Swnj { 3512373Swnj signal(SIGTERM, SIG_IGN); 3522373Swnj unlink(nologin); 3532373Swnj exit(0); 3542373Swnj } 3552373Swnj 356*15920Skarels timeout() 3572373Swnj { 358*15920Skarels longjmp(alarmbuf, 1); 3592373Swnj } 3602818Swnj 3612818Swnj /* 3622818Swnj * make an entry in the shutdown log 3632818Swnj */ 3642818Swnj 3653484Sroot char *days[] = { 3663484Sroot "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" 3673484Sroot }; 3683484Sroot 3693484Sroot char *months[] = { 3703484Sroot "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", 3713484Sroot "Oct", "Nov", "Dec" 3723484Sroot }; 3733484Sroot 3743484Sroot log_entry(now) 3758841Smckusick time_t now; 3762818Swnj { 3773484Sroot register FILE *fp; 3783484Sroot register char **mess; 3793484Sroot struct tm *tm, *localtime(); 3802818Swnj 3813484Sroot tm = localtime(&now); 3823484Sroot fp = fopen(LOGFILE, "a"); 3838841Smckusick if (fp == NULL) { 3848841Smckusick printf("Shutdown: log entry failed\n"); 3853578Sroot return; 3868841Smckusick } 3873484Sroot fseek(fp, 0L, 2); 3883484Sroot fprintf(fp, "%02d:%02d %s %s %2d, %4d. Shutdown:", tm->tm_hour, 3893484Sroot tm->tm_min, days[tm->tm_wday], months[tm->tm_mon], 3903484Sroot tm->tm_mday, tm->tm_year + 1900); 3912818Swnj for (mess = nolog2; *mess; mess++) 3923484Sroot fprintf(fp, " %s", *mess); 3933880Swnj if (shutter) 3948841Smckusick fprintf(fp, " (by %s!%s)", hostname, shutter); 3953484Sroot fputc('\n', fp); 3963484Sroot fclose(fp); 3972818Swnj } 398