121179Sdist /* 221179Sdist * Copyright (c) 1983 Regents of the University of California. 321179Sdist * All rights reserved. The Berkeley software License Agreement 421179Sdist * specifies the terms and conditions for redistribution. 521179Sdist */ 621179Sdist 712682Ssam #ifndef lint 821179Sdist char copyright[] = 921179Sdist "@(#) Copyright (c) 1983 Regents of the University of California.\n\ 1021179Sdist All rights reserved.\n"; 1121179Sdist #endif not lint 122373Swnj 1321179Sdist #ifndef lint 14*25408Sbloom static char sccsid[] = "@(#)shutdown.c 5.3 (Berkeley) 11/06/85"; 1521179Sdist #endif not lint 1621179Sdist 172373Swnj #include <stdio.h> 182373Swnj #include <ctype.h> 192373Swnj #include <signal.h> 2015920Skarels #include <setjmp.h> 212373Swnj #include <utmp.h> 2212897Ssam #include <sys/time.h> 2312897Ssam #include <sys/resource.h> 242373Swnj #include <sys/types.h> 252373Swnj /* 262373Swnj * /etc/shutdown when [messages] 272373Swnj * 282373Swnj * allow super users to tell users and remind users 292373Swnj * of iminent shutdown of unix 302373Swnj * and shut it down automatically 312373Swnj * and even reboot or halt the machine if they desire 322373Swnj */ 332818Swnj #ifdef DEBUG 342818Swnj #define LOGFILE "shutdown.log" 352818Swnj #else 362818Swnj #define LOGFILE "/usr/adm/shutdownlog" 372818Swnj #endif 382373Swnj #define REBOOT "/etc/reboot" 392373Swnj #define HALT "/etc/halt" 402373Swnj #define MAXINTS 20 412373Swnj #define HOURS *3600 422373Swnj #define MINUTES *60 432373Swnj #define SECONDS 443880Swnj #define NLOG 20 /* no of args possible for message */ 452373Swnj #define NOLOGTIME 5 MINUTES 463885Sroot #define IGNOREUSER "sleeper" 472373Swnj 486203Sroot char hostname[32]; 496203Sroot 5015920Skarels int timeout(); 512373Swnj time_t getsdt(); 522373Swnj 532373Swnj extern char *ctime(); 542373Swnj extern struct tm *localtime(); 55*25408Sbloom extern long time(); 562373Swnj 57*25408Sbloom extern char *strcpy(); 58*25408Sbloom extern char *strncat(); 59*25408Sbloom extern off_t lseek(); 60*25408Sbloom 612373Swnj struct utmp utmp; 622373Swnj int sint; 632373Swnj int stogo; 642373Swnj char tpath[] = "/dev/"; 652373Swnj int nlflag = 1; /* nolog yet to be done */ 662373Swnj int killflg = 1; 67*25408Sbloom int doreboot = 0; 682373Swnj int halt = 0; 6925366Sbloom int fast = 0; 7025366Sbloom char *nosync = NULL; 7125366Sbloom char nosyncflag[] = "-n"; 722373Swnj char term[sizeof tpath + sizeof utmp.ut_line]; 732373Swnj char tbuf[BUFSIZ]; 742373Swnj char nolog1[] = "\n\nNO LOGINS: System going down at %5.5s\n\n"; 752373Swnj char *nolog2[NLOG+1]; 762373Swnj #ifdef DEBUG 772373Swnj char nologin[] = "nologin"; 7825366Sbloom char fastboot[] = "fastboot"; 792373Swnj #else 802373Swnj char nologin[] = "/etc/nologin"; 8125366Sbloom char fastboot[] = "/fastboot"; 822373Swnj #endif 838841Smckusick time_t nowtime; 8415920Skarels jmp_buf alarmbuf; 858841Smckusick 862373Swnj struct interval { 872373Swnj int stogo; 882373Swnj int sint; 892373Swnj } interval[] = { 902373Swnj 4 HOURS, 1 HOURS, 912373Swnj 2 HOURS, 30 MINUTES, 922373Swnj 1 HOURS, 15 MINUTES, 932373Swnj 30 MINUTES, 10 MINUTES, 942373Swnj 15 MINUTES, 5 MINUTES, 952818Swnj 10 MINUTES, 5 MINUTES, 962818Swnj 5 MINUTES, 3 MINUTES, 978841Smckusick 2 MINUTES, 1 MINUTES, 988841Smckusick 1 MINUTES, 30 SECONDS, 992373Swnj 0 SECONDS, 0 SECONDS 1002373Swnj }; 1018841Smckusick 1022818Swnj char *shutter, *getlogin(); 1038841Smckusick 1042373Swnj main(argc,argv) 1052373Swnj int argc; 1062373Swnj char **argv; 1072373Swnj { 1082373Swnj register i, ufd; 1092373Swnj register char **mess, *f; 1102373Swnj char *ts; 1118841Smckusick time_t sdt; 1122373Swnj int h, m; 1138841Smckusick int first; 1142373Swnj FILE *termf; 1152373Swnj 1162818Swnj shutter = getlogin(); 117*25408Sbloom (void) gethostname(hostname, sizeof (hostname)); 1182373Swnj argc--, argv++; 1192373Swnj while (argc > 0 && (f = argv[0], *f++ == '-')) { 1202373Swnj while (i = *f++) switch (i) { 1212373Swnj case 'k': 1222373Swnj killflg = 0; 1232373Swnj continue; 12425366Sbloom case 'n': 12525366Sbloom nosync = nosyncflag; 12625366Sbloom continue; 12725366Sbloom case 'f': 12825366Sbloom fast = 1; 12925366Sbloom continue; 1302373Swnj case 'r': 131*25408Sbloom doreboot = 1; 1322373Swnj continue; 1332373Swnj case 'h': 1342373Swnj halt = 1; 1352373Swnj continue; 1362373Swnj default: 1372373Swnj fprintf(stderr, "shutdown: '%c' - unknown flag\n", i); 1382373Swnj exit(1); 1392373Swnj } 1402373Swnj argc--, argv++; 1412373Swnj } 1422373Swnj if (argc < 1) { 14325366Sbloom /* argv[0] is not available after the argument handling. */ 14425366Sbloom printf("Usage: shutdown [ -krhfn ] shutdowntime [ message ]\n"); 1452373Swnj finish(); 1462373Swnj } 14725366Sbloom if (fast && (nosync == nosyncflag)) { 14825366Sbloom printf ("shutdown: Incompatible switches 'fast' & 'nosync'\n"); 14925366Sbloom finish(); 15025366Sbloom } 1513720Sroot if (geteuid()) { 1523720Sroot fprintf(stderr, "NOT super-user\n"); 1533648Stoy finish(); 1543648Stoy } 155*25408Sbloom nowtime = time((long *)0); 1562373Swnj sdt = getsdt(argv[0]); 1572373Swnj argc--, argv++; 1582373Swnj i = 0; 1592373Swnj while (argc-- > 0) 1602373Swnj if (i < NLOG) 1612373Swnj nolog2[i++] = *argv++; 1622373Swnj nolog2[i] = NULL; 1632373Swnj m = ((stogo = sdt - nowtime) + 30)/60; 1642373Swnj h = m/60; 1652373Swnj m %= 60; 1662373Swnj ts = ctime(&sdt); 1672818Swnj printf("Shutdown at %5.5s (in ", ts+11); 1682373Swnj if (h > 0) 1692373Swnj printf("%d hour%s ", h, h != 1 ? "s" : ""); 1702818Swnj printf("%d minute%s) ", m, m != 1 ? "s" : ""); 1712373Swnj #ifndef DEBUG 172*25408Sbloom (void) signal(SIGHUP, SIG_IGN); 173*25408Sbloom (void) signal(SIGQUIT, SIG_IGN); 174*25408Sbloom (void) signal(SIGINT, SIG_IGN); 1752373Swnj #endif 176*25408Sbloom (void) signal(SIGTTOU, SIG_IGN); 177*25408Sbloom (void) signal(SIGTERM, finish); 178*25408Sbloom (void) signal(SIGALRM, timeout); 179*25408Sbloom (void) setpriority(PRIO_PROCESS, 0, PRIO_MIN); 180*25408Sbloom (void) fflush(stdout); 1812818Swnj #ifndef DEBUG 1822373Swnj if (i = fork()) { 1832818Swnj printf("[pid %d]\n", i); 1842373Swnj exit(0); 1852373Swnj } 1868841Smckusick #else 187*25408Sbloom (void) putc('\n', stdout); 1882818Swnj #endif 1892373Swnj sint = 1 HOURS; 1902373Swnj f = ""; 1918841Smckusick ufd = open("/etc/utmp",0); 1928841Smckusick if (ufd < 0) { 1938841Smckusick perror("shutdown: /etc/utmp"); 1948841Smckusick exit(1); 1958841Smckusick } 1968841Smckusick first = 1; 1972373Swnj for (;;) { 1982373Swnj for (i = 0; stogo <= interval[i].stogo && interval[i].sint; i++) 1992373Swnj sint = interval[i].sint; 2008841Smckusick if (stogo > 0 && (stogo-sint) < interval[i].stogo) 2018841Smckusick sint = stogo - interval[i].stogo; 2022373Swnj if (stogo <= NOLOGTIME && nlflag) { 2032373Swnj nlflag = 0; 2042373Swnj nolog(sdt); 2052373Swnj } 2062373Swnj if (sint >= stogo || sint == 0) 2072373Swnj f = "FINAL "; 208*25408Sbloom nowtime = time((long *)0); 209*25408Sbloom (void) lseek(ufd, 0L, 0); 210*25408Sbloom while (read(ufd,(char *)&utmp,sizeof utmp)==sizeof utmp) 2113885Sroot if (utmp.ut_name[0] && 2123885Sroot strncmp(utmp.ut_name, IGNOREUSER, sizeof(utmp.ut_name))) { 21315920Skarels if (setjmp(alarmbuf)) 21415920Skarels continue; 215*25408Sbloom (void) strcpy(term, tpath); 216*25408Sbloom (void) strncat(term, utmp.ut_line, sizeof utmp.ut_line); 217*25408Sbloom (void) alarm(3); 2182373Swnj #ifdef DEBUG 2192818Swnj if ((termf = stdout) != NULL) 2202373Swnj #else 2212373Swnj if ((termf = fopen(term, "w")) != NULL) 2222373Swnj #endif 2232373Swnj { 224*25408Sbloom (void) alarm(0); 2252373Swnj setbuf(termf, tbuf); 2268841Smckusick fprintf(termf, "\n\r\n"); 2278841Smckusick warn(termf, sdt, nowtime, f); 2288841Smckusick if (first || sdt - nowtime > 1 MINUTES) { 2298841Smckusick if (*nolog2) 2308841Smckusick fprintf(termf, "\t..."); 2312373Swnj for (mess = nolog2; *mess; mess++) 2328841Smckusick fprintf(termf, " %s", *mess); 2338841Smckusick } 234*25408Sbloom (void) fputc('\r', termf); 235*25408Sbloom (void) fputc('\n', termf); 236*25408Sbloom (void) alarm(5); 2372818Swnj #ifdef DEBUG 238*25408Sbloom (void) fflush(termf); 2392818Swnj #else 240*25408Sbloom (void) fclose(termf); 2412818Swnj #endif 242*25408Sbloom (void) alarm(0); 2432373Swnj } 2442373Swnj } 2458841Smckusick if (stogo <= 0) { 2462373Swnj printf("\n\007\007System shutdown time has arrived\007\007\n"); 2472818Swnj log_entry(sdt); 248*25408Sbloom (void) unlink(nologin); 2492373Swnj if (!killflg) { 2502373Swnj printf("but you'll have to do it yourself\n"); 2512373Swnj finish(); 2522373Swnj } 25325366Sbloom if (fast) 25425366Sbloom doitfast(); 2552373Swnj #ifndef DEBUG 256*25408Sbloom (void) kill(-1, SIGTERM); /* terminate everyone */ 2578841Smckusick sleep(5); /* & wait while they die */ 258*25408Sbloom if (doreboot) 25925366Sbloom execle(REBOOT, "reboot", nosync, 0, 0); 2602373Swnj if (halt) 26125366Sbloom execle(HALT, "halt", nosync, 0, 0); 262*25408Sbloom (void) kill(1, SIGTERM); /* sync */ 263*25408Sbloom (void) kill(1, SIGTERM); /* sync */ 2642373Swnj sleep(20); 2652373Swnj #else 2662373Swnj printf("EXTERMINATE EXTERMINATE\n"); 267*25408Sbloom if (doreboot) 26825366Sbloom printf("REBOOT"); 26925366Sbloom if (halt) 27025366Sbloom printf(" HALT"); 27125366Sbloom if (fast) 27225366Sbloom printf(" %s (without fsck's)\n", nosync); 27325366Sbloom else 27425366Sbloom printf(" %s\n", nosync); 27525366Sbloom 2762373Swnj #endif 2772373Swnj finish(); 2782373Swnj } 279*25408Sbloom stogo = sdt - time((long *) 0); 2808841Smckusick if (stogo > 0 && sint > 0) 281*25408Sbloom sleep((unsigned)(sint<stogo ? sint : stogo)); 2822373Swnj stogo -= sint; 2838841Smckusick first = 0; 2842373Swnj } 2852373Swnj } 2862373Swnj 2872373Swnj time_t 2882373Swnj getsdt(s) 2898841Smckusick register char *s; 2902373Swnj { 2912373Swnj time_t t, t1, tim; 2922373Swnj register char c; 2932373Swnj struct tm *lt; 2942373Swnj 2958841Smckusick if (strcmp(s, "now") == 0) 2968841Smckusick return(nowtime); 2972373Swnj if (*s == '+') { 2982373Swnj ++s; 2992373Swnj t = 0; 3002373Swnj for (;;) { 3012373Swnj c = *s++; 3022373Swnj if (!isdigit(c)) 3032373Swnj break; 3042373Swnj t = t * 10 + c - '0'; 3052373Swnj } 3062373Swnj if (t <= 0) 3072373Swnj t = 5; 3082373Swnj t *= 60; 309*25408Sbloom tim = time((long *) 0) + t; 3102373Swnj return(tim); 3112373Swnj } 3122373Swnj t = 0; 3132373Swnj while (strlen(s) > 2 && isdigit(*s)) 3142373Swnj t = t * 10 + *s++ - '0'; 3152373Swnj if (*s == ':') 3162373Swnj s++; 3172373Swnj if (t > 23) 3182373Swnj goto badform; 3192373Swnj tim = t*60; 3202373Swnj t = 0; 3212373Swnj while (isdigit(*s)) 3222373Swnj t = t * 10 + *s++ - '0'; 3232373Swnj if (t > 59) 3242373Swnj goto badform; 3252373Swnj tim += t; 3262373Swnj tim *= 60; 327*25408Sbloom t1 = time((long *) 0); 3282373Swnj lt = localtime(&t1); 3292373Swnj t = lt->tm_sec + lt->tm_min*60 + lt->tm_hour*3600; 3302373Swnj if (tim < t || tim >= (24*3600)) { 3312373Swnj /* before now or after midnight */ 3322373Swnj printf("That must be tomorrow\nCan't you wait till then?\n"); 3332373Swnj finish(); 3342373Swnj } 3358841Smckusick return (t1 + tim - t); 3362373Swnj badform: 3372373Swnj printf("Bad time format\n"); 3382373Swnj finish(); 339*25408Sbloom /*NOTREACHED*/ 3402373Swnj } 3412373Swnj 3428841Smckusick warn(term, sdt, now, type) 3432373Swnj FILE *term; 3448841Smckusick time_t sdt, now; 3458841Smckusick char *type; 3462373Swnj { 3472373Swnj char *ts; 3488841Smckusick register delay = sdt - now; 3492373Swnj 3503880Swnj if (delay > 8) 3513880Swnj while (delay % 5) 3523880Swnj delay++; 3533880Swnj 3543880Swnj if (shutter) 3553880Swnj fprintf(term, 35613178Sroot "\007\007\t*** %sSystem shutdown message from %s@%s ***\r\n\n", 35713178Sroot type, shutter, hostname); 3583880Swnj else 3593880Swnj fprintf(term, 3608841Smckusick "\007\007\t*** %sSystem shutdown message (%s) ***\r\n\n", 3618841Smckusick type, hostname); 3628841Smckusick 3632373Swnj ts = ctime(&sdt); 3648841Smckusick if (delay > 10 MINUTES) 3658841Smckusick fprintf(term, "System going down at %5.5s\r\n", ts+11); 3668841Smckusick else if (delay > 95 SECONDS) { 3678841Smckusick fprintf(term, "System going down in %d minute%s\r\n", 3688841Smckusick (delay+30)/60, (delay+30)/60 != 1 ? "s" : ""); 3698841Smckusick } else if (delay > 0) { 3708841Smckusick fprintf(term, "System going down in %d second%s\r\n", 3718841Smckusick delay, delay != 1 ? "s" : ""); 3722373Swnj } else 3738841Smckusick fprintf(term, "System going down IMMEDIATELY\r\n"); 3742373Swnj } 3752373Swnj 37625366Sbloom doitfast() 37725366Sbloom { 37825366Sbloom FILE *fastd; 37925366Sbloom 38025366Sbloom if ((fastd = fopen(fastboot, "w")) != NULL) { 38125366Sbloom putc('\n', fastd); 382*25408Sbloom (void) fclose(fastd); 38325366Sbloom } 38425366Sbloom } 38525366Sbloom 3862373Swnj nolog(sdt) 3878841Smckusick time_t sdt; 3882373Swnj { 3892373Swnj FILE *nologf; 3902373Swnj register char **mess; 3912373Swnj 392*25408Sbloom (void) unlink(nologin); /* in case linked to std file */ 3932373Swnj if ((nologf = fopen(nologin, "w")) != NULL) { 3942373Swnj fprintf(nologf, nolog1, (ctime(&sdt)) + 11); 395*25408Sbloom (void) putc('\t', nologf); 3962373Swnj for (mess = nolog2; *mess; mess++) 3973880Swnj fprintf(nologf, " %s", *mess); 398*25408Sbloom (void) putc('\n', nologf); 399*25408Sbloom (void) fclose(nologf); 4002373Swnj } 4012373Swnj } 4022373Swnj 4032373Swnj finish() 4042373Swnj { 405*25408Sbloom (void) signal(SIGTERM, SIG_IGN); 406*25408Sbloom (void) unlink(nologin); 4072373Swnj exit(0); 4082373Swnj } 4092373Swnj 41015920Skarels timeout() 4112373Swnj { 41215920Skarels longjmp(alarmbuf, 1); 4132373Swnj } 4142818Swnj 4152818Swnj /* 4162818Swnj * make an entry in the shutdown log 4172818Swnj */ 4182818Swnj 4193484Sroot char *days[] = { 4203484Sroot "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" 4213484Sroot }; 4223484Sroot 4233484Sroot char *months[] = { 4243484Sroot "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", 4253484Sroot "Oct", "Nov", "Dec" 4263484Sroot }; 4273484Sroot 4283484Sroot log_entry(now) 4298841Smckusick time_t now; 4302818Swnj { 4313484Sroot register FILE *fp; 4323484Sroot register char **mess; 4333484Sroot struct tm *tm, *localtime(); 4342818Swnj 4353484Sroot tm = localtime(&now); 4363484Sroot fp = fopen(LOGFILE, "a"); 4378841Smckusick if (fp == NULL) { 4388841Smckusick printf("Shutdown: log entry failed\n"); 4393578Sroot return; 4408841Smckusick } 441*25408Sbloom (void) fseek(fp, 0L, 2); 4423484Sroot fprintf(fp, "%02d:%02d %s %s %2d, %4d. Shutdown:", tm->tm_hour, 4433484Sroot tm->tm_min, days[tm->tm_wday], months[tm->tm_mon], 4443484Sroot tm->tm_mday, tm->tm_year + 1900); 4452818Swnj for (mess = nolog2; *mess; mess++) 4463484Sroot fprintf(fp, " %s", *mess); 4473880Swnj if (shutter) 4488841Smckusick fprintf(fp, " (by %s!%s)", hostname, shutter); 449*25408Sbloom (void) fputc('\n', fp); 450*25408Sbloom (void) fclose(fp); 4512818Swnj } 452