| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173 |
- /* execute a program with a timeout by alarm(2) */
- #define _GNU_SOURCE
- #include <unistd.h>
- #include <sys/types.h>
- #include <sys/wait.h>
- #include <signal.h>
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include <errno.h>
- static const char *argv0;
- static char **prgargv;
- static pid_t pid;
- static int signo;
- static unsigned int timeout;
- static void timedout(int sig)
- {
- fprintf(stderr, "%s[%d]: %s[%d] timed out after %u sec\n",
- argv0, getpid(), *prgargv, pid, timeout);
- if (pid)
- kill(-pid, signo);
- }
- static void interrupted(int sig)
- {
- alarm(0);
- if (pid)
- kill(-pid, sig);
- }
- static void usage()
- {
- fprintf(stderr, "%s <timeout-seconds> [-<signal>] program ...\n"
- "Where <signal> is a signal number (see kill -l).\n"
- "Some symbolic names recognized. KILL used by default\n",
- argv0);
- exit(1);
- }
- static struct {
- const char *name;
- int signo;
- } known[] = {
- {"HUP", SIGHUP},
- {"INT", SIGINT},
- {"QUIT", SIGQUIT},
- {"ILL", SIGILL},
- {"TRAP", SIGTRAP},
- {"ABRT", SIGABRT},
- {"BUS", SIGBUS},
- {"FPE", SIGFPE},
- {"KILL", SIGKILL},
- {"USR1", SIGUSR1},
- {"SEGV", SIGSEGV},
- {"USR2", SIGUSR2},
- {"PIPE", SIGPIPE},
- {"ALRM", SIGALRM},
- {"TERM", SIGTERM},
- {"STKFLT", SIGSTKFLT},
- {"CHLD", SIGCHLD},
- {"CONT", SIGCONT},
- {"STOP", SIGSTOP},
- {"TSTP", SIGTSTP},
- {"TTIN", SIGTTIN},
- {"TTOU", SIGTTOU},
- {"URG", SIGURG},
- {"XCPU", SIGXCPU},
- {"XFSZ", SIGXFSZ},
- {"VTALRM", SIGVTALRM},
- {"PROF", SIGPROF},
- {"WINCH", SIGWINCH},
- {"IO", SIGIO},
- {"PWR", SIGPWR},
- {"SYS", SIGSYS},
- };
- static int signo_arg(const char *arg)
- {
- if (*arg == '-') {
- char *p;
- int s = strtol(++arg, &p, 10);
- if (!*p && p > arg && s > 0 && s < _NSIG) {
- signo = s;
- return 1;
- }
- if (!strncasecmp(arg, "SIG", 3))
- arg += 3;
- for (s = 0; s < sizeof(known)/sizeof(*known); ++s)
- if (!strcasecmp(arg, known[s].name)) {
- signo = known[s].signo;
- return 1;
- }
- }
- return 0;
- }
- int main(int argc, char** argv)
- {
- argv0 = strrchr(*argv, '/');
- if (argv0)
- ++argv0;
- else
- argv0 = *argv;
- signal(SIGALRM, timedout);
- signal(SIGINT, interrupted);
- signal(SIGHUP, interrupted);
- ++argv;
- if (!*argv)
- usage();
- if (signo_arg(*argv))
- ++argv;
- if (sscanf(*argv, "%u", &timeout) == 1)
- ++argv;
- else
- usage();
- if (!signo && signo_arg(*argv))
- ++argv;
- if (!signo)
- signo = SIGKILL;
- if (!*argv)
- usage();
- prgargv = argv;
- alarm(timeout);
- pid = fork();
- if (!pid) {
- signal(SIGALRM, SIG_DFL);
- signal(SIGCHLD, SIG_DFL);
- signal(SIGINT, SIG_DFL);
- signal(SIGHUP, SIG_DFL);
- setpgid(0, 0);
- execvp(*prgargv, prgargv);
- fprintf(stderr, "%s: %s: %s\n",
- argv0, *prgargv, strerror(errno));
- _exit(2);
- } else if (pid < 0) {
- fprintf(stderr, "%s: %s\n", argv0, strerror(errno));
- } else {
- int status;
- while (waitpid(pid, &status, 0) < 0 && EINTR == errno)
- ;
- alarm(0);
- if (WIFEXITED(status))
- return WEXITSTATUS(status);
- if (WIFSIGNALED(status)) {
- /*
- * Some signals are special, lets die with
- * the same signal as child process
- */
- if (WTERMSIG(status) == SIGHUP ||
- WTERMSIG(status) == SIGINT ||
- WTERMSIG(status) == SIGTERM ||
- WTERMSIG(status) == SIGQUIT ||
- WTERMSIG(status) == SIGKILL) {
- signal(WTERMSIG(status), SIG_DFL);
- raise(WTERMSIG(status));
- }
- fprintf(stderr, "%s: %s: %s\n",
- argv0, *prgargv, strsignal(WTERMSIG(status)));
- }
- else
- fprintf(stderr, "%s died\n", *prgargv);
- }
- return 2;
- }
|