enum failtest_result (*failtest_hook)(struct tlist_calls *);
static int tracefd = -1;
+static int warnfd;
unsigned int failtest_timeout_ms = 20000;
#define set_cleanup(call, clean, type) \
(call)->cleanup = (void *)((void)sizeof(clean((type *)NULL),1), (clean))
+
+/* Dup the fd to a high value (out of the way I hope!), and close the old fd. */
+static int move_fd_to_high(int fd)
+{
+ int i;
+
+ for (i = FD_SETSIZE - 1; i >= 0; 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);
+ close(fd);
+ return i;
+ }
+ }
+ /* Nothing? Really? Er... ok? */
+ return fd;
+}
+
static bool read_write_info(int fd)
{
struct write_call *w;
return ret;
}
+static void warn_via_fd(int e, const char *fmt, va_list ap)
+{
+ char *p = failpath_string();
+
+ vdprintf(warnfd, fmt, ap);
+ if (e != -1)
+ dprintf(warnfd, ": %s", strerror(e));
+ dprintf(warnfd, " [%s]\n", p);
+ free(p);
+}
+
+static void fwarn(const char *fmt, ...)
+{
+ va_list ap;
+ int e = errno;
+
+ va_start(ap, fmt);
+ warn_via_fd(e, fmt, ap);
+ va_end(ap);
+}
+
+
+static void fwarnx(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ warn_via_fd(-1, fmt, ap);
+ va_end(ap);
+}
+
static void tell_parent(enum info_type type)
{
if (control_fd != -1)
dup2(output[1], STDERR_FILENO);
if (output[1] != STDOUT_FILENO && output[1] != STDERR_FILENO)
close(output[1]);
- control_fd = control[1];
+ control_fd = move_fd_to_high(control[1]);
/* Valgrind spots the leak if we don't free these. */
free_files(files);
return true;
unsigned int i;
orig_pid = getpid();
-
+
+ warnfd = move_fd_to_high(dup(STDERR_FILENO));
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);
+ tracefd = warnfd;
failtest_timeout_ms = -1;
} else if (!strncmp(argv[i], "--debugpath=",
strlen("--debugpath="))) {