Sun Mar 10 15:18:45 2019 UTC ()
Deal with overflow when the sleep duration given is a simple
integer (previously it was just clamped at the max possible value).
This would have caused
	sleep 10000000000000000000
(or anything bigger) to have only actually slept for 9223372036854775807
secs.   Someone would have noticed that happen, one day, in some other
universe.

This is now an error, as it was previously if this had been entered as
	sleep 1e19

Also detect an attempt to sleep for so long that a time_t will no longer
be able to represent the current time when the sleep is done.

Undo the attempts to work around a broken kernel nanosleep()
implementation (by only ever issuing shortish sleep requests,
and looping).   That code was broken (idiot botch of mine) though
you would have had to wait a month to observe it happen.  I was going
to just fix it, but sanity prevailed, and the kernel got fixed instead.

That allows this to be much simplified, only looping as needed to
handle dealing with SIGINFO.   Switch to using clock_nanosleep()
to implement the delay, as while our nanosleep() uses CLOCK_MONOTONIC
the standards say it should use CLOCK_REALTIME, and if that we
ever changed that, the old way would alter "sleep 5" from
"sleep for 5 seconds" to "sleep until now + 5 secs", which is
subtly different.

Always use %g format to print the original sleep duration in reports of how
much time remains - this works best for both long and short durations.
A couple of other minor (frill) mods to the SIGINFO report message as well.


(kre)
diff -r1.29 -r1.30 src/bin/sleep/sleep.c

cvs diff -r1.29 -r1.30 src/bin/sleep/sleep.c (expand / switch to unified diff)

--- src/bin/sleep/sleep.c 2019/01/27 02:00:45 1.29
+++ src/bin/sleep/sleep.c 2019/03/10 15:18:45 1.30
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: sleep.c,v 1.29 2019/01/27 02:00:45 christos Exp $ */ 1/* $NetBSD: sleep.c,v 1.30 2019/03/10 15:18:45 kre Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 1988, 1993, 1994 4 * Copyright (c) 1988, 1993, 1994
5 * The Regents of the University of California. All rights reserved. 5 * The Regents of the University of California. All rights reserved.
6 * 6 *
7 * Redistribution and use in source and binary forms, with or without 7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions 8 * modification, are permitted provided that the following conditions
9 * are met: 9 * are met:
10 * 1. Redistributions of source code must retain the above copyright 10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer. 11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright 12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the 13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution. 14 * documentation and/or other materials provided with the distribution.
@@ -29,63 +29,66 @@ @@ -29,63 +29,66 @@
29 * SUCH DAMAGE. 29 * SUCH DAMAGE.
30 */ 30 */
31 31
32#include <sys/cdefs.h> 32#include <sys/cdefs.h>
33#ifndef lint 33#ifndef lint
34__COPYRIGHT("@(#) Copyright (c) 1988, 1993, 1994\ 34__COPYRIGHT("@(#) Copyright (c) 1988, 1993, 1994\
35 The Regents of the University of California. All rights reserved."); 35 The Regents of the University of California. All rights reserved.");
36#endif /* not lint */ 36#endif /* not lint */
37 37
38#ifndef lint 38#ifndef lint
39#if 0 39#if 0
40static char sccsid[] = "@(#)sleep.c 8.3 (Berkeley) 4/2/94"; 40static char sccsid[] = "@(#)sleep.c 8.3 (Berkeley) 4/2/94";
41#else 41#else
42__RCSID("$NetBSD: sleep.c,v 1.29 2019/01/27 02:00:45 christos Exp $"); 42__RCSID("$NetBSD: sleep.c,v 1.30 2019/03/10 15:18:45 kre Exp $");
43#endif 43#endif
44#endif /* not lint */ 44#endif /* not lint */
45 45
46#include <ctype.h> 46#include <ctype.h>
47#include <err.h> 47#include <err.h>
 48#include <errno.h>
48#include <locale.h> 49#include <locale.h>
49#include <math.h> 50#include <math.h>
50#include <signal.h> 51#include <signal.h>
51#include <stdio.h> 52#include <stdio.h>
52#include <stdlib.h> 53#include <stdlib.h>
 54#include <string.h>
53#include <time.h> 55#include <time.h>
54#include <unistd.h> 56#include <unistd.h>
55 57
56__dead static void alarmhandle(int); 58__dead static void alarmhandle(int);
57__dead static void usage(void); 59__dead static void usage(void);
58 60
59static void report(const time_t, const time_t, const char *const); 61static void report(const time_t, const time_t, const char *const);
60 62
61static volatile sig_atomic_t report_requested; 63static volatile sig_atomic_t report_requested;
62static void 64static void
63report_request(int signo __unused) 65report_request(int signo __unused)
64{ 66{
65 67
66 report_requested = 1; 68 report_requested = 1;
67} 69}
68 70
69int 71int
70main(int argc, char *argv[]) 72main(int argc, char *argv[])
71{ 73{
72 char *arg, *temp; 74 char *arg, *temp;
73 const char *msg; 75 const char *msg;
74 double fval, ival, val; 76 double fval, ival, val;
75 struct timespec ntime; 77 struct timespec ntime;
 78 struct timespec endtime;
 79 struct timespec now;
76 time_t original; 80 time_t original;
77 int ch, fracflag; 81 int ch, fracflag;
78 unsigned delay; 
79 82
80 setprogname(argv[0]); 83 setprogname(argv[0]);
81 (void)setlocale(LC_ALL, ""); 84 (void)setlocale(LC_ALL, "");
82 85
83 (void)signal(SIGALRM, alarmhandle); 86 (void)signal(SIGALRM, alarmhandle);
84 87
85 while ((ch = getopt(argc, argv, "")) != -1) 88 while ((ch = getopt(argc, argv, "")) != -1)
86 switch(ch) { 89 switch(ch) {
87 default: 90 default:
88 usage(); 91 usage();
89 } 92 }
90 argc -= optind; 93 argc -= optind;
91 argv += optind; 94 argv += optind;
@@ -135,91 +138,104 @@ main(int argc, char *argv[]) @@ -135,91 +138,104 @@ main(int argc, char *argv[])
135 if (val < 0 || temp == arg || *temp != '\0') 138 if (val < 0 || temp == arg || *temp != '\0')
136 usage(); 139 usage();
137 140
138 ival = floor(val); 141 ival = floor(val);
139 fval = (1000000000 * (val-ival)); 142 fval = (1000000000 * (val-ival));
140 ntime.tv_sec = ival; 143 ntime.tv_sec = ival;
141 if ((double)ntime.tv_sec != ival) 144 if ((double)ntime.tv_sec != ival)
142 errx(1, "requested delay (%s) out of range", arg); 145 errx(1, "requested delay (%s) out of range", arg);
143 ntime.tv_nsec = fval; 146 ntime.tv_nsec = fval;
144 147
145 if (ntime.tv_sec == 0 && ntime.tv_nsec == 0) 148 if (ntime.tv_sec == 0 && ntime.tv_nsec == 0)
146 return EXIT_SUCCESS; /* was 0.0 or underflowed */ 149 return EXIT_SUCCESS; /* was 0.0 or underflowed */
147 } else { 150 } else {
 151 errno = 0;
148 ntime.tv_sec = strtol(arg, &temp, 10); 152 ntime.tv_sec = strtol(arg, &temp, 10);
149 if (ntime.tv_sec < 0 || temp == arg || *temp != '\0') 153 if (ntime.tv_sec < 0 || temp == arg || *temp != '\0')
150 usage(); 154 usage();
 155 if (errno == ERANGE)
 156 errx(EXIT_FAILURE, "Requested delay (%s) out of range",
 157 arg);
 158 else if (errno != 0)
 159 err(EXIT_FAILURE, "Requested delay (%s)", arg);
151 160
152 if (ntime.tv_sec == 0) 161 if (ntime.tv_sec == 0)
153 return EXIT_SUCCESS; 162 return EXIT_SUCCESS;
154 ntime.tv_nsec = 0; 163 ntime.tv_nsec = 0;
155 } 164 }
156 165
157 original = ntime.tv_sec; 166 original = ntime.tv_sec;
158 if (ntime.tv_nsec != 0) 167 if (original < 86400) {
159 msg = " and a bit"; 168 if (ntime.tv_nsec > 1000000000 * 2 / 3) {
160 else 169 original++;
 170 msg = " less a bit";
 171 } else if (ntime.tv_nsec != 0)
 172 msg = " and a bit";
 173 else
 174 msg = "";
 175 } else
161 msg = ""; 176 msg = "";
162 177
 178 if (clock_gettime(CLOCK_MONOTONIC, &now) != 0)
 179 err(EXIT_FAILURE, "clock_gettime");
 180 timespecadd(&now, &ntime, &endtime);
 181
 182 if (endtime.tv_sec < now.tv_sec || (endtime.tv_sec == now.tv_sec &&
 183 endtime.tv_nsec <= now.tv_nsec))
 184 errx(EXIT_FAILURE, "cannot sleep beyond the end of time");
 185
163 signal(SIGINFO, report_request); 186 signal(SIGINFO, report_request);
 187 for (;;) {
 188 int e;
 189
 190 if ((e = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME,
 191 &endtime, NULL)) == 0)
 192 return EXIT_SUCCESS;
164 193
165 if (ntime.tv_sec <= 10000) { /* arbitrary */ 194 if (!report_requested || e != EINTR) {
166 while (nanosleep(&ntime, &ntime) != 0) { 195 errno = e;
167 if (report_requested) { 196 err(EXIT_FAILURE, "clock_nanotime");
168 report(ntime.tv_sec, original, msg); 
169 report_requested = 0; 
170 } else 
171 err(EXIT_FAILURE, "nanosleep failed"); 
172 } 197 }
173 } else while (ntime.tv_sec > 0) { 
174 delay = (unsigned int)ntime.tv_sec; 
175 198
176 if ((time_t)delay != ntime.tv_sec || delay > 30 * 86400) 199 report_requested = 0;
177 delay = 30 * 86400; 200 if (clock_gettime(CLOCK_MONOTONIC, &now) != 0) /* Huh? */
 201 continue;
178 202
179 ntime.tv_sec -= delay; 203 timespecsub(&endtime, &now, &ntime);
180 delay = sleep(delay); 204 report(ntime.tv_sec, original, msg);
181 ntime.tv_sec += delay; 
182 
183 if (delay != 0 && report_requested) { 
184 report(ntime.tv_sec, original, ""); 
185 report_requested = 0; 
186 } else 
187 break; 
188 } 205 }
189 
190 return EXIT_SUCCESS; 
191 /* NOTREACHED */ 
192} 206}
193 207
194 /* Reporting does not bother with nanoseconds. */ 208 /* Reporting does not bother with nanoseconds. */
195static void 209static void
196report(const time_t remain, const time_t original, const char * const msg) 210report(const time_t remain, const time_t original, const char * const msg)
197{ 211{
198 if (remain == 0) 212 if (remain == 0)
199 warnx("In the final moments of the original" 213 warnx("In the final moments of the original"
200 " %jd%s second%s", (intmax_t)original, msg, 214 " %g%s second%s", (double)original, msg,
201 original == 1 && *msg == '\0' ? "" : "s"); 215 original == 1 && *msg == '\0' ? "" : "s");
202 else if (remain < 2000) 216 else if (remain < 2000)
203 warnx("Between %jd and %jd seconds left" 217 warnx("Between %jd and %jd seconds left"
204 " out of the original %g%s", 218 " out of the original %g%s",
205 (intmax_t)remain, (intmax_t)remain + 1, (double)original, 219 (intmax_t)remain, (intmax_t)remain + 1, (double)original,
206 msg); 220 msg);
207 else if ((original - remain) < 100000 && (original-remain) < original/8) 221 else if ((original - remain) < 100000 && (original-remain) < original/8)
208 warnx("Have waited only %jd seconds of the original %g", 222 warnx("Have waited only %jd second%s of the original %g%s",
209 (intmax_t)(original - remain), (double)original); 223 (intmax_t)(original - remain),
 224 (original - remain) == 1 ? "" : "s",
 225 (double)original, msg);
210 else 226 else
211 warnx("Approximately %g seconds left out of the original %g", 227 warnx("Approximately %g seconds left out of the original %g%s",
212 (double)remain, (double)original); 228 (double)remain, (double)original, msg);
213} 229}
214 230
215static void 231static void
216usage(void) 232usage(void)
217{ 233{
218 (void)fprintf(stderr, "usage: %s seconds\n", getprogname()); 234 (void)fprintf(stderr, "usage: %s seconds\n", getprogname());
219 exit(EXIT_FAILURE); 235 exit(EXIT_FAILURE);
220 /* NOTREACHED */ 236 /* NOTREACHED */
221} 237}
222 238
223/* ARGSUSED */ 239/* ARGSUSED */
224static void 240static void
225alarmhandle(int i) 241alarmhandle(int i)