timeout(1): Some minor tweaks and improvements

- Define exit status and macros and use them
- Improve the second kill logic by setting 'do_second_kill = false'
  after configuring the second kill
- Minor style tweaks
- Reorder options in the man page, as well as the usage help
- Reorder the exit status in the man page
- Enhance the HISTORY section in the man page (obtained from NetBSD)

Reviewed by:	bapt, Alexander Ziaee (manpages)
Approved by:	bapt (src)
Obtained from:	DragonFlyBSD
MFC after:	1 week
Differential Revision:	https://reviews.freebsd.org/D47866
This commit is contained in:
Gordon Bergling 2024-12-28 08:13:22 +01:00
parent 15ce9a0544
commit 06690044da
2 changed files with 60 additions and 41 deletions

View file

@ -24,7 +24,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.Dd June 17, 2024
.Dd December 28, 2024
.Dt TIMEOUT 1
.Os
.Sh NAME
@ -32,10 +32,11 @@
.Nd run a command with a time limit
.Sh SYNOPSIS
.Nm
.Op Fl -signal Ar sig | Fl s Ar sig
.Op Fl -preserve-status
.Op Fl k Ar time | Fl -kill-after Ar time
.Op Fl s Ar sig | Fl -signal Ar sig
.Op Fl -kill-after Ar time | Fl k Ar time
.Op Fl -foreground
.Op Fl -preserve-status
.Ar duration
.Ar command
.Op Ar args ...
@ -62,18 +63,6 @@ is 0.
.Pp
The options are as follows:
.Bl -tag -width indent
.It Fl -preserve-status
Exit with the same status as
.Ar command ,
even if it times out and is killed.
.It Fl -foreground
Do not propagate timeout to the children of
.Ar command .
.It Fl s Ar sig , Fl -signal Ar sig
Specify the signal to send on timeout.
By default,
.Dv SIGTERM
is sent.
.It Fl k Ar time , Fl -kill-after Ar time
Send a
.Dv SIGKILL
@ -82,8 +71,21 @@ signal if
is still running after
.Ar time
after the first signal was sent.
.It Fl s Ar sig , Fl -signal Ar sig
Specify the signal to send on timeout.
By default,
.Dv SIGTERM
is sent.
.It Fl -foreground
Do not propagate timeout to the children of
.Ar command .
.It Fl -preserve-status
Exit with the same status as
.Ar command ,
even if it times out and is killed.
.El
.Sh DURATION FORMAT
The
.Ar duration
and
.Ar time
@ -92,7 +94,7 @@ unit-specifying suffix.
Values without an explicit unit are interpreted as seconds.
.Pp
Supported unit symbols are:
.Bl -tag -width indent -compact
.Bl -tag -offset indent -width indent -compact
.It Cm s
seconds
.It Cm m
@ -116,10 +118,15 @@ If
.Fl -preserve-status
is not set, an exit status of 124 is returned.
.Pp
If an invalid parameter is passed to
.Fl s
or
.Fl k ,
the exit status returned is 125.
.Pp
If
.Ar command
exits after receiving a signal, the exit status returned is the signal number
plus 128.
is an otherwise invalid program, the exit status returned is 126.
.Pp
If
.Ar command
@ -127,13 +134,8 @@ refers to a non-existing program, the exit status returned is 127.
.Pp
If
.Ar command
is an otherwise invalid program, the exit status returned is 126.
.Pp
If an invalid parameter is passed to
.Fl s
or
.Fl k ,
the exit status returned is 125.
exits after receiving a signal, the exit status returned is the signal number
plus 128.
.Sh EXAMPLES
Run
.Xr sleep 1
@ -206,6 +208,17 @@ The
.Nm
command first appeared in
.Fx 10.3 .
.Pp
The
.Fx
work is compatible with GNU
.Nm
by
.An Padraig Brady ,
from GNU Coreutils 8.21.
The
.Nm
utility first appeared in GNU Coreutils 7.0.
.Sh AUTHORS
.An Baptiste Daroussin Aq Mt bapt@FreeBSD.org
and

View file

@ -41,6 +41,9 @@
#include <unistd.h>
#define EXIT_TIMEOUT 124
#define EXIT_INVALID 125
#define EXIT_CMD_ERROR 126
#define EXIT_CMD_NOENT 127
static sig_atomic_t sig_chld = 0;
static sig_atomic_t sig_term = 0;
@ -51,9 +54,9 @@ static void
usage(void)
{
fprintf(stderr, "Usage: %s [--signal sig | -s sig] [--preserve-status]"
" [--kill-after time | -k time] [--foreground] <duration> <command>"
" <arg ...>\n", getprogname());
fprintf(stderr, "Usage: %s [-k time | --kill-after time]"
" [-s sig | --signal sig] [--foreground] [--preserve-status]"
" <duration> <command> <arg ...>\n", getprogname());
exit(EXIT_FAILURE);
}
@ -66,13 +69,13 @@ parse_duration(const char *duration)
ret = strtod(duration, &end);
if (ret == 0 && end == duration)
errx(125, "invalid duration");
errx(EXIT_INVALID, "invalid duration");
if (end == NULL || *end == '\0')
return (ret);
if (end != NULL && *(end + 1) != '\0')
errx(125, "invalid duration");
errx(EXIT_INVALID, "invalid duration");
switch (*end) {
case 's':
@ -87,11 +90,11 @@ parse_duration(const char *duration)
ret *= 60 * 60 * 24;
break;
default:
errx(125, "invalid duration");
errx(EXIT_INVALID, "invalid duration");
}
if (ret < 0 || ret >= 100000000UL)
errx(125, "invalid duration");
errx(EXIT_INVALID, "invalid duration");
return (ret);
}
@ -106,6 +109,7 @@ parse_signal(const char *str)
if (errstr == NULL)
return (sig);
if (strncasecmp(str, "SIG", 3) == 0)
str += 3;
@ -114,7 +118,7 @@ parse_signal(const char *str)
return (i);
}
errx(125, "invalid signal");
errx(EXIT_INVALID, "invalid signal");
}
static void
@ -149,7 +153,7 @@ set_interval(double iv)
memset(&tim, 0, sizeof(tim));
tim.it_value.tv_sec = (time_t)iv;
iv -= (time_t)iv;
iv -= (double)tim.it_value.tv_sec;
tim.it_value.tv_usec = (suseconds_t)(iv * 1000000UL);
if (setitimer(ITIMER_REAL, &tim, NULL) == -1)
@ -160,10 +164,10 @@ int
main(int argc, char **argv)
{
int ch;
unsigned long i;
int foreground, preserve;
int error, pstat, status;
int killsig = SIGTERM;
size_t i;
pid_t pid, cpid;
double first_kill;
double second_kill;
@ -240,11 +244,13 @@ main(int argc, char **argv)
signals.sa_handler = sig_handler;
signals.sa_flags = SA_RESTART;
for (i = 0; i < sizeof(signums) / sizeof(signums[0]); i++)
for (i = 0; i < sizeof(signums) / sizeof(signums[0]); i++) {
if (signums[i] != -1 && signums[i] != 0 &&
sigaction(signums[i], &signals, NULL) == -1)
err(EXIT_FAILURE, "sigaction()");
}
/* Don't stop if background child needs TTY */
signal(SIGTTIN, SIG_IGN);
signal(SIGTTOU, SIG_IGN);
@ -259,9 +265,9 @@ main(int argc, char **argv)
error = execvp(argv[0], argv);
if (error == -1) {
if (errno == ENOENT)
err(127, "exec(%s)", argv[0]);
err(EXIT_CMD_NOENT, "exec(%s)", argv[0]);
else
err(126, "exec(%s)", argv[0]);
err(EXIT_CMD_ERROR, "exec(%s)", argv[0]);
}
}
@ -294,7 +300,7 @@ main(int argc, char **argv)
break;
} else {
procctl(P_PID, getpid(),
PROC_REAP_STATUS, &info);
PROC_REAP_STATUS, &info);
if (info.rs_children == 0)
break;
}
@ -313,7 +319,7 @@ main(int argc, char **argv)
if (do_second_kill) {
set_interval(second_kill);
second_kill = 0;
do_second_kill = false;
sig_ign = killsig;
killsig = SIGKILL;
} else
@ -330,7 +336,7 @@ main(int argc, char **argv)
if (do_second_kill) {
set_interval(second_kill);
second_kill = 0;
do_second_kill = false;
sig_ign = killsig;
killsig = SIGKILL;
} else