Standard: https://pubs.opengroup.org/onlinepubs/9799919799/utilities/timeout.html Requirements: * This standard requires that all signal dispositions inherited by the utility specified by the utility operand are the same as the disposition that timeout inherited, with the single exception of the signal that timeout sends when the time limit is reached, which needs to be inherited as default in order for the timeout to take effect (without resorting to SIGKILL if -k is specified). * There is no reason to select a subset of these signals to be propagated, therefore this standard requires them all to be propagated (except SIGKILL, which cannot). In the event that a user wants to prevent the utility being timed out, sending timeout a SIGKILL can be used for this purpose. * If timeout receives a signal and propagates it to the child process (see ASYNCHRONOUS EVENTS below), this shall be treated as the first signal. * If the delivered signal is SIGALRM, timeout may behave as if the time limit had been reached instead of sending SIGALRM. Prototype: -------------------------------------------------------------------------------- static volatile sig_atomic_t sig_chld = 0; static volatile sig_atomic_t sig_alrm = 0; static volatile sig_atomic_t sig_term = 0; static volatile sig_atomic_t sig_propagate = 0; void sig_handlr(int signo) { switch (signo) { case SIGCHLD: sig_chld = 1; break; case SIGALRM: sig_alrm = 1; break; default: sig_propagate = signo; break; } } int main() { int killsig = SIGTERM; sigaction_t sa; sigset_t newmask, oldmask, waitmask; /* block all signals */ sigfillset(&newmask); sigprocmask(SIG_BLOCK, &newmask, &oldmask); pid = fork(); if (pid == -1) { err(...); } else if (pid == 0) { /* child */ signal(killsig, SIG_DFL); sigprocmask(SIG_SETMASK, &oldmask, NULL); execvp(...); _exit(...); } /* parent */ signal(SIGTTIN, SIG_IGN); signal(SIGTTOU, SIG_IGN); /* catch all signals in order to propagate them */ memset(&sa, 0, sizeof(sa)); sigemptyset(&sa.sa_mask); sa.sig_handlr; sa.sa_flags = SA_RESTART; for (sig = 1; sig < sys_nsig; i++) { if (sig == SIGKILL || sig == SIGSTOP || sig == SIGCONT) continue; if (sigaction(sig, &sa, NULL) == -1) err(...); } /* wait for all signals */ sigemptyset(&waitmask); set_interval(first_kill); for (;;) { sigsuspend(&waitmask); if (sig_chld) { sig_chld = 0; waitpid(...); ... } else if (sig_alrm) { sig_alrm = 0; send_sig(pid, killsig); ... } else if (sig_propagate) { int sig = sig_propagate; sig_propagate = 0; send_sig(pid, sig); } } ... } --------------------------------------------------------------------------------