1*6203Sroot static char *sccsid = "@(#)shutdown.c 4.12 (Berkeley) 82/03/15"; 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 39*6203Sroot char hostname[32]; 40*6203Sroot 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 642373Swnj int slots; 652373Swnj struct interval { 662373Swnj int stogo; 672373Swnj int sint; 682373Swnj } interval[] = { 692373Swnj 4 HOURS, 1 HOURS, 702373Swnj 2 HOURS, 30 MINUTES, 712373Swnj 1 HOURS, 15 MINUTES, 722373Swnj 30 MINUTES, 10 MINUTES, 732373Swnj 15 MINUTES, 5 MINUTES, 742818Swnj 10 MINUTES, 5 MINUTES, 752818Swnj 5 MINUTES, 3 MINUTES, 762373Swnj 2 MINUTES, 30 SECONDS, 773880Swnj 40 SECONDS, 10 SECONDS, 782373Swnj 0 SECONDS, 0 SECONDS 792373Swnj }; 802818Swnj char *shutter, *getlogin(); 812373Swnj main(argc,argv) 822373Swnj int argc; 832373Swnj char **argv; 842373Swnj { 852373Swnj register i, ufd; 862373Swnj register char **mess, *f; 872373Swnj char *ts; 882373Swnj long sdt; 892373Swnj int h, m; 902373Swnj long nowtime; 912373Swnj FILE *termf; 922373Swnj 932818Swnj shutter = getlogin(); 94*6203Sroot gethostname(hostname, sizeof (hostname)); 952373Swnj argc--, argv++; 962373Swnj while (argc > 0 && (f = argv[0], *f++ == '-')) { 972373Swnj while (i = *f++) switch (i) { 982373Swnj case 'k': 992373Swnj killflg = 0; 1002373Swnj continue; 1012373Swnj case 'r': 1022373Swnj reboot = 1; 1032373Swnj continue; 1042373Swnj case 'h': 1052373Swnj halt = 1; 1062373Swnj continue; 1072373Swnj default: 1082373Swnj fprintf(stderr, "shutdown: '%c' - unknown flag\n", i); 1092373Swnj exit(1); 1102373Swnj } 1112373Swnj argc--, argv++; 1122373Swnj } 1132373Swnj if (argc < 1) { 1143880Swnj printf("Usage: %s [ -krh ] shutdowntime [ message ]\n", 1152373Swnj argv[0]); 1162373Swnj finish(); 1172373Swnj } 1183720Sroot if (geteuid()) { 1193720Sroot fprintf(stderr, "NOT super-user\n"); 1203648Stoy finish(); 1213648Stoy } 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 nowtime = time((long *)0); 1302373Swnj m = ((stogo = sdt - nowtime) + 30)/60; 1312373Swnj h = m/60; 1322373Swnj m %= 60; 1332373Swnj ts = ctime(&sdt); 1342818Swnj printf("Shutdown at %5.5s (in ", ts+11); 1352373Swnj if (h > 0) 1362373Swnj printf("%d hour%s ", h, h != 1 ? "s" : ""); 1372818Swnj printf("%d minute%s) ", m, m != 1 ? "s" : ""); 1382373Swnj #ifndef DEBUG 1392373Swnj signal(SIGHUP, SIG_IGN); 1402373Swnj signal(SIGQUIT, SIG_IGN); 1412373Swnj signal(SIGINT, SIG_IGN); 1422373Swnj #endif 1432373Swnj signal(SIGTERM, finish); 1442373Swnj signal(SIGALRM, do_nothing); 1452373Swnj nice(-20); 1463880Swnj fflush(stdout); 1472818Swnj #ifndef DEBUG 1482373Swnj if (i = fork()) { 1492818Swnj printf("[pid %d]\n", i); 1502373Swnj exit(0); 1512373Swnj } 1522818Swnj #endif 1532373Swnj sint = 1 HOURS; 1542373Swnj f = ""; 1552373Swnj for (;;) { 1562373Swnj for (i = 0; stogo <= interval[i].stogo && interval[i].sint; i++) 1572373Swnj sint = interval[i].sint; 1582373Swnj if (stogo <= NOLOGTIME && nlflag) { 1592373Swnj nlflag = 0; 1602373Swnj nolog(sdt); 1612373Swnj } 1622373Swnj if (sint >= stogo || sint == 0) 1632373Swnj f = "FINAL "; 1642373Swnj ufd = open("/etc/utmp",0); 1652373Swnj nowtime = time((long *) 0); 1662373Swnj while (read(ufd,&utmp,sizeof utmp)==sizeof utmp) 1673885Sroot if (utmp.ut_name[0] && 1683885Sroot strncmp(utmp.ut_name, IGNOREUSER, sizeof(utmp.ut_name))) { 1692373Swnj strcpy(term, tpath); 1702373Swnj strncat(term, utmp.ut_line, sizeof utmp.ut_line); 1712373Swnj alarm(3); 1722373Swnj #ifdef DEBUG 1732818Swnj if ((termf = stdout) != NULL) 1742373Swnj #else 1752373Swnj if ((termf = fopen(term, "w")) != NULL) 1762373Swnj #endif 1772373Swnj { 1782373Swnj alarm(0); 1792373Swnj setbuf(termf, tbuf); 1802373Swnj fprintf(termf, "\n\n"); 1812373Swnj warn(termf, sdt, nowtime); 1822373Swnj if (sdt - nowtime > 1 MINUTES) 1832373Swnj for (mess = nolog2; *mess; mess++) 1842373Swnj fprintf(termf, "%s ", *mess); 1852373Swnj fputc('\n', termf); 1862818Swnj alarm(5); 1872818Swnj #ifdef DEBUG 1882818Swnj fflush(termf); 1892818Swnj #else 1902373Swnj fclose(termf); 1912818Swnj #endif 1922373Swnj alarm(0); 1932373Swnj } 1942373Swnj } 1952373Swnj if (stogo < 0) { 1962373Swnj printf("\n\007\007System shutdown time has arrived\007\007\n"); 1972818Swnj log_entry(sdt); 1982373Swnj unlink(nologin); 1992373Swnj if (!killflg) { 2002373Swnj printf("but you'll have to do it yourself\n"); 2012373Swnj finish(); 2022373Swnj } 2032373Swnj #ifndef DEBUG 2042373Swnj if (reboot) 2052373Swnj execle(REBOOT, "reboot", 0, 0); 2062373Swnj if (halt) 2072373Swnj execle(HALT, "halt", 0, 0); 2082373Swnj kill(1, SIGTERM); /* sync */ 2092373Swnj kill(1, SIGTERM); /* sync */ 2102373Swnj sleep(20); 2112373Swnj #else 2122373Swnj printf("EXTERMINATE EXTERMINATE\n"); 2132373Swnj #endif 2142373Swnj finish(); 2152373Swnj } 2162373Swnj stogo = sdt - time((long *) 0); 2172373Swnj if (stogo > 0) 2182373Swnj sleep(sint<stogo ? sint : stogo); 2192373Swnj stogo -= sint; 2202373Swnj } 2212373Swnj } 2222373Swnj 2232373Swnj time_t 2242373Swnj getsdt(s) 2252373Swnj register char *s; 2262373Swnj { 2272373Swnj time_t t, t1, tim; 2282373Swnj register char c; 2292373Swnj struct tm *lt; 2302373Swnj 2312373Swnj if (*s == '+') { 2322373Swnj ++s; 2332373Swnj t = 0; 2342373Swnj for (;;) { 2352373Swnj c = *s++; 2362373Swnj if (!isdigit(c)) 2372373Swnj break; 2382373Swnj t = t * 10 + c - '0'; 2392373Swnj } 2402373Swnj if (t <= 0) 2412373Swnj t = 5; 2422373Swnj t *= 60; 2432373Swnj tim = time((long *) 0) + t; 2442373Swnj return(tim); 2452373Swnj } 2462373Swnj t = 0; 2472373Swnj while (strlen(s) > 2 && isdigit(*s)) 2482373Swnj t = t * 10 + *s++ - '0'; 2492373Swnj if (*s == ':') 2502373Swnj s++; 2512373Swnj if (t > 23) 2522373Swnj goto badform; 2532373Swnj tim = t*60; 2542373Swnj t = 0; 2552373Swnj while (isdigit(*s)) 2562373Swnj t = t * 10 + *s++ - '0'; 2572373Swnj if (t > 59) 2582373Swnj goto badform; 2592373Swnj tim += t; 2602373Swnj tim *= 60; 2612373Swnj t1 = time((long *) 0); 2622373Swnj lt = localtime(&t1); 2632373Swnj t = lt->tm_sec + lt->tm_min*60 + lt->tm_hour*3600; 2642373Swnj if (tim < t || tim >= (24*3600)) { 2652373Swnj /* before now or after midnight */ 2662373Swnj printf("That must be tomorrow\nCan't you wait till then?\n"); 2672373Swnj finish(); 2682373Swnj } 2692373Swnj return (t1 + tim -t); 2702373Swnj badform: 2712373Swnj printf("Bad time format\n"); 2722373Swnj finish(); 2732373Swnj } 2742373Swnj 2752373Swnj warn(term, sdt, nowtime) 2762373Swnj FILE *term; 2772373Swnj long sdt, nowtime; 2782373Swnj { 2792373Swnj char *ts; 2803881Swnj register delay = sdt - nowtime; 2812373Swnj 2823880Swnj if (delay > 8) 2833880Swnj while (delay % 5) 2843880Swnj delay++; 2853880Swnj 2863880Swnj if (shutter) 2873880Swnj fprintf(term, 2885633Sroot "\007\007*** System shutdown message from %s!%s ***\n", 2895633Sroot sysname,shutter); 2903880Swnj else 2913880Swnj fprintf(term, 2923880Swnj "\007\007*** System shutdown message ***\n"); 2932373Swnj ts = ctime(&sdt); 2943880Swnj if (delay> 10 MINUTES) 2952373Swnj fprintf(term, "System going down at %5.5s\n", ts+11); 2963880Swnj else if ( delay > 60 SECONDS ) { 2972373Swnj fprintf(term, "System going down in %d minute%s\n", 2983880Swnj (delay+30)/60, (delay+30)/60 != 1 ? "s" : ""); 2993880Swnj } else if ( delay > 0 ) { 3002818Swnj fprintf(term, "System going down in %d second%s\n", 3013880Swnj delay, delay != 1 ? "s" : ""); 3022373Swnj } else 3032373Swnj fprintf(term, "System going down IMMEDIATELY\n"); 3042373Swnj } 3052373Swnj 3062373Swnj nolog(sdt) 3072373Swnj long sdt; 3082373Swnj { 3092373Swnj FILE *nologf; 3102373Swnj register char **mess; 3112373Swnj 3122373Swnj if ((nologf = fopen(nologin, "w")) != NULL) { 3132373Swnj fprintf(nologf, nolog1, (ctime(&sdt)) + 11); 3143880Swnj putc('\t', nologf); 3152373Swnj for (mess = nolog2; *mess; mess++) 3163880Swnj fprintf(nologf, " %s", *mess); 3173880Swnj putc('\n', nologf); 3182373Swnj fclose(nologf); 3192373Swnj } 3202373Swnj } 3212373Swnj 3222373Swnj finish() 3232373Swnj { 3242373Swnj signal(SIGTERM, SIG_IGN); 3252373Swnj unlink(nologin); 3262373Swnj exit(0); 3272373Swnj } 3282373Swnj 3292373Swnj do_nothing() 3302373Swnj { 3312373Swnj 3322373Swnj signal(SIGALRM, do_nothing); 3332373Swnj } 3342818Swnj 3352818Swnj /* 3362818Swnj * make an entry in the shutdown log 3372818Swnj */ 3382818Swnj 3393484Sroot char *days[] = { 3403484Sroot "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" 3413484Sroot }; 3423484Sroot 3433484Sroot char *months[] = { 3443484Sroot "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", 3453484Sroot "Oct", "Nov", "Dec" 3463484Sroot }; 3473484Sroot 3483484Sroot log_entry(now) 3493484Sroot time_t now; 3502818Swnj { 3513484Sroot register FILE *fp; 3523484Sroot register char **mess; 3533484Sroot struct tm *tm, *localtime(); 3542818Swnj 3553484Sroot tm = localtime(&now); 3563484Sroot fp = fopen(LOGFILE, "a"); 3573578Sroot if (fp==0) 3583578Sroot return; 3593484Sroot fseek(fp, 0L, 2); 3603484Sroot fprintf(fp, "%02d:%02d %s %s %2d, %4d. Shutdown:", tm->tm_hour, 3613484Sroot tm->tm_min, days[tm->tm_wday], months[tm->tm_mon], 3623484Sroot tm->tm_mday, tm->tm_year + 1900); 3632818Swnj for (mess = nolog2; *mess; mess++) 3643484Sroot fprintf(fp, " %s", *mess); 3653880Swnj if (shutter) 3665633Sroot fprintf(fp, " (by %s!%s)", sysname,shutter); 3673484Sroot fputc('\n', fp); 3683484Sroot fclose(fp); 3692818Swnj } 370