Hey,

If we treat tlist[] like an array instead of a list, we can
eliminate a lot of special cases and duplicate calls in shutdown(8)'s
countdown loop().

We add a spare index at the beginning of tlist[] to accomodate
offsets greater than 10 hours and insert our offset into tlist[]
in an initial loop.  With that done we can cut out all of the
duplicate calls and most of the extra logic and invoke timewarn(),
nolog(), and sleep() once each in a master countdown loop.

While we're here I think we ought to make everything in tlist[] a
time_t to eliminate the casting in loop().  offset is a time_t, so
there's just less type friction.  It also makes things simpler for
some later diffs I have planned.  But so, int -> time_t, hence
sleep -> nanosleep.

ok?

--
Scott Cheloha

Index: sbin/shutdown/shutdown.c
===================================================================
RCS file: /cvs/src/sbin/shutdown/shutdown.c,v
retrieving revision 1.48
diff -u -p -r1.48 shutdown.c
--- sbin/shutdown/shutdown.c    24 Feb 2018 20:00:07 -0000      1.48
+++ sbin/shutdown/shutdown.c    24 Feb 2018 23:57:54 -0000
@@ -64,8 +64,10 @@
 #define        S               *1
 #define        NOLOG_TIME      5*60
 struct interval {
-       int timeleft, timetowait;
+       time_t timeleft;
+       time_t timetowait;
 } tlist[] = {
+       {    0,    0 },
        { 10 H,  5 H },
        {  5 H,  3 H },
        {  2 H,  1 H },
@@ -79,6 +81,7 @@ struct interval {
        { 30 S, 30 S },
        {    0,    0 }
 };
+const int tlistlen = { sizeof(tlist) / sizeof(tlist[0]) };
 #undef H
 #undef M
 #undef S
@@ -96,7 +99,7 @@ void getoffset(char *);
 void __dead loop(void);
 void nolog(void);
 void timeout(int);
-void timewarn(int);
+void timewarn(time_t);
 void usage(void);
 
 int
@@ -229,40 +232,38 @@ main(int argc, char *argv[])
 void
 loop(void)
 {
-       struct interval *tp;
-       u_int sltime;
-       int logged;
-
-       if (offset <= NOLOG_TIME) {
-               logged = 1;
-               nolog();
-       } else
-               logged = 0;
-       tp = tlist;
-       if (tp->timeleft < offset)
-               (void)sleep((u_int)(offset - tp->timeleft));
-       else {
-               while (offset < tp->timeleft)
-                       ++tp;
-               /*
-                * Warn now, if going to sleep more than a fifth of
-                * the next wait time.
-                */
-               if ((sltime = offset - tp->timeleft)) {
-                       if (sltime > tp->timetowait / 5)
-                               timewarn(offset);
-                       (void)sleep(sltime);
+       struct timespec timeout;
+       int broadcast, i, logged;
+
+       broadcast = 1;
+
+       for (i = 0; i < tlistlen - 1; i++) {
+               if (offset > tlist[i + 1].timeleft) {
+                       tlist[i].timeleft = offset;
+                       tlist[i].timetowait = offset - tlist[i + 1].timeleft;
+                       break;
                }
        }
-       for (;; ++tp) {
-               timewarn(tp->timeleft);
-               if (!logged && tp->timeleft <= NOLOG_TIME) {
+
+       /*
+        * Don't spam the users: skip our offset's warning broadcast if
+        * there's a broadcast scheduled after ours and it's relatively
+        * imminent.
+        */
+       if (offset > 0 && tlist[i].timetowait < tlist[i + 1].timetowait / 5)
+               broadcast = 0;
+
+       for (logged = 0; i < tlistlen; i++) {
+               if (broadcast)
+                       timewarn(tlist[i].timeleft);
+               broadcast = 1;
+               if (!logged && tlist[i].timeleft <= NOLOG_TIME) {
                        logged = 1;
                        nolog();
                }
-               (void)sleep((u_int)tp->timetowait);
-               if (!tp->timeleft)
-                       break;
+               timeout.tv_sec = tlist[i].timetowait;
+               timeout.tv_nsec = 0;
+               nanosleep(&timeout, NULL);
        }
        die_you_gravy_sucking_pig_dog();
 }
@@ -273,7 +274,7 @@ static char *restricted_environ[] = {
 };
 
 void
-timewarn(int timeleft)
+timewarn(time_t timeleft)
 {
        static char hostname[HOST_NAME_MAX+1];
        static int first;
@@ -321,7 +322,7 @@ timewarn(int timeleft)
                    tm->tm_hour, tm->tm_min);
        } else if (timeleft > 59)
                dprintf(fd[1], "System going down in %d minute%s\n\n",
-                   timeleft / 60, (timeleft > 60) ? "s" : "");
+                   (int)(timeleft / 60), (timeleft > 60) ? "s" : "");
        else if (timeleft)
                dprintf(fd[1], "System going down in 30 seconds\n\n");
        else

Reply via email to