/* * timeout.c -- run commands with a specified timeout * Copyright (C) 2007 Robert Millan * * GRUB is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GRUB; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #define PROGRAM_NAME "timeout" #define PROGRAM_VERSION "0.0.1" int pid; int signum = SIGTERM; int timeout_status = 1; static struct option options[] = { {"signal", required_argument, 0, 's'}, {"status", required_argument, 0, 't'}, {"help", no_argument, 0, 'h'}, {"version", no_argument, 0, 'v'}, {0, 0, 0, 0} }; static void usage (int status) { if (status) fprintf (stderr, "Try ``" PROGRAM_NAME " --help'' for more information.\n"); else printf ("\ Usage: " PROGRAM_NAME " [OPTION]... NUMBER COMMAND ARGUMENTS\n\ Runs COMMAND with ARGUMENTS, and kills it after NUMBER seconds.\n\ \n\ -s, --signal SIGNUM use SIGNUM to kill our child\n\ -t, --status NUMBER after killing our child, exit with NUMBER\n\ -h, --help display this message and exit\n\ -v, --version print version information and exit\n\ \n"); exit (status); } void handler (int dummy) { kill (signum, pid); exit (timeout_status); } main (int argc, char **argv) { int timeout; char *tail; /* Check for options. */ while (1) { int c = getopt_long (argc, argv, "hs:t:v", options, 0); if (c == -1) break; switch (c) { case 'h': usage (0); case 'v': printf (PROGRAM_NAME " " PROGRAM_VERSION "\n"); exit (0); break; case 's': signum = strtol (optarg, &tail, 10); if (tail[0] != '\0') usage (1); break; case 't': timeout_status = strtol (optarg, &tail, 10); if (tail[0] != '\0') usage (1); break; default: usage (1); } } /* Ditch getopt args -- no longer needed */ argv += optind; if (argv[0] == NULL) usage (1); timeout = strtol (argv[0], &tail, 10); if (tail[0] != '\0') usage (1); /* Ditch timeout -- no longer needed */ argv++; signal (SIGALRM, handler); pid = fork (); switch (pid) { case -1: perror ("fork"); exit (1); case 0: execvp (argv[0], argv); perror ("execvp"); exit (1); default: { int child_status; alarm (timeout); while (waitpid (pid, &child_status, WNOHANG) == 0); exit (child_status); } } }