123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284 |
- /*
- * Copyright (C) 2007 Nokia Corporation.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * 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 this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- * Author: Adrian Hunter
- */
- #include <sys/types.h>
- #include <sys/wait.h>
- #include <unistd.h>
- #include <stdio.h>
- #include <signal.h>
- #include <string.h>
- #include <stdlib.h>
- #include <ctype.h>
- #include <errno.h>
- struct child_info {
- struct child_info *next;
- pid_t pid;
- int terminated;
- int killed;
- int gone;
- };
- struct child_info *children = 0;
- static void kill_children(void)
- {
- struct child_info *child;
- child = children;
- while (child) {
- if (!child->gone) {
- if (!child->terminated) {
- child->terminated = 1;
- kill(child->pid, SIGTERM);
- } /*else if (!child->killed) {
- child->killed = 1;
- kill(child->pid, SIGKILL);
- }*/
- }
- child = child->next;
- }
- }
- static void add_child(pid_t child_pid)
- {
- struct child_info *child;
- size_t sz;
- sz = sizeof(struct child_info);
- child = (struct child_info *) malloc(sz);
- memset(child, 0, sz);
- child->pid = child_pid;
- child->next = children;
- children = child;
- }
- static void mark_child_gone(pid_t child_pid)
- {
- struct child_info *child;
- child = children;
- while (child) {
- if (child->pid == child_pid) {
- child->gone = 1;
- break;
- }
- child = child->next;
- }
- }
- static int have_children(void)
- {
- struct child_info *child;
- child = children;
- while (child) {
- if (!child->gone)
- return 1;
- child = child->next;
- }
- return 0;
- }
- static int parse_command_line(char *cmdline, int *pargc, char ***pargv)
- {
- char **tmp;
- char *p, *v, *q;
- size_t sz;
- int argc = 0;
- int state = 0;
- char *argv[1024];
- if (!cmdline)
- return 1;
- q = v = (char *) malloc(strlen(cmdline) + 1024);
- if (!v)
- return 1;
- p = cmdline;
- for (;;) {
- char c = *p++;
- if (!c) {
- *v++ = 0;
- break;
- }
- switch (state) {
- case 0: /* Between args */
- if (isspace(c))
- break;
- argv[argc++] = v;
- if (c == '"') {
- state = 2;
- break;
- } else if (c == '\'') {
- state = 3;
- break;
- }
- state = 1;
- /* fall-through */
- case 1: /* Not quoted */
- if (c == '\\') {
- if (*p)
- *v++ = *p;
- } else if (isspace(c)) {
- *v++ = 0;
- state = 0;
- } else
- *v++ = c;
- break;
- case 2: /* Double quoted */
- if (c == '\\' && *p == '"') {
- *v++ = '"';
- ++p;
- } else if (c == '"') {
- *v++ = 0;
- state = 0;
- } else
- *v++ = c;
- break;
- case 3: /* Single quoted */
- if (c == '\'') {
- *v++ = 0;
- state = 0;
- } else
- *v++ = c;
- break;
- }
- }
- argv[argc] = 0;
- sz = sizeof(char *) * (argc + 1);
- tmp = (char **) malloc(sz);
- if (!tmp) {
- free(q);
- return 1;
- }
- if (argc == 0)
- free(q);
- memcpy(tmp, argv, sz);
- *pargc = argc;
- *pargv = tmp;
- return 0;
- }
- static void signal_handler(int signum)
- {
- (void)signum;
- kill_children();
- }
- int result = 0;
- int alarm_gone_off = 0;
- static void alarm_handler(int signum)
- {
- (void)signum;
- if (!result)
- alarm_gone_off = 1;
- kill_children();
- }
- int main(int argc, char *argv[], char **env)
- {
- int p;
- pid_t child_pid;
- int status;
- int duration = 0;
- p = 1;
- if (argc > 1) {
- if (strncmp(argv[p], "--help", 6) == 0 ||
- strncmp(argv[p], "-h", 2) == 0) {
- printf( "Usage is: "
- "fstest_monitor options programs...\n"
- " Options are:\n"
- " -h, --help "
- "This help message\n"
- " -d, --duration arg "
- "Stop after arg seconds\n"
- "\n"
- "Run programs and wait for them."
- " If duration is specified,\n"
- "kill all programs"
- " after that number of seconds have elapsed.\n"
- "Example: "
- "fstest_monitor \"/bin/ls -l\" /bin/date\n"
- );
- return 1;
- }
- if (strncmp(argv[p], "--duration", 10) == 0 ||
- strncmp(argv[p], "-d", 2) == 0) {
- char *s;
- if (p+1 < argc && !isdigit(argv[p][strlen(argv[p])-1]))
- ++p;
- s = argv[p];
- while (*s && !isdigit(*s))
- ++s;
- duration = atoi(s);
- ++p;
- }
- }
- signal(SIGTERM, signal_handler);
- signal(SIGINT, signal_handler);
- for (; p < argc; ++p) {
- child_pid = fork();
- if (child_pid) {
- /* Parent */
- if (child_pid == (pid_t) -1) {
- kill_children();
- result = 1;
- break;
- }
- add_child(child_pid);
- } else {
- /* Child */
- int cargc;
- char **cargv;
- if (parse_command_line(argv[p], &cargc, &cargv))
- return 1;
- execve(cargv[0], cargv, env);
- return 1;
- }
- }
- if (!result && duration > 0) {
- signal(SIGALRM, alarm_handler);
- alarm(duration);
- }
- while (have_children()) {
- status = 0;
- child_pid = wait(&status);
- if (child_pid == (pid_t) -1) {
- if (errno == EINTR)
- continue;
- kill_children();
- return 1;
- }
- mark_child_gone(child_pid);
- if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
- result = 1;
- kill_children();
- }
- }
- if (alarm_gone_off)
- return 0;
- return result;
- }
|