summaryrefslogtreecommitdiff
path: root/tests/fs-tests/utils/fstest_monitor.c
diff options
context:
space:
mode:
Diffstat (limited to 'tests/fs-tests/utils/fstest_monitor.c')
-rw-r--r--tests/fs-tests/utils/fstest_monitor.c281
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;
+}