diff options
Diffstat (limited to 'tests/fs-tests/utils/fstest_monitor.c')
-rw-r--r-- | tests/fs-tests/utils/fstest_monitor.c | 281 |
1 files changed, 281 insertions, 0 deletions
diff --git a/tests/fs-tests/utils/fstest_monitor.c b/tests/fs-tests/utils/fstest_monitor.c new file mode 100644 index 0000000..298ee26 --- /dev/null +++ b/tests/fs-tests/utils/fstest_monitor.c @@ -0,0 +1,281 @@ +/* + * 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; + +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; + } +} + +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; +} + +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; + } +} + +int have_children(void) +{ + struct child_info *child; + + child = children; + while (child) { + if (!child->gone) + return 1; + child = child->next; + } + return 0; +} + +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; + 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; +} + +void signal_handler(int signum) +{ + kill_children(); +} + +int result = 0; +int alarm_gone_off = 0; + +void alarm_handler(int 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; +} |