Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/bin/sleep Adjust the way the arg string is parsed in the "no...



details:   https://anonhg.NetBSD.org/src/rev/5b983ee54aeb
branches:  trunk
changeset: 447841:5b983ee54aeb
user:      kre <kre%NetBSD.org@localhost>
date:      Sat Jan 26 15:19:08 2019 +0000

description:
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.

diffstat:

 bin/sleep/sleep.1 |  67 +++++++++++++++++++++++++++++++-------
 bin/sleep/sleep.c |  94 ++++++++++++++++++++++++++++++++++++------------------
 2 files changed, 116 insertions(+), 45 deletions(-)

diffs (275 lines):

diff -r 8b3f08814722 -r 5b983ee54aeb bin/sleep/sleep.1
--- a/bin/sleep/sleep.1 Sat Jan 26 15:12:20 2019 +0000
+++ b/bin/sleep/sleep.1 Sat Jan 26 15:19:08 2019 +0000
@@ -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 @@
 .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 @@
 .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 @@
 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 @@
 .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 .
diff -r 8b3f08814722 -r 5b983ee54aeb bin/sleep/sleep.c
--- a/bin/sleep/sleep.c Sat Jan 26 15:12:20 2019 +0000
+++ b/bin/sleep/sleep.c Sat Jan 26 15:19:08 2019 +0000
@@ -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 @@
 #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 @@
 __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 @@
        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 @@
 
        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 @@
                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);
+
+       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;
 
-                       report_requested = 0;
-               } else
-                       break;
+               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;
+                       }
+               }
        }
 
-       if (rv == -1)
-               err(EXIT_FAILURE, "nanosleep failed");
-
        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)
 {



Home | Main Index | Thread Index | Old Index