Module Name: src Committed By: kre Date: Sat Jan 26 15:19:08 UTC 2019
Modified Files: src/bin/sleep: sleep.1 sleep.c Log Message: Adjust the way the arg string is parsed in the "not entirely integer" case, so we avoid adjusting the locale of sleep, and generally be more reliable and simpler. In addition, deal with weirdness in nanosleep() when the interval gets long, by avoiding using it. In this version when the sleep interval < 10000 seconds, we use nanosleep() as before, for delays longer than that we use sleep() instead, and ignore any fractional seconds. We avoid overflow problems here by not bothering to sleep at all for delays longer than 135 years (approx) and simply pause() instead. That sleep never terminates in such a case is unlikely to ever be observed. This commit makes no decision on the question of whether the arg should be interpreted in the locale of the user, or always in the C locale. That is for another day. To generate a diff of this commit: cvs rdiff -u -r1.24 -r1.25 src/bin/sleep/sleep.1 cvs rdiff -u -r1.25 -r1.26 src/bin/sleep/sleep.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/bin/sleep/sleep.1 diff -u src/bin/sleep/sleep.1:1.24 src/bin/sleep/sleep.1:1.25 --- src/bin/sleep/sleep.1:1.24 Mon Jul 3 21:33:24 2017 +++ src/bin/sleep/sleep.1 Sat Jan 26 15:19:08 2019 @@ -1,4 +1,4 @@ -.\" $NetBSD: sleep.1,v 1.24 2017/07/03 21:33:24 wiz Exp $ +.\" $NetBSD: sleep.1,v 1.25 2019/01/26 15:19:08 kre Exp $ .\" .\" Copyright (c) 1990, 1993, 1994 .\" The Regents of the University of California. All rights reserved. @@ -32,7 +32,7 @@ .\" .\" @(#)sleep.1 8.3 (Berkeley) 4/18/94 .\" -.Dd August 12, 2016 +.Dd January 26, 2019 .Dt SLEEP 1 .Os .Sh NAME @@ -44,9 +44,9 @@ .Sh DESCRIPTION The .Nm -utility -suspends execution for a minimum of -.Ar seconds . +utility suspends execution for a minimum of +.Ar seconds +seconds, then exits. It is usually used to schedule the execution of other commands (see .Sx EXAMPLES below). @@ -55,12 +55,24 @@ Note: The .Nx .Nm command will accept and honor a non-integer number of specified seconds. -This is a non-portable extension, and its use will nearly guarantee that -a shell script will not execute properly on another system. +Note however, that if the request is for much more than 2.5 hours, +any fractional seconds will be ignored. +Permitting non-integral delays is a non-portable extension, +and its use will decrease the probability that +a shell script will execute properly on another system. +.Pp +If the request is for more than a little over 135 years +.Nm +will pause forever. +If the computer is still running when the +.Nm +should have terminated, +.Nm +will need to be killed by outside intervention. .Pp When the .Dv SIGINFO -signal is received, the estimate of the amount of seconds left to +signal is received, an estimate of the number of seconds remaining to sleep is printed on the standard output. .Sh EXIT STATUS The @@ -77,15 +89,16 @@ An error occurred. .Sh EXAMPLES To schedule the execution of a command for 1800 seconds later: .Pp -.Dl (sleep 1800; sh command_file >& errors)& +.Dl (sleep 1800; sh command_file >errors 2>&1)& .Pp This incantation would wait half an hour before -running the script command_file. +running the script +.Dq command_file . (See the .Xr at 1 utility.) .Pp -To reiteratively run a command (with +To repeatedly run a command (using .Xr csh 1 ) : .Pp .Bd -literal -offset indent -compact @@ -107,12 +120,36 @@ running is taking longer than expected t files, and it would be nice to have another program start processing the files created by the first program as soon as it is finished (when zzz.rawdata is created). -The script checks every five minutes for the file zzz.rawdata, -when the file is found, then another portion processing +The script checks every five minutes for the file zzz.rawdata. +When the file is found, processing the generated files (*.rawdata) is done courteously by sleeping for 70 seconds in between each awk job. +.Pp +To wait until a particular time, the following, +with some error checking added, might be used (using +.Xr sh 1 +on +.Nx ) : +.Bd -literal -offset indent +END=$(( $( date -d "$1" +%s ) - START_TIME )) +while [ "${SECONDS}" -lt "${END}" ] +do + sleep "$((END - SECONDS))" +done +.Ed +.Pp +where the argument +.Sq \&$1 +specifies the desired date and time in any format the +.Fl d +option to the +.Xr date 1 +command accepts. .Sh SEE ALSO .Xr at 1 , +.Xr csh 1 , +.Xr date 1 , +.Xr sh 1 , .Xr nanosleep 2 , .Xr sleep 3 .Sh STANDARDS @@ -126,3 +163,7 @@ A .Nm utility appeared in .At v4 . +Processing fractional seconds, and processing the +.Ic seconds +argument respecting the current locale, was added in +.Nx 1.3 . Index: src/bin/sleep/sleep.c diff -u src/bin/sleep/sleep.c:1.25 src/bin/sleep/sleep.c:1.26 --- src/bin/sleep/sleep.c:1.25 Sat Jan 19 13:27:12 2019 +++ src/bin/sleep/sleep.c Sat Jan 26 15:19:08 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: sleep.c,v 1.25 2019/01/19 13:27:12 kre Exp $ */ +/* $NetBSD: sleep.c,v 1.26 2019/01/26 15:19:08 kre Exp $ */ /* * Copyright (c) 1988, 1993, 1994 @@ -39,7 +39,7 @@ __COPYRIGHT("@(#) Copyright (c) 1988, 19 #if 0 static char sccsid[] = "@(#)sleep.c 8.3 (Berkeley) 4/2/94"; #else -__RCSID("$NetBSD: sleep.c,v 1.25 2019/01/19 13:27:12 kre Exp $"); +__RCSID("$NetBSD: sleep.c,v 1.26 2019/01/26 15:19:08 kre Exp $"); #endif #endif /* not lint */ @@ -56,6 +56,8 @@ __RCSID("$NetBSD: sleep.c,v 1.25 2019/01 __dead static void alarmhandle(int); __dead static void usage(void); +static void report(const time_t, const time_t, const char *const); + static volatile sig_atomic_t report_requested; static void report_request(int signo __unused) @@ -72,7 +74,8 @@ main(int argc, char *argv[]) double fval, ival, val; struct timespec ntime; time_t original; - int ch, fracflag, rv; + int ch, fracflag; + unsigned delay; setprogname(argv[0]); (void)setlocale(LC_ALL, ""); @@ -117,23 +120,24 @@ main(int argc, char *argv[]) if (fracflag) { /* - * If the radix char in the arg was a '.' - * (as is likely when used from scripts, etc) - * then force the C locale, so atof() works - * as intended, even if the user's locale - * expects something different, like ',' - * (but leave the locale alone otherwise, so if - * the user entered 2,4 and that is correct for - * the locale, it will work). + * If we cannot convert the value using the user's locale + * then try again using the C locale, so strtod() can always + * parse values like 2.5, even if the user's locale uses + * a different decimal radix character (like ',') + * + * (but only if that is the potential problem) */ - if (ch == '.') - (void)setlocale(LC_ALL, "C"); val = strtod(arg, &temp); + if (*temp != '\0') + val = strtod_l(arg, &temp, LC_C_LOCALE); if (val < 0 || temp == arg || *temp != '\0') usage(); ival = floor(val); fval = (1000000000 * (val-ival)); - ntime.tv_sec = ival; + if (ival >= (double)UINT_MAX) + ntime.tv_sec = (double)UINT_MAX; + else + ntime.tv_sec = ival; ntime.tv_nsec = fval; if (ntime.tv_sec == 0 && ntime.tv_nsec == 0) return EXIT_SUCCESS; /* was 0.0 or underflowed */ @@ -153,31 +157,57 @@ main(int argc, char *argv[]) msg = ""; signal(SIGINFO, report_request); - while ((rv = nanosleep(&ntime, &ntime)) != 0) { - if (report_requested) { - /* Reporting does not bother (much) with nanoseconds. */ - if (ntime.tv_sec == 0) - warnx("in the final moments of the original" - " %ld%s second%s", (long)original, msg, - original == 1 && *msg == '\0' ? "" : "s"); - else - warnx("between %ld and %ld seconds left" - " out of the original %ld%s", - (long)ntime.tv_sec, (long)ntime.tv_sec + 1, - (long)original, msg); - - report_requested = 0; - } else - break; - } - if (rv == -1) - err(EXIT_FAILURE, "nanosleep failed"); + if (ntime.tv_sec <= 10000) { /* arbitrary */ + while (nanosleep(&ntime, &ntime) != 0) { + if (report_requested) { + report(ntime.tv_sec, original, msg); + report_requested = 0; + } else + err(EXIT_FAILURE, "nanosleep failed"); + } + } else { + delay = (unsigned long)ntime.tv_sec; + + if ((time_t)delay != ntime.tv_sec || + delay > UINT_MAX - 86400) { + for (;;) { + pause(); + if (report_requested) { + warnx("Waiting for the end of time"); + report_requested = 0; + } else + break; + } + } else { + while ((delay = sleep(delay)) != 0) { + if (report_requested) { + report((time_t)delay, original, ""); + report_requested = 0; + } else + break; + } + } + } return EXIT_SUCCESS; /* NOTREACHED */ } + /* Reporting does not bother with nanoseconds. */ +static void +report(const time_t remain, const time_t original, const char * const msg) +{ + if (remain == 0) + warnx("In the final moments of the original" + " %ld%s second%s", (long)original, msg, + original == 1 && *msg == '\0' ? "" : "s"); + else + warnx("Between %ld and %ld seconds left" + " out of the original %ld%s", + remain, remain + 1, (long)original, msg); +} + static void usage(void) {