bin/sleep: add support for multiple delay values

The sleep time is calculated as the sum of all arguments passed.

This makes the FreeBSD version of sleep functionally compatible with
the version in GNU coreutils.

MFC after:	1 week
This commit is contained in:
Stefan Eßer 2022-05-24 10:47:40 +02:00
parent 34978f7edd
commit be038c3afc
2 changed files with 40 additions and 26 deletions

View File

@ -32,7 +32,7 @@
.\" @(#)sleep.1 8.3 (Berkeley) 4/18/94
.\" $FreeBSD$
.\"
.Dd December 31, 2020
.Dd May 24, 2022
.Dt SLEEP 1
.Os
.Sh NAME
@ -40,21 +40,21 @@
.Nd suspend execution for an interval of time
.Sh SYNOPSIS
.Nm
.Ar number[unit]
.Ar number[unit] ...
.Sh DESCRIPTION
The
.Nm
command
suspends execution for a minimum of
command suspends execution for a minimum of
.Ar number
seconds (the default, or unit
.Ar s ) ,
or minutes (unit
minutes (unit
.Ar m ) ,
hours (unit
.Ar h ) ,
or days (unit
.Ar d ) .
If multiple arguments are passed, the delay will be the sum of all values.
.Pp
If the
.Nm
@ -72,9 +72,9 @@ The
.Nm
command allows and honors a non-integer number of seconds to sleep
in any form acceptable by
.Xr strtod 3 .
This is a non-portable extension, but is also implemented in GNU sh-utils
since version 2.0a (released in 2002).
.Xr strtod 3 and it accepts more than one delay value.
These are non-portable extensions, but they have also been implemented
in GNU sh-utils since version 2.0a (released in 2002).
.Sh EXIT STATUS
.Ex -std
.Sh EXAMPLES

View File

@ -64,34 +64,48 @@ int
main(int argc, char *argv[])
{
struct timespec time_to_sleep;
double d;
double d, seconds;
time_t original;
char unit;
char buf[2];
int i, matches;
if (caph_limit_stdio() < 0 || caph_enter() < 0)
err(1, "capsicum");
if (argc != 2)
if (argc < 2)
usage();
if (sscanf(argv[1], "%lf%c%1s", &d, &unit, buf) == 2)
switch(unit) {
case 'd': d *= 24;
case 'h': d *= 60;
case 'm': d *= 60;
case 's': break;
default: usage();
}
else
if (sscanf(argv[1], "%lf%1s", &d, buf) != 1)
usage();
if (d > INT_MAX)
seconds = 0;
for (i = 1; i < argc; i++) {
matches = sscanf(argv[i], "%lf%c%1s", &d, &unit, buf);
if (matches == 2)
switch(unit) {
case 'd':
d *= 24;
/* FALLTHROUGH */
case 'h':
d *= 60;
/* FALLTHROUGH */
case 'm':
d *= 60;
/* FALLTHROUGH */
case 's':
break;
default:
usage();
}
else
if (matches != 1)
usage();
seconds += d;
}
if (seconds > INT_MAX)
usage();
if (d <= 0)
if (seconds <= 0)
return (0);
original = time_to_sleep.tv_sec = (time_t)d;
time_to_sleep.tv_nsec = 1e9 * (d - time_to_sleep.tv_sec);
original = time_to_sleep.tv_sec = (time_t)seconds;
time_to_sleep.tv_nsec = 1e9 * (seconds - time_to_sleep.tv_sec);
signal(SIGINFO, report_request);
@ -116,7 +130,7 @@ static void
usage(void)
{
fprintf(stderr, "usage: sleep number[unit]\n");
fprintf(stderr, "usage: sleep number[unit] ...\n");
fprintf(stderr, "Unit can be 's' (seconds, the default), "
"m (minutes), h (hours), or d (days).\n");
exit(1);