1*8841Smckusick static char *sccsid = "@(#)shutdown.c 4.14 (Berkeley) 82/10/23"; 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 223885Sroot * Dave Presotto, Berkeley, 1981 232373Swnj */ 242818Swnj #ifdef DEBUG 252818Swnj #define LOGFILE "shutdown.log" 262818Swnj #else 272818Swnj #define LOGFILE "/usr/adm/shutdownlog" 282818Swnj #endif 292373Swnj #define REBOOT "/etc/reboot" 302373Swnj #define HALT "/etc/halt" 312373Swnj #define MAXINTS 20 322373Swnj #define HOURS *3600 332373Swnj #define MINUTES *60 342373Swnj #define SECONDS 353880Swnj #define NLOG 20 /* no of args possible for message */ 362373Swnj #define NOLOGTIME 5 MINUTES 373885Sroot #define IGNOREUSER "sleeper" 382373Swnj 396203Sroot char hostname[32]; 406203Sroot 412373Swnj int do_nothing(); 422373Swnj time_t getsdt(); 432373Swnj 442373Swnj extern char *ctime(); 452373Swnj extern struct tm *localtime(); 462373Swnj 472373Swnj struct utmp utmp; 482373Swnj int sint; 492373Swnj int stogo; 502373Swnj char tpath[] = "/dev/"; 512373Swnj int nlflag = 1; /* nolog yet to be done */ 522373Swnj int killflg = 1; 532373Swnj int reboot = 0; 542373Swnj int halt = 0; 552373Swnj char term[sizeof tpath + sizeof utmp.ut_line]; 562373Swnj char tbuf[BUFSIZ]; 572373Swnj char nolog1[] = "\n\nNO LOGINS: System going down at %5.5s\n\n"; 582373Swnj char *nolog2[NLOG+1]; 592373Swnj #ifdef DEBUG 602373Swnj char nologin[] = "nologin"; 612373Swnj #else 622373Swnj char nologin[] = "/etc/nologin"; 632373Swnj #endif 64*8841Smckusick time_t nowtime; 65*8841Smckusick 662373Swnj struct interval { 672373Swnj int stogo; 682373Swnj int sint; 692373Swnj } interval[] = { 702373Swnj 4 HOURS, 1 HOURS, 712373Swnj 2 HOURS, 30 MINUTES, 722373Swnj 1 HOURS, 15 MINUTES, 732373Swnj 30 MINUTES, 10 MINUTES, 742373Swnj 15 MINUTES, 5 MINUTES, 752818Swnj 10 MINUTES, 5 MINUTES, 762818Swnj 5 MINUTES, 3 MINUTES, 77*8841Smckusick 2 MINUTES, 1 MINUTES, 78*8841Smckusick 1 MINUTES, 30 SECONDS, 792373Swnj 0 SECONDS, 0 SECONDS 802373Swnj }; 81*8841Smckusick 822818Swnj char *shutter, *getlogin(); 83*8841Smckusick 842373Swnj main(argc,argv) 852373Swnj int argc; 862373Swnj char **argv; 872373Swnj { 882373Swnj register i, ufd; 892373Swnj register char **mess, *f; 902373Swnj char *ts; 91*8841Smckusick time_t sdt; 922373Swnj int h, m; 93*8841Smckusick int first; 942373Swnj FILE *termf; 952373Swnj 962818Swnj shutter = getlogin(); 976203Sroot gethostname(hostname, sizeof (hostname)); 982373Swnj argc--, argv++; 992373Swnj while (argc > 0 && (f = argv[0], *f++ == '-')) { 1002373Swnj while (i = *f++) switch (i) { 1012373Swnj case 'k': 1022373Swnj killflg = 0; 1032373Swnj continue; 1042373Swnj case 'r': 1052373Swnj reboot = 1; 1062373Swnj continue; 1072373Swnj case 'h': 1082373Swnj halt = 1; 1092373Swnj continue; 1102373Swnj default: 1112373Swnj fprintf(stderr, "shutdown: '%c' - unknown flag\n", i); 1122373Swnj exit(1); 1132373Swnj } 1142373Swnj argc--, argv++; 1152373Swnj } 1162373Swnj if (argc < 1) { 1173880Swnj printf("Usage: %s [ -krh ] shutdowntime [ message ]\n", 1182373Swnj argv[0]); 1192373Swnj finish(); 1202373Swnj } 1213720Sroot if (geteuid()) { 1223720Sroot fprintf(stderr, "NOT super-user\n"); 1233648Stoy finish(); 1243648Stoy } 125*8841Smckusick nowtime = time((time_t *)0); 1262373Swnj sdt = getsdt(argv[0]); 1272373Swnj argc--, argv++; 1282373Swnj i = 0; 1292373Swnj while (argc-- > 0) 1302373Swnj if (i < NLOG) 1312373Swnj nolog2[i++] = *argv++; 1322373Swnj nolog2[i] = NULL; 1332373Swnj m = ((stogo = sdt - nowtime) + 30)/60; 1342373Swnj h = m/60; 1352373Swnj m %= 60; 1362373Swnj ts = ctime(&sdt); 1372818Swnj printf("Shutdown at %5.5s (in ", ts+11); 1382373Swnj if (h > 0) 1392373Swnj printf("%d hour%s ", h, h != 1 ? "s" : ""); 1402818Swnj printf("%d minute%s) ", m, m != 1 ? "s" : ""); 1412373Swnj #ifndef DEBUG 1422373Swnj signal(SIGHUP, SIG_IGN); 1432373Swnj signal(SIGQUIT, SIG_IGN); 1442373Swnj signal(SIGINT, SIG_IGN); 1452373Swnj #endif 1462373Swnj signal(SIGTERM, finish); 1472373Swnj signal(SIGALRM, do_nothing); 1482373Swnj nice(-20); 1493880Swnj fflush(stdout); 1502818Swnj #ifndef DEBUG 1512373Swnj if (i = fork()) { 1522818Swnj printf("[pid %d]\n", i); 1532373Swnj exit(0); 1542373Swnj } 155*8841Smckusick #else 156*8841Smckusick putc('\n', stdout); 1572818Swnj #endif 1582373Swnj sint = 1 HOURS; 1592373Swnj f = ""; 160*8841Smckusick ufd = open("/etc/utmp",0); 161*8841Smckusick if (ufd < 0) { 162*8841Smckusick perror("shutdown: /etc/utmp"); 163*8841Smckusick exit(1); 164*8841Smckusick } 165*8841Smckusick first = 1; 1662373Swnj for (;;) { 1672373Swnj for (i = 0; stogo <= interval[i].stogo && interval[i].sint; i++) 1682373Swnj sint = interval[i].sint; 169*8841Smckusick if (stogo > 0 && (stogo-sint) < interval[i].stogo) 170*8841Smckusick sint = stogo - interval[i].stogo; 1712373Swnj if (stogo <= NOLOGTIME && nlflag) { 1722373Swnj nlflag = 0; 1732373Swnj nolog(sdt); 1742373Swnj } 1752373Swnj if (sint >= stogo || sint == 0) 1762373Swnj f = "FINAL "; 177*8841Smckusick nowtime = time((time_t *) 0); 178*8841Smckusick lseek(ufd, 0L, 0); 1792373Swnj while (read(ufd,&utmp,sizeof utmp)==sizeof utmp) 1803885Sroot if (utmp.ut_name[0] && 1813885Sroot strncmp(utmp.ut_name, IGNOREUSER, sizeof(utmp.ut_name))) { 1822373Swnj strcpy(term, tpath); 1832373Swnj strncat(term, utmp.ut_line, sizeof utmp.ut_line); 1842373Swnj alarm(3); 1852373Swnj #ifdef DEBUG 1862818Swnj if ((termf = stdout) != NULL) 1872373Swnj #else 1882373Swnj if ((termf = fopen(term, "w")) != NULL) 1892373Swnj #endif 1902373Swnj { 1912373Swnj alarm(0); 1922373Swnj setbuf(termf, tbuf); 193*8841Smckusick fprintf(termf, "\n\r\n"); 194*8841Smckusick warn(termf, sdt, nowtime, f); 195*8841Smckusick if (first || sdt - nowtime > 1 MINUTES) { 196*8841Smckusick if (*nolog2) 197*8841Smckusick fprintf(termf, "\t..."); 1982373Swnj for (mess = nolog2; *mess; mess++) 199*8841Smckusick fprintf(termf, " %s", *mess); 200*8841Smckusick } 201*8841Smckusick fputc('\r', termf); 2022373Swnj fputc('\n', termf); 2032818Swnj alarm(5); 2042818Swnj #ifdef DEBUG 2052818Swnj fflush(termf); 2062818Swnj #else 2072373Swnj fclose(termf); 2082818Swnj #endif 2092373Swnj alarm(0); 2102373Swnj } 2112373Swnj } 212*8841Smckusick if (stogo <= 0) { 2132373Swnj printf("\n\007\007System shutdown time has arrived\007\007\n"); 2142818Swnj log_entry(sdt); 2152373Swnj unlink(nologin); 2162373Swnj if (!killflg) { 2172373Swnj printf("but you'll have to do it yourself\n"); 2182373Swnj finish(); 2192373Swnj } 2202373Swnj #ifndef DEBUG 221*8841Smckusick kill(-1, SIGTERM); /* terminate everyone */ 222*8841Smckusick sleep(5); /* & wait while they die */ 2232373Swnj if (reboot) 2242373Swnj execle(REBOOT, "reboot", 0, 0); 2252373Swnj if (halt) 2262373Swnj execle(HALT, "halt", 0, 0); 2272373Swnj kill(1, SIGTERM); /* sync */ 2282373Swnj kill(1, SIGTERM); /* sync */ 2292373Swnj sleep(20); 2302373Swnj #else 2312373Swnj printf("EXTERMINATE EXTERMINATE\n"); 2322373Swnj #endif 2332373Swnj finish(); 2342373Swnj } 235*8841Smckusick stogo = sdt - time((time_t *) 0); 236*8841Smckusick if (stogo > 0 && sint > 0) 2372373Swnj sleep(sint<stogo ? sint : stogo); 2382373Swnj stogo -= sint; 239*8841Smckusick first = 0; 2402373Swnj } 2412373Swnj } 2422373Swnj 2432373Swnj time_t 2442373Swnj getsdt(s) 245*8841Smckusick register char *s; 2462373Swnj { 2472373Swnj time_t t, t1, tim; 2482373Swnj register char c; 2492373Swnj struct tm *lt; 2502373Swnj 251*8841Smckusick if (strcmp(s, "now") == 0) 252*8841Smckusick return(nowtime); 2532373Swnj if (*s == '+') { 2542373Swnj ++s; 2552373Swnj t = 0; 2562373Swnj for (;;) { 2572373Swnj c = *s++; 2582373Swnj if (!isdigit(c)) 2592373Swnj break; 2602373Swnj t = t * 10 + c - '0'; 2612373Swnj } 2622373Swnj if (t <= 0) 2632373Swnj t = 5; 2642373Swnj t *= 60; 265*8841Smckusick tim = time((time_t *) 0) + t; 2662373Swnj return(tim); 2672373Swnj } 2682373Swnj t = 0; 2692373Swnj while (strlen(s) > 2 && isdigit(*s)) 2702373Swnj t = t * 10 + *s++ - '0'; 2712373Swnj if (*s == ':') 2722373Swnj s++; 2732373Swnj if (t > 23) 2742373Swnj goto badform; 2752373Swnj tim = t*60; 2762373Swnj t = 0; 2772373Swnj while (isdigit(*s)) 2782373Swnj t = t * 10 + *s++ - '0'; 2792373Swnj if (t > 59) 2802373Swnj goto badform; 2812373Swnj tim += t; 2822373Swnj tim *= 60; 283*8841Smckusick t1 = time((time_t *) 0); 2842373Swnj lt = localtime(&t1); 2852373Swnj t = lt->tm_sec + lt->tm_min*60 + lt->tm_hour*3600; 2862373Swnj if (tim < t || tim >= (24*3600)) { 2872373Swnj /* before now or after midnight */ 2882373Swnj printf("That must be tomorrow\nCan't you wait till then?\n"); 2892373Swnj finish(); 2902373Swnj } 291*8841Smckusick return (t1 + tim - t); 2922373Swnj badform: 2932373Swnj printf("Bad time format\n"); 2942373Swnj finish(); 2952373Swnj } 2962373Swnj 297*8841Smckusick warn(term, sdt, now, type) 2982373Swnj FILE *term; 299*8841Smckusick time_t sdt, now; 300*8841Smckusick char *type; 3012373Swnj { 3022373Swnj char *ts; 303*8841Smckusick register delay = sdt - now; 3042373Swnj 3053880Swnj if (delay > 8) 3063880Swnj while (delay % 5) 3073880Swnj delay++; 3083880Swnj 3093880Swnj if (shutter) 3103880Swnj fprintf(term, 311*8841Smckusick "\007\007\t*** %sSystem shutdown message from %s!%s ***\r\n\n", 312*8841Smckusick type, hostname, shutter); 3133880Swnj else 3143880Swnj fprintf(term, 315*8841Smckusick "\007\007\t*** %sSystem shutdown message (%s) ***\r\n\n", 316*8841Smckusick type, hostname); 317*8841Smckusick 3182373Swnj ts = ctime(&sdt); 319*8841Smckusick if (delay > 10 MINUTES) 320*8841Smckusick fprintf(term, "System going down at %5.5s\r\n", ts+11); 321*8841Smckusick else if (delay > 95 SECONDS) { 322*8841Smckusick fprintf(term, "System going down in %d minute%s\r\n", 323*8841Smckusick (delay+30)/60, (delay+30)/60 != 1 ? "s" : ""); 324*8841Smckusick } else if (delay > 0) { 325*8841Smckusick fprintf(term, "System going down in %d second%s\r\n", 326*8841Smckusick delay, delay != 1 ? "s" : ""); 3272373Swnj } else 328*8841Smckusick fprintf(term, "System going down IMMEDIATELY\r\n"); 3292373Swnj } 3302373Swnj 3312373Swnj nolog(sdt) 332*8841Smckusick time_t sdt; 3332373Swnj { 3342373Swnj FILE *nologf; 3352373Swnj register char **mess; 3362373Swnj 337*8841Smckusick unlink(nologin); /* in case linked to std file */ 3382373Swnj if ((nologf = fopen(nologin, "w")) != NULL) { 3392373Swnj fprintf(nologf, nolog1, (ctime(&sdt)) + 11); 3403880Swnj putc('\t', nologf); 3412373Swnj for (mess = nolog2; *mess; mess++) 3423880Swnj fprintf(nologf, " %s", *mess); 3433880Swnj putc('\n', nologf); 3442373Swnj fclose(nologf); 3452373Swnj } 3462373Swnj } 3472373Swnj 3482373Swnj finish() 3492373Swnj { 3502373Swnj signal(SIGTERM, SIG_IGN); 3512373Swnj unlink(nologin); 3522373Swnj exit(0); 3532373Swnj } 3542373Swnj 3552373Swnj do_nothing() 3562373Swnj { 3572373Swnj 3582373Swnj signal(SIGALRM, do_nothing); 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) 375*8841Smckusick 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"); 383*8841Smckusick if (fp == NULL) { 384*8841Smckusick printf("Shutdown: log entry failed\n"); 3853578Sroot return; 386*8841Smckusick } 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) 394*8841Smckusick fprintf(fp, " (by %s!%s)", hostname, shutter); 3953484Sroot fputc('\n', fp); 3963484Sroot fclose(fp); 3972818Swnj } 398