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*28024Seric static char sccsid[] = "@(#)shutdown.c 5.4 (Berkeley) 05/12/86"; 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> 25*28024Seric #include <sys/syslog.h> 26*28024Seric 272373Swnj /* 282373Swnj * /etc/shutdown when [messages] 292373Swnj * 302373Swnj * allow super users to tell users and remind users 312373Swnj * of iminent shutdown of unix 322373Swnj * and shut it down automatically 332373Swnj * and even reboot or halt the machine if they desire 342373Swnj */ 35*28024Seric 362373Swnj #define REBOOT "/etc/reboot" 372373Swnj #define HALT "/etc/halt" 382373Swnj #define MAXINTS 20 392373Swnj #define HOURS *3600 402373Swnj #define MINUTES *60 412373Swnj #define SECONDS 42*28024Seric #define NLOG 600 /* no of bytes possible for message */ 432373Swnj #define NOLOGTIME 5 MINUTES 443885Sroot #define IGNOREUSER "sleeper" 452373Swnj 466203Sroot char hostname[32]; 476203Sroot 4815920Skarels int timeout(); 492373Swnj time_t getsdt(); 502373Swnj 512373Swnj extern char *ctime(); 522373Swnj extern struct tm *localtime(); 5325408Sbloom extern long time(); 542373Swnj 5525408Sbloom extern char *strcpy(); 5625408Sbloom extern char *strncat(); 5725408Sbloom extern off_t lseek(); 5825408Sbloom 592373Swnj struct utmp utmp; 602373Swnj int sint; 612373Swnj int stogo; 622373Swnj char tpath[] = "/dev/"; 632373Swnj int nlflag = 1; /* nolog yet to be done */ 642373Swnj int killflg = 1; 6525408Sbloom int doreboot = 0; 662373Swnj int halt = 0; 6725366Sbloom int fast = 0; 6825366Sbloom char *nosync = NULL; 6925366Sbloom char nosyncflag[] = "-n"; 702373Swnj char term[sizeof tpath + sizeof utmp.ut_line]; 712373Swnj char tbuf[BUFSIZ]; 722373Swnj char nolog1[] = "\n\nNO LOGINS: System going down at %5.5s\n\n"; 73*28024Seric char nolog2[NLOG+1]; 742373Swnj #ifdef DEBUG 752373Swnj char nologin[] = "nologin"; 7625366Sbloom char fastboot[] = "fastboot"; 772373Swnj #else 782373Swnj char nologin[] = "/etc/nologin"; 7925366Sbloom char fastboot[] = "/fastboot"; 802373Swnj #endif 818841Smckusick time_t nowtime; 8215920Skarels jmp_buf alarmbuf; 838841Smckusick 842373Swnj struct interval { 852373Swnj int stogo; 862373Swnj int sint; 872373Swnj } interval[] = { 882373Swnj 4 HOURS, 1 HOURS, 892373Swnj 2 HOURS, 30 MINUTES, 902373Swnj 1 HOURS, 15 MINUTES, 912373Swnj 30 MINUTES, 10 MINUTES, 922373Swnj 15 MINUTES, 5 MINUTES, 932818Swnj 10 MINUTES, 5 MINUTES, 942818Swnj 5 MINUTES, 3 MINUTES, 958841Smckusick 2 MINUTES, 1 MINUTES, 968841Smckusick 1 MINUTES, 30 SECONDS, 972373Swnj 0 SECONDS, 0 SECONDS 982373Swnj }; 998841Smckusick 1002818Swnj char *shutter, *getlogin(); 1018841Smckusick 1022373Swnj main(argc,argv) 1032373Swnj int argc; 1042373Swnj char **argv; 1052373Swnj { 1062373Swnj register i, ufd; 107*28024Seric register char *f; 1082373Swnj char *ts; 1098841Smckusick time_t sdt; 1102373Swnj int h, m; 1118841Smckusick int first; 1122373Swnj FILE *termf; 1132373Swnj 1142818Swnj shutter = getlogin(); 115*28024Seric if (shutter == 0) 116*28024Seric shutter = "???"; 11725408Sbloom (void) gethostname(hostname, sizeof (hostname)); 118*28024Seric openlog("shutdown", 0, LOG_AUTH); 1192373Swnj argc--, argv++; 1202373Swnj while (argc > 0 && (f = argv[0], *f++ == '-')) { 1212373Swnj while (i = *f++) switch (i) { 1222373Swnj case 'k': 1232373Swnj killflg = 0; 1242373Swnj continue; 12525366Sbloom case 'n': 12625366Sbloom nosync = nosyncflag; 12725366Sbloom continue; 12825366Sbloom case 'f': 12925366Sbloom fast = 1; 13025366Sbloom continue; 1312373Swnj case 'r': 13225408Sbloom doreboot = 1; 1332373Swnj continue; 1342373Swnj case 'h': 1352373Swnj halt = 1; 1362373Swnj continue; 1372373Swnj default: 1382373Swnj fprintf(stderr, "shutdown: '%c' - unknown flag\n", i); 1392373Swnj exit(1); 1402373Swnj } 1412373Swnj argc--, argv++; 1422373Swnj } 1432373Swnj if (argc < 1) { 14425366Sbloom /* argv[0] is not available after the argument handling. */ 14525366Sbloom printf("Usage: shutdown [ -krhfn ] shutdowntime [ message ]\n"); 1462373Swnj finish(); 1472373Swnj } 14825366Sbloom if (fast && (nosync == nosyncflag)) { 14925366Sbloom printf ("shutdown: Incompatible switches 'fast' & 'nosync'\n"); 15025366Sbloom finish(); 15125366Sbloom } 1523720Sroot if (geteuid()) { 1533720Sroot fprintf(stderr, "NOT super-user\n"); 1543648Stoy finish(); 1553648Stoy } 15625408Sbloom nowtime = time((long *)0); 1572373Swnj sdt = getsdt(argv[0]); 1582373Swnj argc--, argv++; 159*28024Seric nolog2[0] = '\0'; 160*28024Seric while (argc-- > 0) { 161*28024Seric strcat(nolog2, " "); 162*28024Seric strcat(nolog2, *argv++); 163*28024Seric } 1642373Swnj m = ((stogo = sdt - nowtime) + 30)/60; 1652373Swnj h = m/60; 1662373Swnj m %= 60; 1672373Swnj ts = ctime(&sdt); 1682818Swnj printf("Shutdown at %5.5s (in ", ts+11); 1692373Swnj if (h > 0) 1702373Swnj printf("%d hour%s ", h, h != 1 ? "s" : ""); 1712818Swnj printf("%d minute%s) ", m, m != 1 ? "s" : ""); 1722373Swnj #ifndef DEBUG 17325408Sbloom (void) signal(SIGHUP, SIG_IGN); 17425408Sbloom (void) signal(SIGQUIT, SIG_IGN); 17525408Sbloom (void) signal(SIGINT, SIG_IGN); 1762373Swnj #endif 17725408Sbloom (void) signal(SIGTTOU, SIG_IGN); 17825408Sbloom (void) signal(SIGTERM, finish); 17925408Sbloom (void) signal(SIGALRM, timeout); 18025408Sbloom (void) setpriority(PRIO_PROCESS, 0, PRIO_MIN); 18125408Sbloom (void) fflush(stdout); 1822818Swnj #ifndef DEBUG 1832373Swnj if (i = fork()) { 1842818Swnj printf("[pid %d]\n", i); 1852373Swnj exit(0); 1862373Swnj } 1878841Smckusick #else 18825408Sbloom (void) putc('\n', stdout); 1892818Swnj #endif 1902373Swnj sint = 1 HOURS; 1912373Swnj f = ""; 1928841Smckusick ufd = open("/etc/utmp",0); 1938841Smckusick if (ufd < 0) { 1948841Smckusick perror("shutdown: /etc/utmp"); 1958841Smckusick exit(1); 1968841Smckusick } 1978841Smckusick first = 1; 1982373Swnj for (;;) { 1992373Swnj for (i = 0; stogo <= interval[i].stogo && interval[i].sint; i++) 2002373Swnj sint = interval[i].sint; 2018841Smckusick if (stogo > 0 && (stogo-sint) < interval[i].stogo) 2028841Smckusick sint = stogo - interval[i].stogo; 2032373Swnj if (stogo <= NOLOGTIME && nlflag) { 2042373Swnj nlflag = 0; 2052373Swnj nolog(sdt); 2062373Swnj } 2072373Swnj if (sint >= stogo || sint == 0) 2082373Swnj f = "FINAL "; 20925408Sbloom nowtime = time((long *)0); 21025408Sbloom (void) lseek(ufd, 0L, 0); 21125408Sbloom while (read(ufd,(char *)&utmp,sizeof utmp)==sizeof utmp) 2123885Sroot if (utmp.ut_name[0] && 2133885Sroot strncmp(utmp.ut_name, IGNOREUSER, sizeof(utmp.ut_name))) { 21415920Skarels if (setjmp(alarmbuf)) 21515920Skarels continue; 21625408Sbloom (void) strcpy(term, tpath); 21725408Sbloom (void) strncat(term, utmp.ut_line, sizeof utmp.ut_line); 21825408Sbloom (void) alarm(3); 2192373Swnj #ifdef DEBUG 2202818Swnj if ((termf = stdout) != NULL) 2212373Swnj #else 2222373Swnj if ((termf = fopen(term, "w")) != NULL) 2232373Swnj #endif 2242373Swnj { 22525408Sbloom (void) alarm(0); 2262373Swnj setbuf(termf, tbuf); 2278841Smckusick fprintf(termf, "\n\r\n"); 2288841Smckusick warn(termf, sdt, nowtime, f); 2298841Smckusick if (first || sdt - nowtime > 1 MINUTES) { 2308841Smckusick if (*nolog2) 231*28024Seric fprintf(termf, "\t...%s", nolog2); 2328841Smckusick } 23325408Sbloom (void) fputc('\r', termf); 23425408Sbloom (void) fputc('\n', termf); 23525408Sbloom (void) alarm(5); 2362818Swnj #ifdef DEBUG 23725408Sbloom (void) fflush(termf); 2382818Swnj #else 23925408Sbloom (void) fclose(termf); 2402818Swnj #endif 24125408Sbloom (void) alarm(0); 2422373Swnj } 2432373Swnj } 2448841Smckusick if (stogo <= 0) { 245*28024Seric printf("\n\007\007System shutdown time has arrived\007\007\n"); 246*28024Seric syslog(LOG_CRIT, "%s!%s: %s", hostname, shutter, nolog2); 24725408Sbloom (void) unlink(nologin); 2482373Swnj if (!killflg) { 2492373Swnj printf("but you'll have to do it yourself\n"); 2502373Swnj finish(); 2512373Swnj } 25225366Sbloom if (fast) 25325366Sbloom doitfast(); 2542373Swnj #ifndef DEBUG 25525408Sbloom (void) kill(-1, SIGTERM); /* terminate everyone */ 2568841Smckusick sleep(5); /* & wait while they die */ 25725408Sbloom if (doreboot) 25825366Sbloom execle(REBOOT, "reboot", nosync, 0, 0); 2592373Swnj if (halt) 26025366Sbloom execle(HALT, "halt", nosync, 0, 0); 26125408Sbloom (void) kill(1, SIGTERM); /* sync */ 26225408Sbloom (void) kill(1, SIGTERM); /* sync */ 2632373Swnj sleep(20); 2642373Swnj #else 2652373Swnj printf("EXTERMINATE EXTERMINATE\n"); 26625408Sbloom if (doreboot) 26725366Sbloom printf("REBOOT"); 26825366Sbloom if (halt) 26925366Sbloom printf(" HALT"); 27025366Sbloom if (fast) 27125366Sbloom printf(" %s (without fsck's)\n", nosync); 27225366Sbloom else 27325366Sbloom printf(" %s\n", nosync); 27425366Sbloom 2752373Swnj #endif 2762373Swnj finish(); 2772373Swnj } 27825408Sbloom stogo = sdt - time((long *) 0); 2798841Smckusick if (stogo > 0 && sint > 0) 28025408Sbloom sleep((unsigned)(sint<stogo ? sint : stogo)); 2812373Swnj stogo -= sint; 2828841Smckusick first = 0; 2832373Swnj } 2842373Swnj } 2852373Swnj 2862373Swnj time_t 2872373Swnj getsdt(s) 2888841Smckusick register char *s; 2892373Swnj { 2902373Swnj time_t t, t1, tim; 2912373Swnj register char c; 2922373Swnj struct tm *lt; 2932373Swnj 2948841Smckusick if (strcmp(s, "now") == 0) 2958841Smckusick return(nowtime); 2962373Swnj if (*s == '+') { 2972373Swnj ++s; 2982373Swnj t = 0; 2992373Swnj for (;;) { 3002373Swnj c = *s++; 3012373Swnj if (!isdigit(c)) 3022373Swnj break; 3032373Swnj t = t * 10 + c - '0'; 3042373Swnj } 3052373Swnj if (t <= 0) 3062373Swnj t = 5; 3072373Swnj t *= 60; 30825408Sbloom tim = time((long *) 0) + t; 3092373Swnj return(tim); 3102373Swnj } 3112373Swnj t = 0; 3122373Swnj while (strlen(s) > 2 && isdigit(*s)) 3132373Swnj t = t * 10 + *s++ - '0'; 3142373Swnj if (*s == ':') 3152373Swnj s++; 3162373Swnj if (t > 23) 3172373Swnj goto badform; 3182373Swnj tim = t*60; 3192373Swnj t = 0; 3202373Swnj while (isdigit(*s)) 3212373Swnj t = t * 10 + *s++ - '0'; 3222373Swnj if (t > 59) 3232373Swnj goto badform; 3242373Swnj tim += t; 3252373Swnj tim *= 60; 32625408Sbloom t1 = time((long *) 0); 3272373Swnj lt = localtime(&t1); 3282373Swnj t = lt->tm_sec + lt->tm_min*60 + lt->tm_hour*3600; 3292373Swnj if (tim < t || tim >= (24*3600)) { 3302373Swnj /* before now or after midnight */ 3312373Swnj printf("That must be tomorrow\nCan't you wait till then?\n"); 3322373Swnj finish(); 3332373Swnj } 3348841Smckusick return (t1 + tim - t); 3352373Swnj badform: 3362373Swnj printf("Bad time format\n"); 3372373Swnj finish(); 33825408Sbloom /*NOTREACHED*/ 3392373Swnj } 3402373Swnj 3418841Smckusick warn(term, sdt, now, type) 3422373Swnj FILE *term; 3438841Smckusick time_t sdt, now; 3448841Smckusick char *type; 3452373Swnj { 3462373Swnj char *ts; 3478841Smckusick register delay = sdt - now; 3482373Swnj 3493880Swnj if (delay > 8) 3503880Swnj while (delay % 5) 3513880Swnj delay++; 3523880Swnj 353*28024Seric fprintf(term, 35413178Sroot "\007\007\t*** %sSystem shutdown message from %s@%s ***\r\n\n", 35513178Sroot type, shutter, hostname); 3568841Smckusick 3572373Swnj ts = ctime(&sdt); 3588841Smckusick if (delay > 10 MINUTES) 3598841Smckusick fprintf(term, "System going down at %5.5s\r\n", ts+11); 3608841Smckusick else if (delay > 95 SECONDS) { 3618841Smckusick fprintf(term, "System going down in %d minute%s\r\n", 3628841Smckusick (delay+30)/60, (delay+30)/60 != 1 ? "s" : ""); 3638841Smckusick } else if (delay > 0) { 3648841Smckusick fprintf(term, "System going down in %d second%s\r\n", 3658841Smckusick delay, delay != 1 ? "s" : ""); 3662373Swnj } else 3678841Smckusick fprintf(term, "System going down IMMEDIATELY\r\n"); 3682373Swnj } 3692373Swnj 37025366Sbloom doitfast() 37125366Sbloom { 37225366Sbloom FILE *fastd; 37325366Sbloom 37425366Sbloom if ((fastd = fopen(fastboot, "w")) != NULL) { 37525366Sbloom putc('\n', fastd); 37625408Sbloom (void) fclose(fastd); 37725366Sbloom } 37825366Sbloom } 37925366Sbloom 3802373Swnj nolog(sdt) 3818841Smckusick time_t sdt; 3822373Swnj { 3832373Swnj FILE *nologf; 3842373Swnj 38525408Sbloom (void) unlink(nologin); /* in case linked to std file */ 3862373Swnj if ((nologf = fopen(nologin, "w")) != NULL) { 3872373Swnj fprintf(nologf, nolog1, (ctime(&sdt)) + 11); 388*28024Seric if (*nolog2) 389*28024Seric fprintf(nologf, "\t%s\n", nolog2 + 1); 39025408Sbloom (void) fclose(nologf); 3912373Swnj } 3922373Swnj } 3932373Swnj 3942373Swnj finish() 3952373Swnj { 39625408Sbloom (void) signal(SIGTERM, SIG_IGN); 39725408Sbloom (void) unlink(nologin); 3982373Swnj exit(0); 3992373Swnj } 4002373Swnj 40115920Skarels timeout() 4022373Swnj { 40315920Skarels longjmp(alarmbuf, 1); 4042373Swnj } 405