X-Git-Url: http://git.ozlabs.org/?a=blobdiff_plain;f=ccan%2Ffailtest%2Ffailtest.c;h=c61ce442a5d03b39444a87a468514f23c6f3c962;hb=3c65e082a9547992222a9f379f2484cceaaedfa8;hp=b394848fad79cb5dc72ac5fc94e119ffae066aa4;hpb=614259f13c3e694fcd6b57fc05a329066e43c76d;p=ccan diff --git a/ccan/failtest/failtest.c b/ccan/failtest/failtest.c index b394848f..c61ce442 100644 --- a/ccan/failtest/failtest.c +++ b/ccan/failtest/failtest.c @@ -5,7 +5,6 @@ #include #include #include -#include #include #include #include @@ -14,8 +13,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -27,9 +28,8 @@ enum failtest_result (*failtest_hook)(struct tlist_calls *); -static int tracefd = -1; +static FILE *tracef = NULL, *warnf; static int traceindent = 0; -static int warnfd; unsigned int failtest_timeout_ms = 20000; @@ -91,7 +91,7 @@ static int control_fd = -1; /* If we're a child, this is the first call we did ourselves. */ static struct failtest_call *our_history_start = NULL; /* For printing runtime with --trace. */ -static struct timeval start; +static struct timeabs start; /* Set when failtest_hook returns FAIL_PROBE */ static bool probing = false; /* Table to track duplicates. */ @@ -195,11 +195,21 @@ static struct failtest_call *add_history_(enum failtest_call_type type, static int move_fd_to_high(int fd) { int i; + struct rlimit lim; + int max; - for (i = FD_SETSIZE - 1; i >= 0; i--) { + if (getrlimit(RLIMIT_NOFILE, &lim) == 0) { + max = lim.rlim_cur; + printf("Max is %i\n", max); + } else + max = FD_SETSIZE; + + for (i = max - 1; i > fd; i--) { if (fcntl(i, F_GETFL) == -1 && errno == EBADF) { - if (dup2(fd, i) == -1) - err(1, "Failed to dup fd %i to %i", fd, i); + if (dup2(fd, i) == -1) { + warn("Failed to dup fd %i to %i", fd, i); + continue; + } close(fd); return i; } @@ -245,14 +255,14 @@ static char *failpath_string(void) return ret; } -static void warn_via_fd(int e, const char *fmt, va_list ap) +static void do_warn(int e, const char *fmt, va_list ap) { char *p = failpath_string(); - vdprintf(warnfd, fmt, ap); + vfprintf(warnf, fmt, ap); if (e != -1) - dprintf(warnfd, ": %s", strerror(e)); - dprintf(warnfd, " [%s]\n", p); + fprintf(warnf, ": %s", strerror(e)); + fprintf(warnf, " [%s]\n", p); free(p); } @@ -262,7 +272,7 @@ static void fwarn(const char *fmt, ...) int e = errno; va_start(ap, fmt); - warn_via_fd(e, fmt, ap); + do_warn(e, fmt, ap); va_end(ap); } @@ -272,7 +282,7 @@ static void fwarnx(const char *fmt, ...) va_list ap; va_start(ap, fmt); - warn_via_fd(-1, fmt, ap); + do_warn(-1, fmt, ap); va_end(ap); } @@ -302,17 +312,21 @@ static void PRINTF_FMT(1, 2) trace(const char *fmt, ...) { va_list ap; unsigned int i; + char *p; + static int idx; - if (tracefd == -1) + if (!tracef) return; for (i = 0; i < traceindent; i++) - dprintf(tracefd, " "); + fprintf(tracef, " "); - dprintf(tracefd, "%u: ", getpid()); + p = failpath_string(); + fprintf(tracef, "%i: %u: %s ", idx++, getpid(), p); va_start(ap, fmt); - vdprintf(tracefd, fmt, ap); + vfprintf(tracef, fmt, ap); va_end(ap); + free(p); } static pid_t child; @@ -567,7 +581,7 @@ static void free_everything(void) { struct failtest_call *i; - while ((i = tlist_top(&history, struct failtest_call, list)) != NULL) + while ((i = tlist_top(&history, list)) != NULL) free_call(i); failtable_clear(&failtable); @@ -599,8 +613,10 @@ static NORETURN void failtest_cleanup(bool forced_cleanup, int status) /* But their program shouldn't leak, even on failure. */ if (!forced_cleanup && i->can_leak) { + char *p = failpath_string(); printf("Leak at %s:%u: --failpath=%s\n", - i->file, i->line, failpath_string()); + i->file, i->line, p); + free(p); status = 1; } } @@ -737,39 +753,41 @@ static bool should_fail(struct failtest_call *call) /* Prevent double-printing (in child and parent) */ fflush(stdout); + fflush(warnf); + if (tracef) + fflush(tracef); child = fork(); if (child == -1) err(1, "forking failed"); if (child == 0) { traceindent++; - if (tracefd != -1) { - struct timeval diff; + if (tracef) { + struct timerel diff; const char *p; char *failpath; struct failtest_call *c; - c = tlist_tail(&history, struct failtest_call, list); - diff = time_sub(time_now(), start); + c = tlist_tail(&history, list); + diff = time_between(time_now(), start); failpath = failpath_string(); - trace("%u->%u (%u.%02u): %s (", getppid(), getpid(), - (int)diff.tv_sec, (int)diff.tv_usec / 10000, - failpath); - free(failpath); p = strrchr(c->file, '/'); if (p) - trace("%s", p+1); + p++; else - trace("%s", c->file); - trace(":%u)\n", c->line); + p = c->file; + trace("%u->%u (%u.%02u): %s (%s:%u)\n", + getppid(), getpid(), + (int)diff.ts.tv_sec, (int)diff.ts.tv_nsec / 10000000, + failpath, p, c->line); + free(failpath); } /* From here on, we have to clean up! */ - our_history_start = tlist_tail(&history, struct failtest_call, - list); + our_history_start = tlist_tail(&history, list); close(control[0]); close(output[0]); /* Don't swallow stderr if we're tracing. */ - if (tracefd != -1) { + if (!tracef) { dup2(output[1], STDOUT_FILENO); dup2(output[1], STDERR_FILENO); if (output[1] != STDOUT_FILENO @@ -1069,8 +1087,8 @@ int failtest_open(const char *pathname, call.closed = false; if (call.flags & O_CREAT) { call.mode = va_arg(ap, int); - va_end(ap); } + va_end(ap); p = add_history(FAILTEST_OPEN, true, file, line, &call); /* Avoid memory leak! */ if (p == &unrecorded_call) @@ -1161,6 +1179,15 @@ void *failtest_mmap(void *addr, size_t length, int prot, int flags, return p->u.mmap.ret; } +/* Since OpenBSD can't handle adding args, we use this file and line. + * This will make all mmaps look the same, reducing coverage. */ +void *failtest_mmap_noloc(void *addr, size_t length, int prot, int flags, + int fd, off_t offset) +{ + return failtest_mmap(addr, length, prot, flags, fd, offset, + __FILE__, __LINE__); +} + static void cleanup_pipe(struct pipe_call *call, bool restore) { trace("cleaning up pipe fd=%i%s,%i%s\n", @@ -1235,7 +1262,7 @@ static ssize_t failtest_add_read(int fd, void *buf, size_t count, off_t off, set_cleanup(p, cleanup_read, struct read_call); } } - trace("%sread %s:%u fd %i %zu@%llu -> %i\n", + trace("%sread %s:%u fd %i %zu@%llu -> %zi\n", is_pread ? "p" : "", file, line, fd, count, (long long)off, p->u.read.ret); errno = p->error; @@ -1337,7 +1364,7 @@ static ssize_t failtest_add_write(int fd, const void *buf, else p->u.write.ret = write(fd, buf, count); } - trace("%swrite %s:%i %zu@%llu on fd %i -> %i\n", + trace("%swrite %s:%i %zu@%llu on fd %i -> %zi\n", p->u.write.is_pwrite ? "p" : "", file, line, count, (long long)off, fd, p->u.write.ret); errno = p->error; @@ -1675,12 +1702,12 @@ void failtest_init(int argc, char *argv[]) orig_pid = getpid(); - warnfd = move_fd_to_high(dup(STDERR_FILENO)); + warnf = fdopen(move_fd_to_high(dup(STDERR_FILENO)), "w"); for (i = 1; i < argc; i++) { if (!strncmp(argv[i], "--failpath=", strlen("--failpath="))) { failpath = argv[i] + strlen("--failpath="); } else if (strcmp(argv[i], "--trace") == 0) { - tracefd = warnfd; + tracef = warnf; failtest_timeout_ms = -1; } else if (!strncmp(argv[i], "--debugpath=", strlen("--debugpath="))) {