commit: 73156a211e8a46eff3b5d55ba11a1a90c602fea6
parent b5f83eb4ffa17d3c270176b3a35f0e36e2de15a9
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date: Wed, 30 Jul 2025 15:53:53 +0200
cmd/sleep: allow to chainload into another command
Diffstat:
3 files changed, 58 insertions(+), 24 deletions(-)
diff --git a/cmd/sleep.1 b/cmd/sleep.1
@@ -9,18 +9,28 @@
.Nd delay for a specified amount of time
.Sh SYNOPSIS
.Nm
-.Ar duration...
+.Ar duration
+.Op Ar command Op Ar argument...
.Sh DESCRIPTION
The
.Nm
-utily shall suspends execution for the total of each
-.Ar duration
-argument.
-.Pp
+utility shall suspends execution for the total of each
.Ar duration
-is a string containing non-negative decimal numbers including floats, terminated by a suffix: s for seconds, m for minutes, h for hours, d for days.
+argument
+and optionally execute into
+.Ar command .
+.Sh OPERANDS
+.Ss Ar duration
+A string containing non-negative decimal numbers including floats,
+terminated by a suffix: s for seconds, m for minutes, h for hours, d for days.
If the final number doesn't have a suffix it is assumed to be seconds.
Longer durations are taken as out of scope.
+.Ss Ar command
+When present sleep executes into
+.Ar command
+once
+.Ar duration
+elapsed.
.Sh EXIT STATUS
.Ex -std
.Sh SEE ALSO
@@ -32,5 +42,11 @@ Longer durations are taken as out of scope.
should be compliant with the
IEEE Std 1003.1-2024 (“POSIX.1”)
specification.
+.Sh HISTORY
+The
+.Ar command
+operand is inspired by s6-portable-utils and
+useful for chainloading environments like
+.Xr execline 1 .
.Sh AUTHORS
.An Haelwenn (lanodan) Monnier Aq Mt contact+utils@hacktivis.me
diff --git a/cmd/sleep.c b/cmd/sleep.c
@@ -5,9 +5,11 @@
#define _POSIX_C_SOURCE 200809L
#include "../libutils/strtodur.h"
-#include <errno.h> // errno
-#include <stdio.h> // fprintf, perror
-#include <time.h> // nanosleep
+#include <errno.h> // errno
+#include <stdio.h> // fprintf, perror
+#include <string.h> // strerror
+#include <time.h> // nanosleep
+#include <unistd.h> // execvp
const char *argv0 = "sleep";
@@ -16,21 +18,23 @@ main(int argc, char *argv[])
{
struct timespec dur = {.tv_sec = 0, .tv_nsec = 0};
- for(int i = 1; i < argc; i++)
+ argc--, argv++;
+
+ if(argc < 1)
{
- struct timespec arg_dur = {.tv_sec = 0, .tv_nsec = 0};
- if(strtodur(argv[i], &arg_dur) < 0)
- {
- return 1;
- }
+ fprintf(stderr, "sleep: error: No duration argument passed\n");
+ return 1;
+ }
- dur.tv_sec += arg_dur.tv_sec;
- dur.tv_nsec += arg_dur.tv_nsec;
- if(dur.tv_nsec > 999999999)
- {
- dur.tv_nsec = 0;
- dur.tv_sec += 1;
- }
+ struct timespec arg_dur = {.tv_sec = 0, .tv_nsec = 0};
+ if(strtodur(argv[0], &arg_dur) < 0) return 1;
+
+ dur.tv_sec += arg_dur.tv_sec;
+ dur.tv_nsec += arg_dur.tv_nsec;
+ if(dur.tv_nsec > 999999999)
+ {
+ dur.tv_nsec = 0;
+ dur.tv_sec += 1;
}
if(dur.tv_sec == 0 && dur.tv_nsec == 0)
{
@@ -38,6 +42,8 @@ main(int argc, char *argv[])
return 1;
}
+ argc--, argv++;
+
errno = 0;
if(nanosleep(&dur, &dur) != 0)
{
@@ -55,5 +61,15 @@ main(int argc, char *argv[])
}
}
+ if(argc > 0)
+ {
+ errno = 0;
+ execvp(argv[0], argv);
+
+ fprintf(stderr, "sleep: error: Failed executing command '%s': %s\n", argv[0], strerror(errno));
+
+ return (errno == ENOENT) ? 127 : 126;
+ }
+
return 0;
}
diff --git a/test-cmd/sleep.sh b/test-cmd/sleep.sh
@@ -2,14 +2,16 @@
# SPDX-FileCopyrightText: 2017 Haelwenn (lanodan) Monnier <contact+utils@hacktivis.me>
# SPDX-License-Identifier: MPL-2.0
+plans=4
target="$(dirname "$0")/../cmd/sleep"
-plans=3
. "$(dirname "$0")/tap.sh"
-t --exit=1 noargs '' 'sleep: error: Got a total duration of 0
+t --exit=1 noargs '' 'sleep: error: No duration argument passed
'
t --exit=1 zero '0' 'sleep: error: Got a total duration of 0
'
t zero-one 0.1 ''
+
+t_args chainload 'hello' 0.01 printf hello