Blame timedrun.c

Packit 4e8bc4
#include <stdio.h>
Packit 4e8bc4
#include <stdlib.h>
Packit 4e8bc4
#include <unistd.h>
Packit 4e8bc4
#include <signal.h>
Packit 4e8bc4
#include <sys/wait.h>
Packit 4e8bc4
#include <sysexits.h>
Packit 4e8bc4
Packit 4e8bc4
#include <assert.h>
Packit 4e8bc4
Packit 4e8bc4
volatile sig_atomic_t caught_sig = 0;
Packit 4e8bc4
Packit 4e8bc4
static void signal_handler(int which)
Packit 4e8bc4
{
Packit 4e8bc4
    caught_sig = which;
Packit 4e8bc4
}
Packit 4e8bc4
Packit 4e8bc4
static int wait_for_process(pid_t pid)
Packit 4e8bc4
{
Packit 4e8bc4
    int rv = EX_SOFTWARE;
Packit 4e8bc4
    int status = 0;
Packit 4e8bc4
    int i = 0;
Packit 4e8bc4
    struct sigaction sig_handler;
Packit 4e8bc4
Packit 4e8bc4
    sig_handler.sa_handler = signal_handler;
Packit 4e8bc4
    sig_handler.sa_flags = 0;
Packit 4e8bc4
Packit 4e8bc4
    sigaction(SIGALRM, &sig_handler, NULL);
Packit 4e8bc4
    sigaction(SIGHUP, &sig_handler, NULL);
Packit 4e8bc4
    sigaction(SIGINT, &sig_handler, NULL);
Packit 4e8bc4
    sigaction(SIGUSR1, &sig_handler, NULL);
Packit 4e8bc4
    sigaction(SIGTERM, &sig_handler, NULL);
Packit 4e8bc4
    sigaction(SIGPIPE, &sig_handler, NULL);
Packit 4e8bc4
Packit 4e8bc4
    /* Loop forever waiting for the process to quit */
Packit 4e8bc4
    for (i = 0; ;i++) {
Packit 4e8bc4
        pid_t p = waitpid(pid, &status, 0);
Packit 4e8bc4
        if (p == pid) {
Packit 4e8bc4
            /* child exited.  Let's get out of here */
Packit 4e8bc4
            rv = WIFEXITED(status) ?
Packit 4e8bc4
                WEXITSTATUS(status) :
Packit 4e8bc4
                (0x80 | WTERMSIG(status));
Packit 4e8bc4
            break;
Packit 4e8bc4
        } else {
Packit 4e8bc4
            int sig = 0;
Packit 4e8bc4
            switch (i) {
Packit 4e8bc4
            case 0:
Packit 4e8bc4
                /* On the first iteration, pass the signal through */
Packit 4e8bc4
                sig = caught_sig > 0 ? caught_sig : SIGTERM;
Packit 4e8bc4
                if (caught_sig == SIGALRM) {
Packit 4e8bc4
                   fprintf(stderr, "Timeout.. killing the process\n");
Packit 4e8bc4
                }
Packit 4e8bc4
                break;
Packit 4e8bc4
            case 1:
Packit 4e8bc4
                sig = SIGTERM;
Packit 4e8bc4
                break;
Packit 4e8bc4
            default:
Packit 4e8bc4
                sig = SIGKILL;
Packit 4e8bc4
                break;
Packit 4e8bc4
            }
Packit 4e8bc4
            if (kill(pid, sig) < 0) {
Packit 4e8bc4
                /* Kill failed.  Must have lost the process. :/ */
Packit 4e8bc4
                perror("lost child when trying to kill");
Packit 4e8bc4
            }
Packit 4e8bc4
            /* Wait up to 5 seconds for the pid */
Packit 4e8bc4
            alarm(5);
Packit 4e8bc4
        }
Packit 4e8bc4
    }
Packit 4e8bc4
    return rv;
Packit 4e8bc4
}
Packit 4e8bc4
Packit 4e8bc4
static int spawn_and_wait(char **argv)
Packit 4e8bc4
{
Packit 4e8bc4
    int rv = EX_SOFTWARE;
Packit 4e8bc4
    pid_t pid = fork();
Packit 4e8bc4
Packit 4e8bc4
    switch (pid) {
Packit 4e8bc4
    case -1:
Packit 4e8bc4
        perror("fork");
Packit 4e8bc4
        rv = EX_OSERR;
Packit 4e8bc4
        break; /* NOTREACHED */
Packit 4e8bc4
    case 0:
Packit 4e8bc4
        execvp(argv[0], argv);
Packit 4e8bc4
        perror("exec");
Packit 4e8bc4
        rv = EX_SOFTWARE;
Packit 4e8bc4
        break; /* NOTREACHED */
Packit 4e8bc4
    default:
Packit 4e8bc4
        rv = wait_for_process(pid);
Packit 4e8bc4
    }
Packit 4e8bc4
    return rv;
Packit 4e8bc4
}
Packit 4e8bc4
Packit 4e8bc4
int main(int argc, char **argv)
Packit 4e8bc4
{
Packit 4e8bc4
    int naptime = 0;
Packit 4e8bc4
    assert(argc > 2);
Packit 4e8bc4
Packit 4e8bc4
    naptime = atoi(argv[1]);
Packit 4e8bc4
    assert(naptime > 0 && naptime < 1800);
Packit 4e8bc4
Packit 4e8bc4
    alarm(naptime);
Packit 4e8bc4
Packit 4e8bc4
    return spawn_and_wait(argv+2);
Packit 4e8bc4
}