static const char info_to_arg[] = "mceoprw";
+/* Dummy call used for failtest_undo wrappers. */
+static struct failtest_call unrecorded_call;
+
static struct failtest_call *add_history_(enum failtest_call_type type,
const char *file,
unsigned int line,
const void *elem,
size_t elem_size)
{
+ /* NULL file is how we suppress failure. */
+ if (!file)
+ return &unrecorded_call;
+
history = realloc(history, (history_num + 1) * sizeof(*history));
history[history_num].type = type;
history[history_num].file = file;
char *out = NULL;
size_t outlen = 0;
+ if (call == &unrecorded_call)
+ return false;
+
if (failpath) {
if (tolower(*failpath) != info_to_arg[call->type])
errx(1, "Failpath expected '%c' got '%c'\n",
va_end(ap);
}
p = add_history(FAILTEST_OPEN, file, line, &call);
+ /* Avoid memory leak! */
+ if (p == &unrecorded_call)
+ free((char *)call.pathname);
if (should_fail(p)) {
p->u.open.ret = -1;
/* FIXME: Play with error codes? */
}
}
+/* Free up memory, so valgrind doesn't report leaks. */
+static void free_everything(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < writes_num; i++) {
+ free(writes[i].data);
+ if (writes[i].hdr.offset != (off_t)-1)
+ free(writes[i].olddata);
+ }
+ free(writes);
+ free(fd_orig);
+ for (i = 0; i < history_num; i++) {
+ if (history[i].type == FAILTEST_OPEN)
+ free((char *)history[i].u.open.pathname);
+ }
+ free(history);
+}
+
void failtest_exit(int status)
{
unsigned int i;
- if (control_fd == -1)
+ if (control_fd == -1) {
+ free_everything();
exit(status);
+ }
if (failtest_exit_check) {
if (!failtest_exit_check(history, history_num))
close(fd_orig[i].fd);
}
+ free_everything();
tell_parent(SUCCESS);
exit(0);
}