It needs pledge.

> +#include <sys/cdefs.h>

This is wrong, it should be <sys/types.h>

> +#include <sys/time.h>
> +#include <sys/wait.h>

> +
> +#include <err.h>
> +#include <errno.h>
> +#include <getopt.h>
> +#include <limits.h>
> +#include <signal.h>
> +#include <stdbool.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <sysexits.h>
> +#include <unistd.h>
> +
> +#define EXIT_TIMEOUT 124
> +
> +static sig_atomic_t sig_chld = 0;
> +static sig_atomic_t sig_term = 0;
> +static sig_atomic_t sig_alrm = 0;
> +static sig_atomic_t sig_ign = 0;
> +
> +static void __dead
> +usage(void)
> +{
> +     fprintf(stderr, "Usage: %s [--signal sig | -s sig] [--preserve-status]"

lower case usage:

> +         " [--kill-after time | -k time] [--foreground] <duration> <command>"
> +         " <arg ...>\n", getprogname());

This should not use <>, ingo and jmc are going to scream at you.

setprogname/getprogname use is excessive, this could simply be the text 
"timeout"

> +     errno = 0;
> +     sig = strtol(str, &ep, 10);
> +
> +     if (str[0] == '\0' || *ep != '\0')
> +             goto err;
> +     if (errno == ERANGE && (sig == LONG_MAX || sig == LONG_MIN))
> +             goto err;

strtonum will simplify this.

> +             return;
> +     }
> +
> +     switch(signo) {
> +     case 0:

I don't understand what the 0 does here.

> +     case SIGINT:
> +     case SIGHUP:
> +     case SIGQUIT:
> +     case SIGTERM:
> +             sig_term = signo;
> +             break;
> +     case SIGCHLD:
> +             sig_chld = 1;
> +             break;
> +     case SIGALRM:
> +             sig_alrm = 1;
> +             break;
> +     }
> +}
> +main(int argc, char **argv)
> +{
> +     int             ch;
> +     unsigned long   i;
> +     int             foreground, preserve;
> +     int             error, pstat, status;
> +     int             killsig = SIGTERM;
> +     pid_t           pgid, pid, cpid;
> +     double          first_kill;
> +     double          second_kill;
> +     bool            timedout = false;
> +     bool            do_second_kill = false;
> +     struct          sigaction signals;
> +     int             signums[] = {
> +             -1,
> +             SIGTERM,
> +             SIGINT,
> +             SIGHUP,
> +             SIGCHLD,
> +             SIGALRM,
> +             SIGQUIT,
> +     };

Weird indent.

> +
> +     setprogname(argv[0]);

setprogname discussion at the top

> +
> +     foreground = preserve = 0;
> +     second_kill = 0;
> +     cpid = -1;
> +     pgid = -1;

This defines variables *after* code:

> +
> +     const struct option longopts[] = {
> +             { "preserve-status", no_argument,       &preserve,    1 },
> +             { "foreground",      no_argument,       &foreground,  1 },
> +             { "kill-after",      required_argument, NULL,        'k'},
> +             { "signal",          required_argument, NULL,        's'},
> +             { "help",            no_argument,       NULL,        'h'},
> +             { NULL,              0,                 NULL,         0 }
> +     };

can likely do pledge("stdio proc exec") around here.

> +
> +     while ((ch = getopt_long(argc, argv, "+k:s:h", longopts, NULL)) != -1) {
> +             switch (ch) {
> +             case 'k':
> +                     do_second_kill = true;
> +                     second_kill = parse_duration(optarg);
> +                     break;
> +             case 's':
> +                     killsig = parse_signal(optarg);
> +                     break;
> +             case 0:
> +                     break;
> +             case 'h':

'h' is pointless.

> +             default:
> +                     usage();
> +                     break;
> +             }
> +     }
> +
> +     argc -= optind;
> +     argv += optind;
> +
> +     if (argc < 2)
> +             usage();
> +
> +     first_kill = parse_duration(argv[0]);
> +     argc--;
> +     argv++;
> +
> +     if (!foreground) {
> +             pgid = setpgid(0,0);
> +
> +             if (pgid == -1)
> +                     err(EX_OSERR, "setpgid()");
> +     }
> +
> +     memset(&signals, 0, sizeof(signals));
> +     sigemptyset(&signals.sa_mask);
> +
> +     if (killsig != SIGKILL && killsig != SIGSTOP)
> +             signums[0] = killsig;
> +
> +     for (i = 0; i < sizeof(signums) / sizeof(signums[0]); i ++)
> +             sigaddset(&signals.sa_mask, signums[i]);
> +
> +     signals.sa_handler = sig_handler;
> +     signals.sa_flags = SA_RESTART;
> +
> +     for (i = 0; i < sizeof(signums) / sizeof(signums[0]); i ++) {
> +             if (signums[i] != -1 && signums[i] != 0 &&
> +                 sigaction(signums[i], &signals, NULL) == -1)
> +                     err(EX_OSERR, "sigaction()");
> +     }
> +
> +     signal(SIGTTIN, SIG_IGN);
> +     signal(SIGTTOU, SIG_IGN);
> +
> +     pid = fork();
> +     if (pid == -1)
> +             err(EX_OSERR, "fork()");
> +     else if (pid == 0) {
> +             /* child process */
> +             signal(SIGTTIN, SIG_DFL);
> +             signal(SIGTTOU, SIG_DFL);
> +
> +             error = execvp(argv[0], argv);
> +             if (error == -1)
> +                     err(EX_UNAVAILABLE, "exec()");
> +     }
> +
can likely do pledge("stdio") around here.


> +     if (sigprocmask(SIG_BLOCK, &signals.sa_mask, NULL) == -1)
> +             err(EX_OSERR, "sigprocmask()");
> +
> +     /* parent continues here */
> +     set_interval(first_kill);
> +
> +     for (;;) {
> +             sigemptyset(&signals.sa_mask);
> +             sigsuspend(&signals.sa_mask);
> +
> +             if (sig_chld) {
> +                     sig_chld = 0;
> +                     while (((cpid = wait(&status)) < 0) && errno == EINTR)
> +                             continue;
> +
> +                     if (cpid == pid) {
> +                             pstat = status;
> +                             break;
> +                     }
> +             } else if (sig_alrm) {
> +                     sig_alrm = 0;
> +
> +                     timedout = true;
> +                     if (!foreground)
> +                             killpg(pgid, killsig);
> +                     else
> +                             kill(pid, killsig);
> +
> +                     if (do_second_kill) {
> +                             set_interval(second_kill);
> +                             second_kill = 0;
> +                             sig_ign = killsig;
> +                             killsig = SIGKILL;
> +                     } else
> +                             break;
> +
> +             } else if (sig_term) {
> +                     if (!foreground)
> +                             killpg(pgid, killsig);
> +                     else
> +                             kill(pid, (int)sig_term);
> +
> +                     if (do_second_kill) {
> +                             set_interval(second_kill);
> +                             second_kill = 0;
> +                             sig_ign = killsig;
> +                             killsig = SIGKILL;
> +                     } else
> +                             break;
> +             }
> +     }
> +
> +     while (cpid != pid  && wait(&pstat) == -1) {
> +             if (errno != EINTR)
> +                     err(EX_OSERR, "waitpid()");
> +     }
> +
> +     if (WEXITSTATUS(pstat))
> +             pstat = WEXITSTATUS(pstat);
> +     else if(WIFSIGNALED(pstat))
> +             pstat = 128 + WTERMSIG(pstat);
> +
> +     if (timedout && !preserve)
> +             pstat = EXIT_TIMEOUT;
> +
> +     return (pstat);
> +}
> 

I am surprised it is so long.

Reply via email to