1*12129Sedward static char *sccsid = "@(#)shutdown.c 4.16 (Berkeley) 83/04/29"; 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 */ 172818Swnj #ifdef DEBUG 182818Swnj #define LOGFILE "shutdown.log" 192818Swnj #else 202818Swnj #define LOGFILE "/usr/adm/shutdownlog" 212818Swnj #endif 222373Swnj #define REBOOT "/etc/reboot" 232373Swnj #define HALT "/etc/halt" 242373Swnj #define MAXINTS 20 252373Swnj #define HOURS *3600 262373Swnj #define MINUTES *60 272373Swnj #define SECONDS 283880Swnj #define NLOG 20 /* no of args possible for message */ 292373Swnj #define NOLOGTIME 5 MINUTES 303885Sroot #define IGNOREUSER "sleeper" 312373Swnj 326203Sroot char hostname[32]; 336203Sroot 342373Swnj int do_nothing(); 352373Swnj time_t getsdt(); 362373Swnj 372373Swnj extern char *ctime(); 382373Swnj extern struct tm *localtime(); 392373Swnj 402373Swnj struct utmp utmp; 412373Swnj int sint; 422373Swnj int stogo; 432373Swnj char tpath[] = "/dev/"; 442373Swnj int nlflag = 1; /* nolog yet to be done */ 452373Swnj int killflg = 1; 462373Swnj int reboot = 0; 472373Swnj int halt = 0; 482373Swnj char term[sizeof tpath + sizeof utmp.ut_line]; 492373Swnj char tbuf[BUFSIZ]; 502373Swnj char nolog1[] = "\n\nNO LOGINS: System going down at %5.5s\n\n"; 512373Swnj char *nolog2[NLOG+1]; 522373Swnj #ifdef DEBUG 532373Swnj char nologin[] = "nologin"; 542373Swnj #else 552373Swnj char nologin[] = "/etc/nologin"; 562373Swnj #endif 578841Smckusick time_t nowtime; 588841Smckusick 592373Swnj struct interval { 602373Swnj int stogo; 612373Swnj int sint; 622373Swnj } interval[] = { 632373Swnj 4 HOURS, 1 HOURS, 642373Swnj 2 HOURS, 30 MINUTES, 652373Swnj 1 HOURS, 15 MINUTES, 662373Swnj 30 MINUTES, 10 MINUTES, 672373Swnj 15 MINUTES, 5 MINUTES, 682818Swnj 10 MINUTES, 5 MINUTES, 692818Swnj 5 MINUTES, 3 MINUTES, 708841Smckusick 2 MINUTES, 1 MINUTES, 718841Smckusick 1 MINUTES, 30 SECONDS, 722373Swnj 0 SECONDS, 0 SECONDS 732373Swnj }; 748841Smckusick 752818Swnj char *shutter, *getlogin(); 768841Smckusick 772373Swnj main(argc,argv) 782373Swnj int argc; 792373Swnj char **argv; 802373Swnj { 812373Swnj register i, ufd; 822373Swnj register char **mess, *f; 832373Swnj char *ts; 848841Smckusick time_t sdt; 852373Swnj int h, m; 868841Smckusick int first; 872373Swnj FILE *termf; 882373Swnj 892818Swnj shutter = getlogin(); 906203Sroot gethostname(hostname, sizeof (hostname)); 912373Swnj argc--, argv++; 922373Swnj while (argc > 0 && (f = argv[0], *f++ == '-')) { 932373Swnj while (i = *f++) switch (i) { 942373Swnj case 'k': 952373Swnj killflg = 0; 962373Swnj continue; 972373Swnj case 'r': 982373Swnj reboot = 1; 992373Swnj continue; 1002373Swnj case 'h': 1012373Swnj halt = 1; 1022373Swnj continue; 1032373Swnj default: 1042373Swnj fprintf(stderr, "shutdown: '%c' - unknown flag\n", i); 1052373Swnj exit(1); 1062373Swnj } 1072373Swnj argc--, argv++; 1082373Swnj } 1092373Swnj if (argc < 1) { 1103880Swnj printf("Usage: %s [ -krh ] shutdowntime [ message ]\n", 1112373Swnj argv[0]); 1122373Swnj finish(); 1132373Swnj } 1143720Sroot if (geteuid()) { 1153720Sroot fprintf(stderr, "NOT super-user\n"); 1163648Stoy finish(); 1173648Stoy } 1188841Smckusick nowtime = time((time_t *)0); 1192373Swnj sdt = getsdt(argv[0]); 1202373Swnj argc--, argv++; 1212373Swnj i = 0; 1222373Swnj while (argc-- > 0) 1232373Swnj if (i < NLOG) 1242373Swnj nolog2[i++] = *argv++; 1252373Swnj nolog2[i] = NULL; 1262373Swnj m = ((stogo = sdt - nowtime) + 30)/60; 1272373Swnj h = m/60; 1282373Swnj m %= 60; 1292373Swnj ts = ctime(&sdt); 1302818Swnj printf("Shutdown at %5.5s (in ", ts+11); 1312373Swnj if (h > 0) 1322373Swnj printf("%d hour%s ", h, h != 1 ? "s" : ""); 1332818Swnj printf("%d minute%s) ", m, m != 1 ? "s" : ""); 1342373Swnj #ifndef DEBUG 1352373Swnj signal(SIGHUP, SIG_IGN); 1362373Swnj signal(SIGQUIT, SIG_IGN); 1372373Swnj signal(SIGINT, SIG_IGN); 1382373Swnj #endif 139*12129Sedward signal(SIGTTOU, SIG_IGN); 1402373Swnj signal(SIGTERM, finish); 1412373Swnj signal(SIGALRM, do_nothing); 1422373Swnj nice(-20); 1433880Swnj fflush(stdout); 1442818Swnj #ifndef DEBUG 1452373Swnj if (i = fork()) { 1462818Swnj printf("[pid %d]\n", i); 1472373Swnj exit(0); 1482373Swnj } 1498841Smckusick #else 1508841Smckusick putc('\n', stdout); 1512818Swnj #endif 1522373Swnj sint = 1 HOURS; 1532373Swnj f = ""; 1548841Smckusick ufd = open("/etc/utmp",0); 1558841Smckusick if (ufd < 0) { 1568841Smckusick perror("shutdown: /etc/utmp"); 1578841Smckusick exit(1); 1588841Smckusick } 1598841Smckusick first = 1; 1602373Swnj for (;;) { 1612373Swnj for (i = 0; stogo <= interval[i].stogo && interval[i].sint; i++) 1622373Swnj sint = interval[i].sint; 1638841Smckusick if (stogo > 0 && (stogo-sint) < interval[i].stogo) 1648841Smckusick sint = stogo - interval[i].stogo; 1652373Swnj if (stogo <= NOLOGTIME && nlflag) { 1662373Swnj nlflag = 0; 1672373Swnj nolog(sdt); 1682373Swnj } 1692373Swnj if (sint >= stogo || sint == 0) 1702373Swnj f = "FINAL "; 1718841Smckusick nowtime = time((time_t *) 0); 1728841Smckusick lseek(ufd, 0L, 0); 1732373Swnj while (read(ufd,&utmp,sizeof utmp)==sizeof utmp) 1743885Sroot if (utmp.ut_name[0] && 1753885Sroot strncmp(utmp.ut_name, IGNOREUSER, sizeof(utmp.ut_name))) { 1762373Swnj strcpy(term, tpath); 1772373Swnj strncat(term, utmp.ut_line, sizeof utmp.ut_line); 1782373Swnj alarm(3); 1792373Swnj #ifdef DEBUG 1802818Swnj if ((termf = stdout) != NULL) 1812373Swnj #else 1822373Swnj if ((termf = fopen(term, "w")) != NULL) 1832373Swnj #endif 1842373Swnj { 1852373Swnj alarm(0); 1862373Swnj setbuf(termf, tbuf); 1878841Smckusick fprintf(termf, "\n\r\n"); 1888841Smckusick warn(termf, sdt, nowtime, f); 1898841Smckusick if (first || sdt - nowtime > 1 MINUTES) { 1908841Smckusick if (*nolog2) 1918841Smckusick fprintf(termf, "\t..."); 1922373Swnj for (mess = nolog2; *mess; mess++) 1938841Smckusick fprintf(termf, " %s", *mess); 1948841Smckusick } 1958841Smckusick fputc('\r', termf); 1962373Swnj fputc('\n', termf); 1972818Swnj alarm(5); 1982818Swnj #ifdef DEBUG 1992818Swnj fflush(termf); 2002818Swnj #else 2012373Swnj fclose(termf); 2022818Swnj #endif 2032373Swnj alarm(0); 2042373Swnj } 2052373Swnj } 2068841Smckusick if (stogo <= 0) { 2072373Swnj printf("\n\007\007System shutdown time has arrived\007\007\n"); 2082818Swnj log_entry(sdt); 2092373Swnj unlink(nologin); 2102373Swnj if (!killflg) { 2112373Swnj printf("but you'll have to do it yourself\n"); 2122373Swnj finish(); 2132373Swnj } 2142373Swnj #ifndef DEBUG 2158841Smckusick kill(-1, SIGTERM); /* terminate everyone */ 2168841Smckusick sleep(5); /* & wait while they die */ 2172373Swnj if (reboot) 2182373Swnj execle(REBOOT, "reboot", 0, 0); 2192373Swnj if (halt) 2202373Swnj execle(HALT, "halt", 0, 0); 2212373Swnj kill(1, SIGTERM); /* sync */ 2222373Swnj kill(1, SIGTERM); /* sync */ 2232373Swnj sleep(20); 2242373Swnj #else 2252373Swnj printf("EXTERMINATE EXTERMINATE\n"); 2262373Swnj #endif 2272373Swnj finish(); 2282373Swnj } 2298841Smckusick stogo = sdt - time((time_t *) 0); 2308841Smckusick if (stogo > 0 && sint > 0) 2312373Swnj sleep(sint<stogo ? sint : stogo); 2322373Swnj stogo -= sint; 2338841Smckusick first = 0; 2342373Swnj } 2352373Swnj } 2362373Swnj 2372373Swnj time_t 2382373Swnj getsdt(s) 2398841Smckusick register char *s; 2402373Swnj { 2412373Swnj time_t t, t1, tim; 2422373Swnj register char c; 2432373Swnj struct tm *lt; 2442373Swnj 2458841Smckusick if (strcmp(s, "now") == 0) 2468841Smckusick return(nowtime); 2472373Swnj if (*s == '+') { 2482373Swnj ++s; 2492373Swnj t = 0; 2502373Swnj for (;;) { 2512373Swnj c = *s++; 2522373Swnj if (!isdigit(c)) 2532373Swnj break; 2542373Swnj t = t * 10 + c - '0'; 2552373Swnj } 2562373Swnj if (t <= 0) 2572373Swnj t = 5; 2582373Swnj t *= 60; 2598841Smckusick tim = time((time_t *) 0) + t; 2602373Swnj return(tim); 2612373Swnj } 2622373Swnj t = 0; 2632373Swnj while (strlen(s) > 2 && isdigit(*s)) 2642373Swnj t = t * 10 + *s++ - '0'; 2652373Swnj if (*s == ':') 2662373Swnj s++; 2672373Swnj if (t > 23) 2682373Swnj goto badform; 2692373Swnj tim = t*60; 2702373Swnj t = 0; 2712373Swnj while (isdigit(*s)) 2722373Swnj t = t * 10 + *s++ - '0'; 2732373Swnj if (t > 59) 2742373Swnj goto badform; 2752373Swnj tim += t; 2762373Swnj tim *= 60; 2778841Smckusick t1 = time((time_t *) 0); 2782373Swnj lt = localtime(&t1); 2792373Swnj t = lt->tm_sec + lt->tm_min*60 + lt->tm_hour*3600; 2802373Swnj if (tim < t || tim >= (24*3600)) { 2812373Swnj /* before now or after midnight */ 2822373Swnj printf("That must be tomorrow\nCan't you wait till then?\n"); 2832373Swnj finish(); 2842373Swnj } 2858841Smckusick return (t1 + tim - t); 2862373Swnj badform: 2872373Swnj printf("Bad time format\n"); 2882373Swnj finish(); 2892373Swnj } 2902373Swnj 2918841Smckusick warn(term, sdt, now, type) 2922373Swnj FILE *term; 2938841Smckusick time_t sdt, now; 2948841Smckusick char *type; 2952373Swnj { 2962373Swnj char *ts; 2978841Smckusick register delay = sdt - now; 2982373Swnj 2993880Swnj if (delay > 8) 3003880Swnj while (delay % 5) 3013880Swnj delay++; 3023880Swnj 3033880Swnj if (shutter) 3043880Swnj fprintf(term, 3058841Smckusick "\007\007\t*** %sSystem shutdown message from %s!%s ***\r\n\n", 3068841Smckusick type, hostname, shutter); 3073880Swnj else 3083880Swnj fprintf(term, 3098841Smckusick "\007\007\t*** %sSystem shutdown message (%s) ***\r\n\n", 3108841Smckusick type, hostname); 3118841Smckusick 3122373Swnj ts = ctime(&sdt); 3138841Smckusick if (delay > 10 MINUTES) 3148841Smckusick fprintf(term, "System going down at %5.5s\r\n", ts+11); 3158841Smckusick else if (delay > 95 SECONDS) { 3168841Smckusick fprintf(term, "System going down in %d minute%s\r\n", 3178841Smckusick (delay+30)/60, (delay+30)/60 != 1 ? "s" : ""); 3188841Smckusick } else if (delay > 0) { 3198841Smckusick fprintf(term, "System going down in %d second%s\r\n", 3208841Smckusick delay, delay != 1 ? "s" : ""); 3212373Swnj } else 3228841Smckusick fprintf(term, "System going down IMMEDIATELY\r\n"); 3232373Swnj } 3242373Swnj 3252373Swnj nolog(sdt) 3268841Smckusick time_t sdt; 3272373Swnj { 3282373Swnj FILE *nologf; 3292373Swnj register char **mess; 3302373Swnj 3318841Smckusick unlink(nologin); /* in case linked to std file */ 3322373Swnj if ((nologf = fopen(nologin, "w")) != NULL) { 3332373Swnj fprintf(nologf, nolog1, (ctime(&sdt)) + 11); 3343880Swnj putc('\t', nologf); 3352373Swnj for (mess = nolog2; *mess; mess++) 3363880Swnj fprintf(nologf, " %s", *mess); 3373880Swnj putc('\n', nologf); 3382373Swnj fclose(nologf); 3392373Swnj } 3402373Swnj } 3412373Swnj 3422373Swnj finish() 3432373Swnj { 3442373Swnj signal(SIGTERM, SIG_IGN); 3452373Swnj unlink(nologin); 3462373Swnj exit(0); 3472373Swnj } 3482373Swnj 3492373Swnj do_nothing() 3502373Swnj { 3512373Swnj 3522373Swnj signal(SIGALRM, do_nothing); 3532373Swnj } 3542818Swnj 3552818Swnj /* 3562818Swnj * make an entry in the shutdown log 3572818Swnj */ 3582818Swnj 3593484Sroot char *days[] = { 3603484Sroot "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" 3613484Sroot }; 3623484Sroot 3633484Sroot char *months[] = { 3643484Sroot "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", 3653484Sroot "Oct", "Nov", "Dec" 3663484Sroot }; 3673484Sroot 3683484Sroot log_entry(now) 3698841Smckusick time_t now; 3702818Swnj { 3713484Sroot register FILE *fp; 3723484Sroot register char **mess; 3733484Sroot struct tm *tm, *localtime(); 3742818Swnj 3753484Sroot tm = localtime(&now); 3763484Sroot fp = fopen(LOGFILE, "a"); 3778841Smckusick if (fp == NULL) { 3788841Smckusick printf("Shutdown: log entry failed\n"); 3793578Sroot return; 3808841Smckusick } 3813484Sroot fseek(fp, 0L, 2); 3823484Sroot fprintf(fp, "%02d:%02d %s %s %2d, %4d. Shutdown:", tm->tm_hour, 3833484Sroot tm->tm_min, days[tm->tm_wday], months[tm->tm_mon], 3843484Sroot tm->tm_mday, tm->tm_year + 1900); 3852818Swnj for (mess = nolog2; *mess; mess++) 3863484Sroot fprintf(fp, " %s", *mess); 3873880Swnj if (shutter) 3888841Smckusick fprintf(fp, " (by %s!%s)", hostname, shutter); 3893484Sroot fputc('\n', fp); 3903484Sroot fclose(fp); 3912818Swnj } 392