#include <stdio.h>
#include <stdarg.h>
#include <ctype.h>
-#include <err.h>
#include <unistd.h>
#include <poll.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/mman.h>
+#include <sys/resource.h>
#include <signal.h>
#include <assert.h>
+#include <ccan/err/err.h>
#include <ccan/time/time.h>
#include <ccan/read_write_all/read_write_all.h>
#include <ccan/failtest/failtest_proto.h>
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;
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;
}
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);
}
int e = errno;
va_start(ap, fmt);
- warn_via_fd(e, fmt, ap);
+ do_warn(e, fmt, ap);
va_end(ap);
}
va_list ap;
va_start(ap, fmt);
- warn_via_fd(-1, fmt, ap);
+ do_warn(-1, fmt, ap);
va_end(ap);
}
{
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;
{
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);
/* 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) {
+ if (tracef) {
struct timeval diff;
const char *p;
char *failpath;
struct failtest_call *c;
- c = tlist_tail(&history, struct failtest_call, list);
+ c = tlist_tail(&history, list);
diff = time_sub(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.tv_sec, (int)diff.tv_usec / 10000,
+ 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
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",
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="))) {