version 1.1, 2021/09/01 15:50:33 |
version 1.2, 2021/09/01 16:00:48 |
|
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
*/ |
|
|
#include <sys/cdefs.h> |
#include <sys/types.h> |
#include <sys/time.h> |
#include <sys/time.h> |
#include <sys/wait.h> |
#include <sys/wait.h> |
|
|
|
|
#include <stdio.h> |
#include <stdio.h> |
#include <stdlib.h> |
#include <stdlib.h> |
#include <string.h> |
#include <string.h> |
#include <sysexits.h> |
|
#include <unistd.h> |
#include <unistd.h> |
|
|
#define EXIT_TIMEOUT 124 |
#define EXIT_TIMEOUT 124 |
|
|
static void __dead |
static void __dead |
usage(void) |
usage(void) |
{ |
{ |
fprintf(stderr, "Usage: %s [--signal sig | -s sig] [--preserve-status]" |
fprintf(stderr, "usage: timeout [-s sig] [-k time] [--preserve-status]" |
" [--kill-after time | -k time] [--foreground] <duration> <command>" |
" [--foreground] duration command\n"); |
" <arg ...>\n", getprogname()); |
|
|
|
exit(EX_USAGE); |
exit(1); |
} |
} |
|
|
static double |
static double |
|
|
|
|
ret = strtod(duration, &end); |
ret = strtod(duration, &end); |
if (ret == 0 && end == duration) |
if (ret == 0 && end == duration) |
errx(EXIT_FAILURE, "invalid duration"); |
err(1, "invalid duration"); |
|
|
if (end == NULL || *end == '\0') |
if (end == NULL || *end == '\0') |
return (ret); |
return (ret); |
|
|
if (end != NULL && *(end + 1) != '\0') |
if (end != NULL && *(end + 1) != '\0') |
errx(EX_USAGE, "invalid duration"); |
err(1, "invalid duration"); |
|
|
switch (*end) { |
switch (*end) { |
case 's': |
case 's': |
|
|
ret *= 60 * 60 * 24; |
ret *= 60 * 60 * 24; |
break; |
break; |
default: |
default: |
errx(EX_USAGE, "invalid duration"); |
err(1, "invalid duration"); |
} |
} |
|
|
if (ret < 0 || ret >= 100000000UL) |
if (ret < 0 || ret >= 100000000UL) |
errx(EX_USAGE, "invalid duration"); |
err(1, "invalid duration"); |
|
|
return (ret); |
return (ret); |
} |
} |
|
|
return (int)sig; |
return (int)sig; |
|
|
err: |
err: |
errx(EX_USAGE, "invalid signal"); |
err(1, "invalid signal"); |
} |
} |
|
|
static void |
static void |
|
|
tim.it_value.tv_usec = (suseconds_t)(iv * 1000000UL); |
tim.it_value.tv_usec = (suseconds_t)(iv * 1000000UL); |
|
|
if (setitimer(ITIMER_REAL, &tim, NULL) == -1) |
if (setitimer(ITIMER_REAL, &tim, NULL) == -1) |
err(EX_OSERR, "setitimer()"); |
err(1, "setitimer()"); |
} |
} |
|
|
int |
int |
|
|
SIGQUIT, |
SIGQUIT, |
}; |
}; |
|
|
setprogname(argv[0]); |
|
|
|
foreground = preserve = 0; |
foreground = preserve = 0; |
second_kill = 0; |
second_kill = 0; |
cpid = -1; |
cpid = -1; |
|
|
pgid = setpgid(0,0); |
pgid = setpgid(0,0); |
|
|
if (pgid == -1) |
if (pgid == -1) |
err(EX_OSERR, "setpgid()"); |
err(1, "setpgid()"); |
} |
} |
|
|
memset(&signals, 0, sizeof(signals)); |
memset(&signals, 0, sizeof(signals)); |
|
|
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 && |
if (signums[i] != -1 && signums[i] != 0 && |
sigaction(signums[i], &signals, NULL) == -1) |
sigaction(signums[i], &signals, NULL) == -1) |
err(EX_OSERR, "sigaction()"); |
err(1, "sigaction()"); |
} |
} |
|
|
signal(SIGTTIN, SIG_IGN); |
signal(SIGTTIN, SIG_IGN); |
|
|
|
|
pid = fork(); |
pid = fork(); |
if (pid == -1) |
if (pid == -1) |
err(EX_OSERR, "fork()"); |
err(1, "fork()"); |
else if (pid == 0) { |
else if (pid == 0) { |
/* child process */ |
/* child process */ |
signal(SIGTTIN, SIG_DFL); |
signal(SIGTTIN, SIG_DFL); |
|
|
|
|
error = execvp(argv[0], argv); |
error = execvp(argv[0], argv); |
if (error == -1) |
if (error == -1) |
err(EX_UNAVAILABLE, "exec()"); |
err(1, "exec()"); |
} |
} |
|
|
if (sigprocmask(SIG_BLOCK, &signals.sa_mask, NULL) == -1) |
if (sigprocmask(SIG_BLOCK, &signals.sa_mask, NULL) == -1) |
err(EX_OSERR, "sigprocmask()"); |
err(1, "sigprocmask()"); |
|
|
/* parent continues here */ |
/* parent continues here */ |
set_interval(first_kill); |
set_interval(first_kill); |
|
|
|
|
while (cpid != pid && wait(&pstat) == -1) { |
while (cpid != pid && wait(&pstat) == -1) { |
if (errno != EINTR) |
if (errno != EINTR) |
err(EX_OSERR, "waitpid()"); |
err(1, "waitpid()"); |
} |
} |
|
|
if (WEXITSTATUS(pstat)) |
if (WEXITSTATUS(pstat)) |