]> git.ozlabs.org Git - ccan/blobdiff - ccan/failtest/failtest.c
failtest: call failtest_exit_check even in non-failing parent.
[ccan] / ccan / failtest / failtest.c
index 9102ba0a88b884591ef766bdfa9582e4de72d424..ccc89b22f344bbdde2b193f6c33cb91c26f75692 100644 (file)
@@ -25,6 +25,7 @@ static int tracefd = -1;
 unsigned int failtest_timeout_ms = 20000;
 
 const char *failpath;
+const char *debugpath;
 
 enum info_type {
        WRITE,
@@ -329,6 +330,29 @@ static bool should_fail(struct failtest_call *call)
                }
        }
 
+       /* Attach debugger if they asked for it. */
+       if (debugpath && history_num == strlen(debugpath)) {
+               unsigned int i;
+
+               for (i = 0; i < history_num; i++) {
+                       char c = info_to_arg[history[i].type];
+                       if (history[i].fail)
+                               c = toupper(c);
+                       if (c != debugpath[i])
+                               break;
+               }
+               if (i == history_num) {
+                       char str[80];
+
+                       /* Don't timeout. */
+                       signal(SIGUSR1, SIG_IGN);
+                       sprintf(str, "xterm -e gdb /proc/%d/exe %d &",
+                               getpid(), getpid());
+                       system(str);
+                       sleep(5);
+               }
+       }
+
        if (!failtest_hook(history, history_num)) {
                call->fail = false;
                return false;
@@ -431,9 +455,13 @@ static bool should_fail(struct failtest_call *call)
        close(output[0]);
        close(control[0]);
        waitpid(child, &status, 0);
-       if (!WIFEXITED(status))
-               child_fail(out, outlen, "Killed by signal %u: ",
-                          WTERMSIG(status));
+       if (!WIFEXITED(status)) {
+               if (WTERMSIG(status) == SIGUSR1)
+                       child_fail(out, outlen, "Timed out");
+               else
+                       child_fail(out, outlen, "Killed by signal %u: ",
+                                  WTERMSIG(status));
+       }
        /* Child printed failure already, just pass up exit code. */
        if (type == FAILURE) {
                fprintf(stderr, "%.*s", (int)outlen, out);
@@ -588,12 +616,17 @@ int failtest_open(const char *pathname,
        /* Avoid memory leak! */
        if (p == &unrecorded_call)
                free((char *)call.pathname);
-       if (should_fail(p)) {
+       p->u.open.ret = open(pathname, call.flags, call.mode);
+
+       if (!failpath && p->u.open.ret == -1) {
+               p->fail = false;
+               p->error = errno;
+       } else if (should_fail(p)) {
+               close(p->u.open.ret);
                p->u.open.ret = -1;
                /* FIXME: Play with error codes? */
                p->error = EACCES;
        } else {
-               p->u.open.ret = open(pathname, call.flags, call.mode);
                set_cleanup(p, cleanup_open, struct open_call);
        }
        errno = p->error;
@@ -922,6 +955,9 @@ void failtest_init(int argc, char *argv[])
                } else if (strcmp(argv[i], "--tracepath") == 0) {
                        tracefd = dup(STDERR_FILENO);
                        failtest_timeout_ms = -1;
+               } else if (!strncmp(argv[i], "--debugpath=",
+                                   strlen("--debugpath="))) {
+                       debugpath = argv[i] + strlen("--debugpath=");
                }
        }
        gettimeofday(&start, NULL);
@@ -944,16 +980,16 @@ void failtest_exit(int status)
 {
        int i;
 
-       if (control_fd == -1) {
-               free_everything();
-               exit(status);
-       }
-
        if (failtest_exit_check) {
                if (!failtest_exit_check(history, history_num))
                        child_fail(NULL, 0, "failtest_exit_check failed\n");
        }
 
+       if (control_fd == -1) {
+               free_everything();
+               exit(status);
+       }
+
        /* Cleanup everything, in reverse order. */
        for (i = history_num - 1; i >= 0; i--)
                if (history[i].cleanup)