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

View File

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