X-Git-Url: http://git.ozlabs.org/?p=ccan;a=blobdiff_plain;f=ccan%2Ffailtest%2Ffailtest.c;h=598a9e7930e933873ffbd9d02a3578d12d752472;hp=a9e1aa49887e0b97b4a4be7c89aeb5c8271e9d24;hb=f75f0ca743b7a41fe3b31dbde7d2595ba2e75bbe;hpb=6c02fd599f5b3f925197c3161ee186a3305fc963 diff --git a/ccan/failtest/failtest.c b/ccan/failtest/failtest.c index a9e1aa49..598a9e79 100644 --- a/ccan/failtest/failtest.c +++ b/ccan/failtest/failtest.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -19,6 +20,8 @@ bool (*failtest_hook)(struct failtest_call *history, unsigned num) = failtest_default_hook; +static int tracefd = -1; + unsigned int failtest_timeout_ms = 20000; const char *failpath; @@ -63,6 +66,7 @@ bool (*failtest_exit_check)(struct failtest_call *history, unsigned num); static struct failtest_call *history = NULL; static unsigned int history_num = 0; static int control_fd = -1; +static struct timeval start; static struct write_info *writes = NULL; static unsigned int writes_num = 0; @@ -143,18 +147,18 @@ static bool read_write_info(int fd) return true; } -static void print_reproduce(void) +static char *failpath_string(void) { unsigned int i; + char *ret = malloc(history_num + 1); - printf("To reproduce: --failpath="); for (i = 0; i < history_num; i++) { + ret[i] = info_to_arg[history[i].type]; if (history[i].fail) - printf("%c", toupper(info_to_arg[history[i].type])); - else - printf("%c", info_to_arg[history[i].type]); + ret[i] = toupper(ret[i]); } - printf("\n"); + ret[i] = '\0'; + return ret; } static void tell_parent(enum info_type type) @@ -166,13 +170,15 @@ static void tell_parent(enum info_type type) static void child_fail(const char *out, size_t outlen, const char *fmt, ...) { va_list ap; + char *path = failpath_string(); va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); fprintf(stderr, "%.*s", (int)outlen, out); - print_reproduce(); + printf("To reproduce: --failpath=%s\n", path); + free(path); tell_parent(FAILURE); exit(1); } @@ -250,6 +256,18 @@ static void get_locks(void) lock_owner = getpid(); } +static void trace_str(const char *str) +{ + ssize_t ret; + + while ((ret = write(tracefd, str, strlen(str))) <= 0) { + str += ret; + if (!*str) + return; + } + err(1, "Writing trace."); +} + static bool should_fail(struct failtest_call *call) { int status; @@ -265,7 +283,8 @@ static bool should_fail(struct failtest_call *call) if (tolower(*failpath) != info_to_arg[call->type]) errx(1, "Failpath expected '%c' got '%c'\n", info_to_arg[call->type], *failpath); - return isupper(*(failpath++)); + call->fail = isupper(*(failpath++)); + return call->fail; } if (!failtest_hook(history, history_num)) { @@ -285,6 +304,31 @@ static bool should_fail(struct failtest_call *call) err(1, "forking failed"); if (child == 0) { + if (tracefd != -1) { + struct timeval now; + char str[50], *p; + gettimeofday(&now, NULL); + if (now.tv_usec < start.tv_usec) { + now.tv_sec--; + now.tv_usec += 1000000; + } + now.tv_usec -= start.tv_usec; + now.tv_sec -= start.tv_sec; + sprintf(str, "%u (%u.%02u): ", getpid(), + (int)now.tv_sec, (int)now.tv_usec / 10000); + trace_str(str); + p = failpath_string(); + trace_str(p); + free(p); + trace_str("("); + p = strchr(history[history_num-1].file, '/'); + if (p) + trace_str(p+1); + else + trace_str(history[history_num-1].file); + sprintf(str, ":%u)\n", history[history_num-1].line); + trace_str(str); + } close(control[0]); close(output[0]); dup2(output[1], STDOUT_FILENO); @@ -754,10 +798,17 @@ int failtest_fcntl(int fd, const char *file, unsigned line, int cmd, ...) void failtest_init(int argc, char *argv[]) { - if (argc == 2 - && strncmp(argv[1], "--failpath=", strlen("--failpath=")) == 0) { - failpath = argv[1] + strlen("--failpath="); + unsigned int i; + + for (i = 1; i < argc; i++) { + if (!strncmp(argv[i], "--failpath=", strlen("--failpath="))) { + failpath = argv[i] + strlen("--failpath="); + } else if (strcmp(argv[i], "--tracepath") == 0) { + tracefd = dup(STDERR_FILENO); + failtest_timeout_ms = -1; + } } + gettimeofday(&start, NULL); } /* Free up memory, so valgrind doesn't report leaks. */