Hey,

Shutting down a box at the wrong time of day could be bad.  Admins
are not infallible and they do they necessarily reside in the same
timezone as a given box.

Users, too, don't necessarily reside in the same timezone as
a given box, so broadcasting that the box is going down at
"23:00" could be misleading.

So, always print/log/broadcast the machine's local timezone when
we can, giving an admin an opportunity to correct the mistake, or
a user a better understanding of precisely when it's going to happen.

This patch also updates the process' understanding of the current
time before printing the estimated shutdown time everywhere.  It's
possible for the system wall clock to change after a shutdown is
scheduled, which would make subsequent warning broadcasts inaccurate
and might mislead the users on the system.

ok?

--
Scott Cheloha

Index: sbin/shutdown/shutdown.c
===================================================================
RCS file: /cvs/src/sbin/shutdown/shutdown.c,v
retrieving revision 1.50
diff -u -p -r1.50 shutdown.c
--- sbin/shutdown/shutdown.c    19 Mar 2018 14:51:45 -0000      1.50
+++ sbin/shutdown/shutdown.c    30 Mar 2018 20:01:31 -0000
@@ -98,7 +98,7 @@ void doitfast(void);
 void __dead finish(int);
 void getoffset(char *);
 void __dead loop(void);
-void nolog(void);
+void nolog(time_t);
 void timeout(int);
 void timewarn(time_t);
 void usage(void);
@@ -106,9 +106,11 @@ void usage(void);
 int
 main(int argc, char *argv[])
 {
-       int arglen, ch, len, readstdin = 0;
-       struct passwd *pw;
+       char when[64];
        char *p, *endp;
+       struct passwd *pw;
+       struct tm *lt;
+       int arglen, ch, len, readstdin = 0;
        pid_t forkpid;
 
        if (pledge("stdio rpath wpath cpath getpw tty id proc exec", NULL) == 
-1)
@@ -198,15 +200,16 @@ main(int argc, char *argv[])
        }
        mbuflen = strlen(mbuf);
 
-       if (offset) {
-               char *ct = ctime(&shuttime);
-
-               if (ct)
-                       printf("Shutdown at %.24s.\n", ct);
-               else
+       if (offset > 0) {
+               shuttime = time(NULL) + offset;
+               lt = localtime(&shuttime);
+               if (lt != NULL) {
+                       strftime(when, sizeof(when), "%a %b %e %T %Z %Y", lt);
+                       printf("Shutdown at %s.\n", when);
+               } else
                        printf("Shutdown soon.\n");
        } else
-               (void)printf("Shutdown NOW!\n");
+               printf("Shutdown NOW!\n");
 
        if (!(whom = getlogin()))
                whom = (pw = getpwuid(getuid())) ? pw->pw_name : "???";
@@ -261,7 +264,7 @@ loop(void)
                broadcast = 1;
                if (!logged && tlist[i].timeleft <= NOLOG_TIME) {
                        logged = 1;
-                       nolog();
+                       nolog(tlist[i].timeleft);
                }
                timeout.tv_sec = tlist[i].timetowait;
                timeout.tv_nsec = 0;
@@ -279,6 +282,8 @@ void
 timewarn(time_t timeleft)
 {
        static char hostname[HOST_NAME_MAX+1];
+       char when[64];
+       struct tm *lt;
        static int first;
        int fd[2];
        pid_t pid, wpid;
@@ -317,11 +322,17 @@ timewarn(time_t timeleft)
            "\007*** %sSystem shutdown message from %s@%s ***\007\n",
            timeleft ? "": "FINAL ", whom, hostname);
 
-       if (timeleft > 10*60) {
-               struct tm *tm = localtime(&shuttime);
-
-               dprintf(fd[1], "System going down at %d:%02d\n\n",
-                   tm->tm_hour, tm->tm_min);
+       if (timeleft > 10 * 60) {
+               shuttime = time(NULL) + timeleft;
+               lt = localtime(&shuttime);
+               if (lt != NULL) {
+                       strftime(when, sizeof(when), "%H:%M %Z", lt);
+                       dprintf(fd[1], "System going down at %s\n\n", when);
+               } else {
+                       dprintf(fd[1], "System going down in %lld hour%s\n\n",
+                           (long long)(timeleft / 3600),
+                           (timeleft >= 7200) ? "s" : "");
+               }
        } else if (timeleft > 59) {
                dprintf(fd[1], "System going down in %lld minute%s\n\n",
                    (long long)(timeleft / 60), (timeleft > 60) ? "s" : "");
@@ -464,6 +475,7 @@ die_you_gravy_sucking_pig_dog(void)
 void
 getoffset(char *timearg)
 {
+       char when[64];
        const char *errstr;
        struct tm *lt;
        int this_year;
@@ -475,13 +487,11 @@ getoffset(char *timearg)
                return;
        }
 
-       (void)time(&now);
        if (timearg[0] == '+') {                        /* +minutes */
                minutes = strtonum(timearg, 0, INT_MAX, &errstr);
                if (errstr)
                        errx(1, "relative offset is %s: %s", errstr, timearg);
                offset = minutes * 60;
-               shuttime = now + offset;
                return;
        }
 
@@ -498,6 +508,7 @@ getoffset(char *timearg)
        }
 
        unsetenv("TZ");                                 /* OUR timezone */
+       time(&now);
        lt = localtime(&now);                           /* current time val */
 
        switch (strlen(timearg)) {
@@ -534,8 +545,10 @@ getoffset(char *timearg)
                lt->tm_sec = 0;
                if ((shuttime = mktime(lt)) == -1)
                        badtime();
-               if ((offset = shuttime - now) < 0)
-                       errx(1, "that time is already past.");
+               if ((offset = shuttime - now) < 0) {
+                       strftime(when, sizeof(when), "%a %b %e %T %Z %Y", lt);
+                       errx(1, "time is already past: %s", when);
+               }
                break;
        default:
                badtime();
@@ -555,22 +568,23 @@ doitfast(void)
 }
 
 void
-nolog(void)
+nolog(time_t timeleft)
 {
-       int logfd;
+       char when[64];
        struct tm *tm;
+       int logfd;
 
        (void)unlink(_PATH_NOLOGIN);    /* in case linked to another file */
        (void)signal(SIGINT, finish);
        (void)signal(SIGHUP, finish);
        (void)signal(SIGQUIT, finish);
        (void)signal(SIGTERM, finish);
+       shuttime = time(NULL) + timeleft;
        tm = localtime(&shuttime);
        if (tm && (logfd = open(_PATH_NOLOGIN, O_WRONLY|O_CREAT|O_TRUNC,
            0664)) >= 0) {
-               dprintf(logfd,
-                   "\n\nNO LOGINS: System going down at %d:%02d\n\n",
-                   tm->tm_hour, tm->tm_min);
+               strftime(when, sizeof(when), "at %H:%M %Z", tm);
+               dprintf(logfd, "\n\nNO LOGINS: System going down %s\n\n", when);
                close(logfd);
        }
 }

Reply via email to