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