[prev in list] [next in list] [prev in thread] [next in thread] 

List:       openbsd-tech
Subject:    Re: shutdown: simplify countdown loop()
From:       Scott Cheloha <scottcheloha () gmail ! com>
Date:       2018-02-25 22:51:22
Message-ID: 20180225225122.fjufvchqmk26nobo () rascal ! austin ! ibm ! com
[Download RAW message or body]

On Sun, Feb 25, 2018 at 10:42:04AM +0100, Theo Buehler wrote:
> On Sat, Feb 24, 2018 at 06:25:44PM -0600, Scott Cheloha wrote:
> > [...]
> > 
> > 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(). [...]
> > 
> > ok?
> 
> Yes, I think that's easier to follow. Two questions below.
>
> > 
> > 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;
> 
> Should we suffix a constant with LL in the multipliers H, M, S so
> we get correct overflow handling in the initializations below (not
> currently an issue).

If I'm understanding you correctly, no.  We're nowhere near INT_MAX,
and these decimal constants are ints as they lack the suffix.

And even if we did something crazy, like add an interval like this:

	{ 596524 H, 0 }

which just barely overflows a 32-bit type, on amd64 clang gives me:

	cc -O2 -pipe  -Werror-implicit-function-declaration -MD -MP  -c /usr/src/sbin/shutdown/shutdown.c
	/usr/src/sbin/shutdown/shutdown.c:70:11: warning: overflow in expression; result
	      is -2147480896 with type 'int' [-Winteger-overflow]
	        { 596524 H,    0 },
	                 ^
	/usr/src/sbin/shutdown/shutdown.c:62:15: note: expanded from macro 'H'
	#define H               *60*60
	                           ^
	1 warning generated.
	cc  -static -pie -o shutdown shutdown.o 

and on macppc, gcc gives me:

	cc -O2 -pipe  -Werror-implicit-function-declaration -MD -MP  -c /usr/src/sbin/shutdown/shutdown.c
	/usr/src/sbin/shutdown/shutdown.c:69: warning: integer overflow in expression
	cc  -static -pie -o shutdown shutdown.o 

which, while not as glaringly obvious as clang's warning, is
sufficient, I think.

> > [...]
> > @@ -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",
> 
> Wouldn't it be better to use an %lld format and leave the next line as
> it is?

Yes, we ought to use %lld, if only because code tends to move around.

But we can't leave the expression uncasted.  time_t has no dedicated
format specifier so we need an explicit cast.  At least, I've never
seen one in base printed without a cast.  And I suspect that such code
wouldn't be portable.

Updated diff attached.

--
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	25 Feb 2018 22:44:39 -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;
@@ -319,10 +320,10 @@ timewarn(int timeleft)
 
 		dprintf(fd[1], "System going down at %d:%02d\n\n",
 		    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" : "");
-	else if (timeleft)
+	} else if (timeleft > 59) {
+		dprintf(fd[1], "System going down in %lld minute%s\n\n",
+		    (long long)(timeleft / 60), (timeleft > 60) ? "s" : "");
+	} else if (timeleft)
 		dprintf(fd[1], "System going down in 30 seconds\n\n");
 	else
 		dprintf(fd[1], "System going down IMMEDIATELY\n\n");

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic