make machine-independent by generatibg syswrite.s on the fly;
[unix-history] / usr / src / sbin / shutdown / shutdown.c
index 4dfe943..44c26b4 100644 (file)
@@ -1,11 +1,30 @@
-static char *sccsid = "@(#)shutdown.c  4.10 (Berkeley) 81/06/12";
+/*
+ * Copyright (c) 1983,1986 Regents of the University of California.
+ * All rights reserved.  The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1983,1986 Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif not lint
+
+#ifndef lint
+static char sccsid[] = "@(#)shutdown.c 5.6 (Berkeley) %G%";
+#endif not lint
 
 #include <stdio.h>
 #include <ctype.h>
 #include <signal.h>
 
 #include <stdio.h>
 #include <ctype.h>
 #include <signal.h>
+#include <setjmp.h>
 #include <utmp.h>
 #include <utmp.h>
-#include <time.h>
-#include <sys/types.h>
+#include <pwd.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/param.h>
+#include <sys/syslog.h>
+
 /*
  *     /etc/shutdown when [messages]
  *
 /*
  *     /etc/shutdown when [messages]
  *
@@ -13,34 +32,30 @@ static      char *sccsid = "@(#)shutdown.c  4.10 (Berkeley) 81/06/12";
  *     of iminent shutdown of unix
  *     and shut it down automatically
  *     and even reboot or halt the machine if they desire
  *     of iminent shutdown of unix
  *     and shut it down automatically
  *     and even reboot or halt the machine if they desire
- *
- *             Ian Johnstone, Sydney, 1977
- *             Robert Elz, Melbourne, 1978
- *             Peter Lamb, Melbourne, 1980
- *             William Joy, Berkeley, 1981
- *             Michael Toy, Berkeley, 1981
- *             Dave Presotto, Berkeley, 1981
  */
  */
-#ifdef DEBUG
-#define LOGFILE "shutdown.log"
-#else
-#define LOGFILE "/usr/adm/shutdownlog"
-#endif
+
 #define        REBOOT  "/etc/reboot"
 #define        HALT    "/etc/halt"
 #define MAXINTS 20
 #define        HOURS   *3600
 #define MINUTES        *60
 #define SECONDS
 #define        REBOOT  "/etc/reboot"
 #define        HALT    "/etc/halt"
 #define MAXINTS 20
 #define        HOURS   *3600
 #define MINUTES        *60
 #define SECONDS
-#define NLOG           20              /* no of args possible for message */
+#define NLOG           600             /* no of bytes possible for message */
 #define        NOLOGTIME       5 MINUTES
 #define IGNOREUSER     "sleeper"
 
 #define        NOLOGTIME       5 MINUTES
 #define IGNOREUSER     "sleeper"
 
-int    do_nothing();
+char   hostname[MAXHOSTNAMELEN];
+
+int    timeout();
 time_t getsdt();
 
 extern char *ctime();
 extern struct tm *localtime();
 time_t getsdt();
 
 extern char *ctime();
 extern struct tm *localtime();
+extern long time();
+
+extern char *strcpy();
+extern char *strncat();
+extern off_t lseek();
 
 struct utmp utmp;
 int    sint;
 
 struct utmp utmp;
 int    sint;
@@ -48,18 +63,25 @@ int stogo;
 char   tpath[] =       "/dev/";
 int    nlflag = 1;             /* nolog yet to be done */
 int    killflg = 1;
 char   tpath[] =       "/dev/";
 int    nlflag = 1;             /* nolog yet to be done */
 int    killflg = 1;
-int    reboot = 0;
+int    doreboot = 0;
 int    halt = 0;
 int    halt = 0;
+int     fast = 0;
+char    *nosync = NULL;
+char    nosyncflag[] = "-n";
 char   term[sizeof tpath + sizeof utmp.ut_line];
 char   tbuf[BUFSIZ];
 char   nolog1[] = "\n\nNO LOGINS: System going down at %5.5s\n\n";
 char   term[sizeof tpath + sizeof utmp.ut_line];
 char   tbuf[BUFSIZ];
 char   nolog1[] = "\n\nNO LOGINS: System going down at %5.5s\n\n";
-char   *nolog2[NLOG+1];
+char   nolog2[NLOG+1];
 #ifdef DEBUG
 char   nologin[] = "nologin";
 #ifdef DEBUG
 char   nologin[] = "nologin";
+char    fastboot[] = "fastboot";
 #else
 char   nologin[] = "/etc/nologin";
 #else
 char   nologin[] = "/etc/nologin";
+char   fastboot[] = "/fastboot";
 #endif
 #endif
-int slots;
+time_t nowtime;
+jmp_buf        alarmbuf;
+
 struct interval {
        int stogo;
        int sint;
 struct interval {
        int stogo;
        int sint;
@@ -71,32 +93,49 @@ struct interval {
        15 MINUTES,     5 MINUTES,
        10 MINUTES,     5 MINUTES,
        5 MINUTES,      3 MINUTES,
        15 MINUTES,     5 MINUTES,
        10 MINUTES,     5 MINUTES,
        5 MINUTES,      3 MINUTES,
-       2 MINUTES,      30 SECONDS,
-       40 SECONDS,     10 SECONDS,
+       2 MINUTES,      1 MINUTES,
+       1 MINUTES,      30 SECONDS,
        0 SECONDS,      0 SECONDS
 };
        0 SECONDS,      0 SECONDS
 };
+
 char *shutter, *getlogin();
 char *shutter, *getlogin();
+
 main(argc,argv)
        int argc;
        char **argv;
 {
        register i, ufd;
 main(argc,argv)
        int argc;
        char **argv;
 {
        register i, ufd;
-       register char **mess, *f;
+       register char *f;
        char *ts;
        char *ts;
-       long sdt;
+       time_t sdt;
        int h, m;
        int h, m;
-       long nowtime;
+       int first;
        FILE *termf;
        FILE *termf;
+       struct passwd *pw, *getpwuid();
+       extern char *strcat();
+       extern uid_t geteuid();
 
        shutter = getlogin();
 
        shutter = getlogin();
+       if (shutter == 0 && (pw = getpwuid(getuid())))
+               shutter = pw->pw_name;
+       if (shutter == 0)
+               shutter = "???";
+       (void) gethostname(hostname, sizeof (hostname));
+       openlog("shutdown", 0, LOG_AUTH);
        argc--, argv++;
        while (argc > 0 && (f = argv[0], *f++ == '-')) {
                while (i = *f++) switch (i) {
                case 'k':
                        killflg = 0;
                        continue;
        argc--, argv++;
        while (argc > 0 && (f = argv[0], *f++ == '-')) {
                while (i = *f++) switch (i) {
                case 'k':
                        killflg = 0;
                        continue;
+               case 'n':
+                       nosync = nosyncflag;
+                       continue;
+               case 'f':
+                       fast = 1;
+                       continue;
                case 'r':
                case 'r':
-                       reboot = 1;
+                       doreboot = 1;
                        continue;
                case 'h':
                        halt = 1;
                        continue;
                case 'h':
                        halt = 1;
@@ -108,22 +147,26 @@ main(argc,argv)
                argc--, argv++;
        }
        if (argc < 1) {
                argc--, argv++;
        }
        if (argc < 1) {
-               printf("Usage: %s [ -krh ] shutdowntime [ message ]\n",
-                   argv[0]);
+               /* argv[0] is not available after the argument handling. */
+               printf("Usage: shutdown [ -krhfn ] shutdowntime [ message ]\n");
+               finish();
+       }
+       if (fast && (nosync == nosyncflag)) {
+               printf ("shutdown: Incompatible switches 'fast' & 'nosync'\n");
                finish();
        }
        if (geteuid()) {
                fprintf(stderr, "NOT super-user\n");
                finish();
        }
                finish();
        }
        if (geteuid()) {
                fprintf(stderr, "NOT super-user\n");
                finish();
        }
+       nowtime = time((long *)0);
        sdt = getsdt(argv[0]);
        argc--, argv++;
        sdt = getsdt(argv[0]);
        argc--, argv++;
-       i = 0;
-       while (argc-- > 0)
-               if (i < NLOG)
-                       nolog2[i++] = *argv++;
-       nolog2[i] = NULL;
-       nowtime = time((long *)0);
+       nolog2[0] = '\0';
+       while (argc-- > 0) {
+               (void) strcat(nolog2, " ");
+               (void) strcat(nolog2, *argv++);
+       }
        m = ((stogo = sdt - nowtime) + 30)/60;
        h = m/60; 
        m %= 60;
        m = ((stogo = sdt - nowtime) + 30)/60;
        h = m/60; 
        m %= 60;
@@ -133,98 +176,129 @@ main(argc,argv)
                printf("%d hour%s ", h, h != 1 ? "s" : "");
        printf("%d minute%s) ", m, m != 1 ? "s" : "");
 #ifndef DEBUG
                printf("%d hour%s ", h, h != 1 ? "s" : "");
        printf("%d minute%s) ", m, m != 1 ? "s" : "");
 #ifndef DEBUG
-       signal(SIGHUP, SIG_IGN);
-       signal(SIGQUIT, SIG_IGN);
-       signal(SIGINT, SIG_IGN);
+       (void) signal(SIGHUP, SIG_IGN);
+       (void) signal(SIGQUIT, SIG_IGN);
+       (void) signal(SIGINT, SIG_IGN);
 #endif
 #endif
-       signal(SIGTERM, finish);
-       signal(SIGALRM, do_nothing);
-       nice(-20);
-       fflush(stdout);
+       (void) signal(SIGTTOU, SIG_IGN);
+       (void) signal(SIGTERM, finish);
+       (void) signal(SIGALRM, timeout);
+       (void) setpriority(PRIO_PROCESS, 0, PRIO_MIN);
+       (void) fflush(stdout);
 #ifndef DEBUG
        if (i = fork()) {
                printf("[pid %d]\n", i);
                exit(0);
        }
 #ifndef DEBUG
        if (i = fork()) {
                printf("[pid %d]\n", i);
                exit(0);
        }
+#else
+       (void) putc('\n', stdout);
 #endif
        sint = 1 HOURS;
        f = "";
 #endif
        sint = 1 HOURS;
        f = "";
+       ufd = open("/etc/utmp",0);
+       if (ufd < 0) {
+               perror("shutdown: /etc/utmp");
+               exit(1);
+       }
+       first = 1;
        for (;;) {
                for (i = 0; stogo <= interval[i].stogo && interval[i].sint; i++)
                        sint = interval[i].sint;
        for (;;) {
                for (i = 0; stogo <= interval[i].stogo && interval[i].sint; i++)
                        sint = interval[i].sint;
+               if (stogo > 0 && (stogo-sint) < interval[i].stogo)
+                       sint = stogo - interval[i].stogo;
                if (stogo <= NOLOGTIME && nlflag) {
                        nlflag = 0;
                        nolog(sdt);
                }
                if (sint >= stogo || sint == 0)
                        f = "FINAL ";
                if (stogo <= NOLOGTIME && nlflag) {
                        nlflag = 0;
                        nolog(sdt);
                }
                if (sint >= stogo || sint == 0)
                        f = "FINAL ";
-               ufd = open("/etc/utmp",0);
-               nowtime = time((long *) 0);
-               while (read(ufd,&utmp,sizeof utmp)==sizeof utmp)
+               nowtime = time((long *)0);
+               (void) lseek(ufd, 0L, 0);
+               while (read(ufd,(char *)&utmp,sizeof utmp)==sizeof utmp)
                if (utmp.ut_name[0] &&
                    strncmp(utmp.ut_name, IGNOREUSER, sizeof(utmp.ut_name))) {
                if (utmp.ut_name[0] &&
                    strncmp(utmp.ut_name, IGNOREUSER, sizeof(utmp.ut_name))) {
-                       strcpy(term, tpath);
-                       strncat(term, utmp.ut_line, sizeof utmp.ut_line);
-                       alarm(3);
+                       if (setjmp(alarmbuf))
+                               continue;
+                       (void) strcpy(term, tpath);
+                       (void) strncat(term, utmp.ut_line, sizeof utmp.ut_line);
+                       (void) alarm(3);
 #ifdef DEBUG
                        if ((termf = stdout) != NULL)
 #else
                        if ((termf = fopen(term, "w")) != NULL)
 #endif
                        {
 #ifdef DEBUG
                        if ((termf = stdout) != NULL)
 #else
                        if ((termf = fopen(term, "w")) != NULL)
 #endif
                        {
-                               alarm(0);
+                               (void) alarm(0);
                                setbuf(termf, tbuf);
                                setbuf(termf, tbuf);
-                               fprintf(termf, "\n\n");
-                               warn(termf, sdt, nowtime);
-                               if (sdt - nowtime > 1 MINUTES)
-                                       for (mess = nolog2; *mess; mess++)
-                                               fprintf(termf, "%s ", *mess);
-                               fputc('\n', termf);
-                               alarm(5);
+                               fprintf(termf, "\n\r\n");
+                               warn(termf, sdt, nowtime, f);
+                               if (first || sdt - nowtime > 1 MINUTES) {
+                                       if (*nolog2)
+                                               fprintf(termf, "\t...%s", nolog2);
+                               }
+                               (void) fputc('\r', termf);
+                               (void) fputc('\n', termf);
+                               (void) alarm(5);
 #ifdef DEBUG
 #ifdef DEBUG
-                               fflush(termf);
+                               (void) fflush(termf);
 #else
 #else
-                               fclose(termf);
+                               (void) fclose(termf);
 #endif
 #endif
-                               alarm(0);
+                               (void) alarm(0);
                        }
                }
                        }
                }
-               if (stogo < 0) {
-       printf("\n\007\007System shutdown time has arrived\007\007\n");
-                       log_entry(sdt);
-                       unlink(nologin);
+               if (stogo <= 0) {
+                       printf("\n\007\007System shutdown time has arrived\007\007\n");
+                       syslog(LOG_CRIT, "%s by %s: %s",
+                           doreboot ? "reboot" : halt ? "halt" : "shutdown",
+                           shutter, nolog2);
+                       sleep(2);
+                       (void) unlink(nologin);
                        if (!killflg) {
                                printf("but you'll have to do it yourself\n");
                                finish();
                        }
                        if (!killflg) {
                                printf("but you'll have to do it yourself\n");
                                finish();
                        }
+                       if (fast)
+                               doitfast();
 #ifndef DEBUG
 #ifndef DEBUG
-                       if (reboot)
-                               execle(REBOOT, "reboot", 0, 0);
+                       if (doreboot)
+                               execle(REBOOT, "reboot", "-l", nosync, 0, 0);
                        if (halt)
                        if (halt)
-                               execle(HALT, "halt", 0, 0);
-                       kill(1, SIGTERM);       /* sync */
-                       kill(1, SIGTERM);       /* sync */
-                       sleep(20);
+                               execle(HALT, "halt", "-l", nosync, 0, 0);
+                       (void) kill(1, SIGTERM);        /* to single user */
 #else
 #else
-                       printf("EXTERMINATE EXTERMINATE\n");
+                       if (doreboot)
+                               printf("REBOOT");
+                       if (halt)
+                               printf(" HALT");
+                       if (fast)
+                               printf(" -l %s (without fsck's)\n", nosync);
+                       else
+                               printf(" -l %s\n", nosync);
+                       else
+                               printf("kill -HUP 1\n");
+
 #endif
                        finish();
                }
                stogo = sdt - time((long *) 0);
 #endif
                        finish();
                }
                stogo = sdt - time((long *) 0);
-               if (stogo > 0)
-                       sleep(sint<stogo ? sint : stogo);
+               if (stogo > 0 && sint > 0)
+                       sleep((unsigned)(sint<stogo ? sint : stogo));
                stogo -= sint;
                stogo -= sint;
+               first = 0;
        }
 }
 
 time_t
 getsdt(s)
        }
 }
 
 time_t
 getsdt(s)
-register char *s;
+       register char *s;
 {
        time_t t, t1, tim;
        register char c;
        struct tm *lt;
 
 {
        time_t t, t1, tim;
        register char c;
        struct tm *lt;
 
+       if (strcmp(s, "now") == 0)
+               return(nowtime);
        if (*s == '+') {
                ++s; 
                t = 0;
        if (*s == '+') {
                ++s; 
                t = 0;
@@ -263,104 +337,74 @@ register char *s;
                printf("That must be tomorrow\nCan't you wait till then?\n");
                finish();
        }
                printf("That must be tomorrow\nCan't you wait till then?\n");
                finish();
        }
-       return (t1 + tim -t);
+       return (t1 + tim - t);
 badform:
        printf("Bad time format\n");
        finish();
 badform:
        printf("Bad time format\n");
        finish();
+       /*NOTREACHED*/
 }
 
 }
 
-warn(term, sdt, nowtime)
+warn(term, sdt, now, type)
        FILE *term;
        FILE *term;
-       long sdt, nowtime;
+       time_t sdt, now;
+       char *type;
 {
        char *ts;
 {
        char *ts;
-       register delay = sdt - nowtime;
+       register delay = sdt - now;
 
        if (delay > 8)
                while (delay % 5)
                        delay++;
 
 
        if (delay > 8)
                while (delay % 5)
                        delay++;
 
-       if (shutter)
-               fprintf(term,
-                   "\007\007*** System shutdown message from %s ***\n",
-                   shutter);
-       else
-               fprintf(term,
-                   "\007\007*** System shutdown message ***\n");
+       fprintf(term,
+           "\007\007\t*** %sSystem shutdown message from %s@%s ***\r\n\n",
+                   type, shutter, hostname);
+
        ts = ctime(&sdt);
        ts = ctime(&sdt);
-       if (delay> 10 MINUTES)
-               fprintf(term, "System going down at %5.5s\n", ts+11);
-       else if ( delay > 60 SECONDS ) {
-               fprintf(term, "System going down in %d minute%s\n",
-               (delay+30)/60, (delay+30)/60 != 1 ? "s" : "");
-       } else if ( delay > 0 ) {
-               fprintf(term, "System going down in %d second%s\n",
-               delay, delay != 1 ? "s" : "");
+       if (delay > 10 MINUTES)
+               fprintf(term, "System going down at %5.5s\r\n", ts+11);
+       else if (delay > 95 SECONDS) {
+               fprintf(term, "System going down in %d minute%s\r\n",
+                   (delay+30)/60, (delay+30)/60 != 1 ? "s" : "");
+       } else if (delay > 0) {
+               fprintf(term, "System going down in %d second%s\r\n",
+                   delay, delay != 1 ? "s" : "");
        } else
        } else
-               fprintf(term, "System going down IMMEDIATELY\n");
+               fprintf(term, "System going down IMMEDIATELY\r\n");
+}
+
+doitfast()
+{
+       FILE *fastd;
+
+       if ((fastd = fopen(fastboot, "w")) != NULL) {
+               putc('\n', fastd);
+               (void) fclose(fastd);
+       }
 }
 
 nolog(sdt)
 }
 
 nolog(sdt)
-       long sdt;
+       time_t sdt;
 {
        FILE *nologf;
 {
        FILE *nologf;
-       register char **mess;
 
 
+       (void) unlink(nologin);                 /* in case linked to std file */
        if ((nologf = fopen(nologin, "w")) != NULL) {
                fprintf(nologf, nolog1, (ctime(&sdt)) + 11);
        if ((nologf = fopen(nologin, "w")) != NULL) {
                fprintf(nologf, nolog1, (ctime(&sdt)) + 11);
-               putc('\t', nologf);
-               for (mess = nolog2; *mess; mess++)
-                       fprintf(nologf, " %s", *mess);
-               putc('\n', nologf);
-               fclose(nologf);
+               if (*nolog2)
+                       fprintf(nologf, "\t%s\n", nolog2 + 1);
+               (void) fclose(nologf);
        }
 }
 
 finish()
 {
        }
 }
 
 finish()
 {
-       signal(SIGTERM, SIG_IGN);
-       unlink(nologin);
+       (void) signal(SIGTERM, SIG_IGN);
+       (void) unlink(nologin);
        exit(0);
 }
 
        exit(0);
 }
 
-do_nothing()
-{
-
-       signal(SIGALRM, do_nothing);
-}
-
-/*
- * make an entry in the shutdown log
- */
-
-char *days[] = {
-       "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
-};
-
-char *months[] = {
-       "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep",
-       "Oct", "Nov", "Dec"
-};
-
-log_entry(now)
-time_t now;
+timeout()
 {
 {
-       register FILE *fp;
-       register char **mess;
-       struct tm *tm, *localtime();
-
-       tm = localtime(&now);
-       fp = fopen(LOGFILE, "a");
-       if (fp==0)
-               return;
-       fseek(fp, 0L, 2);
-       fprintf(fp, "%02d:%02d  %s %s %2d, %4d.  Shutdown:", tm->tm_hour,
-               tm->tm_min, days[tm->tm_wday], months[tm->tm_mon],
-               tm->tm_mday, tm->tm_year + 1900);
-       for (mess = nolog2; *mess; mess++)
-               fprintf(fp, " %s", *mess);
-       if (shutter)
-               fprintf(fp, " (by %s)", shutter);
-       fputc('\n', fp);
-       fclose(fp);
+       longjmp(alarmbuf, 1);
 }
 }