]> git.ozlabs.org Git - ccan/blob - ccan/failtest/failtest.c
a9e1aa49887e0b97b4a4be7c89aeb5c8271e9d24
[ccan] / ccan / failtest / failtest.c
1 #include <stdarg.h>
2 #include <string.h>
3 #include <stdio.h>
4 #include <stdarg.h>
5 #include <ctype.h>
6 #include <err.h>
7 #include <unistd.h>
8 #include <poll.h>
9 #include <errno.h>
10 #include <sys/types.h>
11 #include <sys/wait.h>
12 #include <sys/stat.h>
13 #include <assert.h>
14 #include <ccan/read_write_all/read_write_all.h>
15 #include <ccan/failtest/failtest_proto.h>
16 #include <ccan/failtest/failtest.h>
17 #include <ccan/build_assert/build_assert.h>
18
19 bool (*failtest_hook)(struct failtest_call *history, unsigned num)
20 = failtest_default_hook;
21
22 unsigned int failtest_timeout_ms = 20000;
23
24 const char *failpath;
25
26 enum info_type {
27         WRITE,
28         RELEASE_LOCKS,
29         FAILURE,
30         SUCCESS,
31         UNEXPECTED
32 };
33
34 struct write_info_hdr {
35         size_t len;
36         off_t offset;
37         int fd;
38 };
39
40 struct fd_orig {
41         int fd;
42         off_t offset;
43         size_t size;
44         bool dupped;
45 };
46
47 struct write_info {
48         struct write_info_hdr hdr;
49         char *data;
50         size_t oldlen;
51         char *olddata;
52 };
53
54 struct lock_info {
55         int fd;
56         /* end is inclusive: you can't have a 0-byte lock. */
57         off_t start, end;
58         int type;
59 };
60
61 bool (*failtest_exit_check)(struct failtest_call *history, unsigned num);
62
63 static struct failtest_call *history = NULL;
64 static unsigned int history_num = 0;
65 static int control_fd = -1;
66
67 static struct write_info *writes = NULL;
68 static unsigned int writes_num = 0;
69
70 static struct write_info *child_writes = NULL;
71 static unsigned int child_writes_num = 0;
72
73 static struct fd_orig *fd_orig = NULL;
74 static unsigned int fd_orig_num = 0;
75
76 static pid_t lock_owner;
77 static struct lock_info *locks = NULL;
78 static unsigned int lock_num = 0;
79
80 static const char info_to_arg[] = "mceoprwf";
81
82 /* Dummy call used for failtest_undo wrappers. */
83 static struct failtest_call unrecorded_call;
84
85 static struct failtest_call *add_history_(enum failtest_call_type type,
86                                           const char *file,
87                                           unsigned int line,
88                                           const void *elem,
89                                           size_t elem_size)
90 {
91         /* NULL file is how we suppress failure. */
92         if (!file)
93                 return &unrecorded_call;
94
95         history = realloc(history, (history_num + 1) * sizeof(*history));
96         history[history_num].type = type;
97         history[history_num].file = file;
98         history[history_num].line = line;
99         memcpy(&history[history_num].u, elem, elem_size);
100         return &history[history_num++];
101 }
102
103 #define add_history(type, file, line, elem) \
104         add_history_((type), (file), (line), (elem), sizeof(*(elem)))
105
106 static void save_fd_orig(int fd)
107 {
108         unsigned int i;
109
110         for (i = 0; i < fd_orig_num; i++)
111                 if (fd_orig[i].fd == fd)
112                         return;
113
114         fd_orig = realloc(fd_orig, (fd_orig_num + 1) * sizeof(*fd_orig));
115         fd_orig[fd_orig_num].fd = fd;
116         fd_orig[fd_orig_num].dupped = false;
117         fd_orig[fd_orig_num].offset = lseek(fd, 0, SEEK_CUR);
118         fd_orig[fd_orig_num].size = lseek(fd, 0, SEEK_END);
119         lseek(fd, fd_orig[fd_orig_num].offset, SEEK_SET);
120         fd_orig_num++;
121 }
122
123 bool failtest_default_hook(struct failtest_call *history, unsigned num)
124 {
125         return true;
126 }
127
128 static bool read_write_info(int fd)
129 {
130         struct write_info_hdr hdr;
131
132         if (!read_all(fd, &hdr, sizeof(hdr)))
133                 return false;
134
135         child_writes = realloc(child_writes,
136                                (child_writes_num+1) * sizeof(child_writes[0]));
137         child_writes[child_writes_num].hdr = hdr;
138         child_writes[child_writes_num].data = malloc(hdr.len);
139         if (!read_all(fd, child_writes[child_writes_num].data, hdr.len))
140                 return false;
141
142         child_writes_num++;
143         return true;
144 }
145
146 static void print_reproduce(void)
147 {
148         unsigned int i;
149
150         printf("To reproduce: --failpath=");
151         for (i = 0; i < history_num; i++) {
152                 if (history[i].fail)
153                         printf("%c", toupper(info_to_arg[history[i].type]));
154                 else
155                         printf("%c", info_to_arg[history[i].type]);
156         }
157         printf("\n");
158 }
159
160 static void tell_parent(enum info_type type)
161 {
162         if (control_fd != -1)
163                 write_all(control_fd, &type, sizeof(type));
164 }
165
166 static void child_fail(const char *out, size_t outlen, const char *fmt, ...)
167 {
168         va_list ap;
169
170         va_start(ap, fmt);
171         vfprintf(stderr, fmt, ap);
172         va_end(ap);
173
174         fprintf(stderr, "%.*s", (int)outlen, out);
175         print_reproduce();
176         tell_parent(FAILURE);
177         exit(1);
178 }
179
180 static pid_t child;
181
182 static void hand_down(int signal)
183 {
184         kill(child, signal);
185 }
186
187 static void release_locks(void)
188 {
189         /* Locks were never acquired/reacquired? */
190         if (lock_owner == 0)
191                 return;
192
193         /* We own them?  Release them all. */
194         if (lock_owner == getpid()) {
195                 unsigned int i;
196                 struct flock fl;
197                 fl.l_type = F_UNLCK;
198                 fl.l_whence = SEEK_SET;
199                 fl.l_start = 0;
200                 fl.l_len = 0;
201
202                 for (i = 0; i < lock_num; i++)
203                         fcntl(locks[i].fd, F_SETLK, &fl);
204         } else {
205                 /* Our parent must have them; pass request up. */
206                 enum info_type type = RELEASE_LOCKS;
207                 assert(control_fd != -1);
208                 write_all(control_fd, &type, sizeof(type));
209         }
210         lock_owner = 0;
211 }
212
213 /* off_t is a signed type.  Getting its max is non-trivial. */
214 static off_t off_max(void)
215 {
216         BUILD_ASSERT(sizeof(off_t) == 4 || sizeof(off_t) == 8);
217         if (sizeof(off_t) == 4)
218                 return (off_t)0x7FFFFFF;
219         else
220                 return (off_t)0x7FFFFFFFFFFFFFFULL;
221 }
222
223 static void get_locks(void)
224 {
225         unsigned int i;
226         struct flock fl;
227
228         if (lock_owner == getpid())
229                 return;
230
231         if (lock_owner != 0) {
232                 enum info_type type = RELEASE_LOCKS;
233                 assert(control_fd != -1);
234                 write_all(control_fd, &type, sizeof(type));
235         }
236
237         fl.l_whence = SEEK_SET;
238
239         for (i = 0; i < lock_num; i++) {
240                 fl.l_type = locks[i].type;
241                 fl.l_start = locks[i].start;
242                 if (locks[i].end == off_max())
243                         fl.l_len = 0;
244                 else
245                         fl.l_len = locks[i].end - locks[i].start + 1;
246
247                 if (fcntl(locks[i].fd, F_SETLKW, &fl) != 0)
248                         abort();
249         }
250         lock_owner = getpid();
251 }
252
253 static bool should_fail(struct failtest_call *call)
254 {
255         int status;
256         int control[2], output[2];
257         enum info_type type = UNEXPECTED;
258         char *out = NULL;
259         size_t outlen = 0;
260
261         if (call == &unrecorded_call)
262                 return false;
263
264         if (failpath) {
265                 if (tolower(*failpath) != info_to_arg[call->type])
266                         errx(1, "Failpath expected '%c' got '%c'\n",
267                              info_to_arg[call->type], *failpath);
268                 return isupper(*(failpath++));
269         }
270
271         if (!failtest_hook(history, history_num)) {
272                 call->fail = false;
273                 return false;
274         }
275
276         /* We're going to fail in the child. */
277         call->fail = true;
278         if (pipe(control) != 0 || pipe(output) != 0)
279                 err(1, "opening pipe");
280
281         /* Prevent double-printing (in child and parent) */
282         fflush(stdout);
283         child = fork();
284         if (child == -1)
285                 err(1, "forking failed");
286
287         if (child == 0) {
288                 close(control[0]);
289                 close(output[0]);
290                 dup2(output[1], STDOUT_FILENO);
291                 dup2(output[1], STDERR_FILENO);
292                 if (output[1] != STDOUT_FILENO && output[1] != STDERR_FILENO)
293                         close(output[1]);
294                 control_fd = control[1];
295                 return true;
296         }
297
298         signal(SIGUSR1, hand_down);
299
300         close(control[1]);
301         close(output[1]);
302
303         /* We grab output so we can display it; we grab writes so we
304          * can compare. */
305         do {
306                 struct pollfd pfd[2];
307                 int ret;
308
309                 pfd[0].fd = output[0];
310                 pfd[0].events = POLLIN|POLLHUP;
311                 pfd[1].fd = control[0];
312                 pfd[1].events = POLLIN|POLLHUP;
313
314                 if (type == SUCCESS)
315                         ret = poll(pfd, 1, failtest_timeout_ms);
316                 else
317                         ret = poll(pfd, 2, failtest_timeout_ms);
318
319                 if (ret <= 0)
320                         hand_down(SIGUSR1);
321
322                 if (pfd[0].revents & POLLIN) {
323                         ssize_t len;
324
325                         out = realloc(out, outlen + 8192);
326                         len = read(output[0], out + outlen, 8192);
327                         outlen += len;
328                 } else if (type != SUCCESS && (pfd[1].revents & POLLIN)) {
329                         if (read_all(control[0], &type, sizeof(type))) {
330                                 if (type == WRITE) {
331                                         if (!read_write_info(control[0]))
332                                                 break;
333                                 } else if (type == RELEASE_LOCKS) {
334                                         release_locks();
335                                         /* FIXME: Tell them we're done... */
336                                 }
337                         }
338                 } else if (pfd[0].revents & POLLHUP) {
339                         break;
340                 }
341         } while (type != FAILURE);
342
343         close(output[0]);
344         close(control[0]);
345         waitpid(child, &status, 0);
346         if (!WIFEXITED(status))
347                 child_fail(out, outlen, "Killed by signal %u: ",
348                            WTERMSIG(status));
349         /* Child printed failure already, just pass up exit code. */
350         if (type == FAILURE) {
351                 fprintf(stderr, "%.*s", (int)outlen, out);
352                 tell_parent(type);
353                 exit(WEXITSTATUS(status) ? WEXITSTATUS(status) : 1);
354         }
355         if (WEXITSTATUS(status) != 0)
356                 child_fail(out, outlen, "Exited with status %i: ",
357                            WEXITSTATUS(status));
358
359         free(out);
360         signal(SIGUSR1, SIG_DFL);
361
362         /* We continue onwards without failing. */
363         call->fail = false;
364         return false;
365 }
366
367 void *failtest_calloc(size_t nmemb, size_t size,
368                       const char *file, unsigned line)
369 {
370         struct failtest_call *p;
371         struct calloc_call call;
372         call.nmemb = nmemb;
373         call.size = size;
374         p = add_history(FAILTEST_CALLOC, file, line, &call);
375
376         if (should_fail(p)) {
377                 p->u.calloc.ret = NULL;
378                 p->error = ENOMEM;
379         } else {
380                 p->u.calloc.ret = calloc(nmemb, size);
381         }
382         errno = p->error;
383         return p->u.calloc.ret;
384 }
385
386 void *failtest_malloc(size_t size, const char *file, unsigned line)
387 {
388         struct failtest_call *p;
389         struct malloc_call call;
390         call.size = size;
391
392         p = add_history(FAILTEST_MALLOC, file, line, &call);
393         if (should_fail(p)) {
394                 p->u.calloc.ret = NULL;
395                 p->error = ENOMEM;
396         } else {
397                 p->u.calloc.ret = malloc(size);
398         }
399         errno = p->error;
400         return p->u.calloc.ret;
401 }
402
403 void *failtest_realloc(void *ptr, size_t size, const char *file, unsigned line)
404 {
405         struct failtest_call *p;
406         struct realloc_call call;
407         call.size = size;
408         p = add_history(FAILTEST_REALLOC, file, line, &call);
409
410         /* FIXME: Try one child moving allocation, one not. */
411         if (should_fail(p)) {
412                 p->u.realloc.ret = NULL;
413                 p->error = ENOMEM;
414         } else {
415                 p->u.realloc.ret = realloc(ptr, size);
416         }
417         errno = p->error;
418         return p->u.realloc.ret;
419 }
420
421 int failtest_open(const char *pathname,
422                   const char *file, unsigned line, ...)
423 {
424         struct failtest_call *p;
425         struct open_call call;
426         va_list ap;
427
428         call.pathname = strdup(pathname);
429         va_start(ap, line);
430         call.flags = va_arg(ap, int);
431         if (call.flags & O_CREAT) {
432                 call.mode = va_arg(ap, mode_t);
433                 va_end(ap);
434         }
435         p = add_history(FAILTEST_OPEN, file, line, &call);
436         /* Avoid memory leak! */
437         if (p == &unrecorded_call)
438                 free((char *)call.pathname);
439         if (should_fail(p)) {
440                 p->u.open.ret = -1;
441                 /* FIXME: Play with error codes? */
442                 p->error = EACCES;
443         } else {
444                 p->u.open.ret = open(pathname, call.flags, call.mode);
445         }
446         errno = p->error;
447         return p->u.open.ret;
448 }
449
450 int failtest_pipe(int pipefd[2], const char *file, unsigned line)
451 {
452         struct failtest_call *p;
453         struct pipe_call call;
454
455         p = add_history(FAILTEST_PIPE, file, line, &call);
456         if (should_fail(p)) {
457                 p->u.open.ret = -1;
458                 /* FIXME: Play with error codes? */
459                 p->error = EMFILE;
460         } else {
461                 p->u.pipe.ret = pipe(p->u.pipe.fds);
462         }
463         /* This causes valgrind to notice if they use pipefd[] after failure */
464         memcpy(pipefd, p->u.pipe.fds, sizeof(p->u.pipe.fds));
465         errno = p->error;
466         return p->u.pipe.ret;
467 }
468
469 ssize_t failtest_pread(int fd, void *buf, size_t count, off_t off,
470                        const char *file, unsigned line)
471 {
472         struct failtest_call *p;
473         struct read_call call;
474         call.fd = fd;
475         call.buf = buf;
476         call.count = count;
477         call.off = off;
478         p = add_history(FAILTEST_READ, file, line, &call);
479
480         /* This is going to change seek offset, so save it. */
481         if (control_fd != -1)
482                 save_fd_orig(fd);
483
484         /* FIXME: Try partial read returns. */
485         if (should_fail(p)) {
486                 p->u.read.ret = -1;
487                 p->error = EIO;
488         } else {
489                 p->u.read.ret = pread(fd, buf, count, off);
490         }
491         errno = p->error;
492         return p->u.read.ret;
493 }
494
495 static struct write_info *new_write(void)
496 {
497         writes = realloc(writes, (writes_num + 1) * sizeof(*writes));
498         return &writes[writes_num++];
499 }
500
501 ssize_t failtest_pwrite(int fd, const void *buf, size_t count, off_t off,
502                         const char *file, unsigned line)
503 {
504         struct failtest_call *p;
505         struct write_call call;
506         off_t offset;
507
508         call.fd = fd;
509         call.buf = buf;
510         call.count = count;
511         call.off = off;
512         p = add_history(FAILTEST_WRITE, file, line, &call);
513
514         offset = lseek(fd, 0, SEEK_CUR);
515
516         /* If we're a child, save contents and tell parent about write. */
517         if (control_fd != -1) {
518                 struct write_info *winfo = new_write();
519                 enum info_type type = WRITE;
520
521                 save_fd_orig(fd);
522
523                 winfo->hdr.len = count;
524                 winfo->hdr.fd = fd;
525                 winfo->data = malloc(count);
526                 memcpy(winfo->data, buf, count);
527                 winfo->hdr.offset = offset;
528                 if (winfo->hdr.offset != (off_t)-1) {
529                         lseek(fd, offset, SEEK_SET);
530                         winfo->olddata = malloc(count);
531                         winfo->oldlen = read(fd, winfo->olddata, count);
532                         if (winfo->oldlen == -1)
533                                 winfo->oldlen = 0;
534                 }
535                 write_all(control_fd, &type, sizeof(type));
536                 write_all(control_fd, &winfo->hdr, sizeof(winfo->hdr));
537                 write_all(control_fd, winfo->data, count);
538         }
539
540         /* FIXME: Try partial write returns. */
541         if (should_fail(p)) {
542                 p->u.write.ret = -1;
543                 p->error = EIO;
544         } else {
545                 /* FIXME: We assume same write order in parent and child */
546                 if (child_writes_num != 0) {
547                         if (child_writes[0].hdr.fd != fd)
548                                 errx(1, "Child wrote to fd %u, not %u?",
549                                      child_writes[0].hdr.fd, fd);
550                         if (child_writes[0].hdr.offset != offset)
551                                 errx(1, "Child wrote to offset %zu, not %zu?",
552                                      (size_t)child_writes[0].hdr.offset,
553                                      (size_t)offset);
554                         if (child_writes[0].hdr.len != count)
555                                 errx(1, "Child wrote length %zu, not %zu?",
556                                      child_writes[0].hdr.len, count);
557                         if (memcmp(child_writes[0].data, buf, count)) {
558                                 child_fail(NULL, 0,
559                                            "Child wrote differently to"
560                                            " fd %u than we did!\n", fd);
561                         }
562                         free(child_writes[0].data);
563                         child_writes_num--;
564                         memmove(&child_writes[0], &child_writes[1],
565                                 sizeof(child_writes[0]) * child_writes_num);
566
567                         /* Is this is a socket or pipe, child wrote it
568                            already. */
569                         if (offset == (off_t)-1) {
570                                 p->u.write.ret = count;
571                                 errno = p->error;
572                                 return p->u.write.ret;
573                         }
574                 }
575                 p->u.write.ret = pwrite(fd, buf, count, off);
576         }
577         errno = p->error;
578         return p->u.write.ret;
579 }
580
581 ssize_t failtest_read(int fd, void *buf, size_t count,
582                       const char *file, unsigned line)
583 {
584         return failtest_pread(fd, buf, count, lseek(fd, 0, SEEK_CUR),
585                               file, line);
586 }
587
588 ssize_t failtest_write(int fd, const void *buf, size_t count,
589                        const char *file, unsigned line)
590 {
591         return failtest_pwrite(fd, buf, count, lseek(fd, 0, SEEK_CUR),
592                                file, line);
593 }
594
595 static struct lock_info *WARN_UNUSED_RESULT
596 add_lock(struct lock_info *locks, int fd, off_t start, off_t end, int type)
597 {
598         unsigned int i;
599         struct lock_info *l;
600
601         for (i = 0; i < lock_num; i++) {
602                 l = &locks[i];
603
604                 if (l->fd != fd)
605                         continue;
606                 /* Four cases we care about:
607                  * Start overlap:
608                  *      l =    |      |
609                  *      new = |   |
610                  * Mid overlap:
611                  *      l =    |      |
612                  *      new =    |  |
613                  * End overlap:
614                  *      l =    |      |
615                  *      new =      |    |
616                  * Total overlap:
617                  *      l =    |      |
618                  *      new = |         |
619                  */
620                 if (start > l->start && end < l->end) {
621                         /* Mid overlap: trim entry, add new one. */
622                         off_t new_start, new_end;
623                         new_start = end + 1;
624                         new_end = l->end;
625                         l->end = start - 1;
626                         locks = add_lock(locks,
627                                          fd, new_start, new_end, l->type);
628                         l = &locks[i];
629                 } else if (start <= l->start && end >= l->end) {
630                         /* Total overlap: eliminate entry. */
631                         l->end = 0;
632                         l->start = 1;
633                 } else if (end >= l->start && end < l->end) {
634                         /* Start overlap: trim entry. */
635                         l->start = end + 1;
636                 } else if (start > l->start && start <= l->end) {
637                         /* End overlap: trim entry. */
638                         l->end = start-1;
639                 }
640                 /* Nothing left?  Remove it. */
641                 if (l->end < l->start) {
642                         memmove(l, l + 1, (--lock_num - i) * sizeof(l[0]));
643                         i--;
644                 }
645         }
646
647         if (type != F_UNLCK) {
648                 locks = realloc(locks, (lock_num + 1) * sizeof(*locks));
649                 l = &locks[lock_num++];
650                 l->fd = fd;
651                 l->start = start;
652                 l->end = end;
653                 l->type = type;
654         }
655         return locks;
656 }
657
658 /* We only trap this so we can dup fds in case we need to restore. */
659 int failtest_close(int fd)
660 {
661         unsigned int i;
662         int newfd = -1;
663
664         for (i = 0; i < fd_orig_num; i++) {
665                 if (fd_orig[i].fd == fd) {
666                         fd_orig[i].fd = newfd = dup(fd);
667                         fd_orig[i].dupped = true;
668                 }
669         }
670
671         for (i = 0; i < writes_num; i++) {
672                 if (writes[i].hdr.fd == fd)
673                         writes[i].hdr.fd = newfd;
674         }
675
676         locks = add_lock(locks, fd, 0, off_max(), F_UNLCK);
677         return close(fd);
678 }
679
680 /* Zero length means "to end of file" */
681 static off_t end_of(off_t start, off_t len)
682 {
683         if (len == 0)
684                 return off_max();
685         return start + len - 1;
686 }
687
688 /* FIXME: This only handles locks, really. */
689 int failtest_fcntl(int fd, const char *file, unsigned line, int cmd, ...)
690 {
691         struct failtest_call *p;
692         struct fcntl_call call;
693         va_list ap;
694
695         call.fd = fd;
696         call.cmd = cmd;
697
698         /* Argument extraction. */
699         switch (cmd) {
700         case F_SETFL:
701         case F_SETFD:
702                 va_start(ap, cmd);
703                 call.arg.l = va_arg(ap, long);
704                 va_end(ap);
705                 return fcntl(fd, cmd, call.arg.l);
706         case F_GETFD:
707         case F_GETFL:
708                 return fcntl(fd, cmd);
709         case F_GETLK:
710                 get_locks();
711                 va_start(ap, cmd);
712                 call.arg.fl = *va_arg(ap, struct flock *);
713                 va_end(ap);
714                 return fcntl(fd, cmd, &call.arg.fl);
715         case F_SETLK:
716         case F_SETLKW:
717                 va_start(ap, cmd);
718                 call.arg.fl = *va_arg(ap, struct flock *);
719                 va_end(ap);
720                 break;
721         default:
722                 /* This means you need to implement it here. */
723                 err(1, "failtest: unknown fcntl %u", cmd);
724         }
725
726         p = add_history(FAILTEST_FCNTL, file, line, &call);
727         get_locks();
728
729         if (should_fail(p)) {
730                 p->u.fcntl.ret = -1;
731                 if (p->u.fcntl.cmd == F_SETLK)
732                         p->error = EAGAIN;
733                 else
734                         p->error = EDEADLK;
735         } else {
736                 p->u.fcntl.ret = fcntl(p->u.fcntl.fd, p->u.fcntl.cmd,
737                                        &p->u.fcntl.arg.fl);
738                 if (p->u.fcntl.ret == -1)
739                         p->error = errno;
740                 else {
741                         /* We don't handle anything else yet. */
742                         assert(p->u.fcntl.arg.fl.l_whence == SEEK_SET);
743                         locks = add_lock(locks,
744                                          p->u.fcntl.fd,
745                                          p->u.fcntl.arg.fl.l_start,
746                                          end_of(p->u.fcntl.arg.fl.l_start,
747                                                 p->u.fcntl.arg.fl.l_len),
748                                          p->u.fcntl.arg.fl.l_type);
749                 }
750         }
751         errno = p->error;
752         return p->u.fcntl.ret;
753 }
754
755 void failtest_init(int argc, char *argv[])
756 {
757         if (argc == 2
758             && strncmp(argv[1], "--failpath=", strlen("--failpath=")) == 0) {
759                 failpath = argv[1] + strlen("--failpath=");
760         }
761 }
762
763 /* Free up memory, so valgrind doesn't report leaks. */
764 static void free_everything(void)
765 {
766         unsigned int i;
767
768         for (i = 0; i < writes_num; i++) {
769                 free(writes[i].data);
770                 if (writes[i].hdr.offset != (off_t)-1)
771                         free(writes[i].olddata);
772         }
773         free(writes);
774         free(fd_orig);
775         for (i = 0; i < history_num; i++) {
776                 if (history[i].type == FAILTEST_OPEN)
777                         free((char *)history[i].u.open.pathname);
778         }
779         free(history);
780 }
781
782 void failtest_exit(int status)
783 {
784         unsigned int i;
785
786         if (control_fd == -1) {
787                 free_everything();
788                 exit(status);
789         }
790
791         if (failtest_exit_check) {
792                 if (!failtest_exit_check(history, history_num))
793                         child_fail(NULL, 0, "failtest_exit_check failed\n");
794         }
795
796         /* Restore any stuff we overwrote. */
797         for (i = 0; i < writes_num; i++) {
798                 if (writes[i].hdr.offset == (off_t)-1)
799                         continue;
800                 if (writes[i].oldlen != 0) {
801                         lseek(writes[i].hdr.fd, writes[i].hdr.offset,
802                               SEEK_SET);
803                         write(writes[i].hdr.fd, writes[i].olddata,
804                               writes[i].oldlen);
805                 }
806         }
807
808         /* Fix up fd offsets, restore sizes. */
809         for (i = 0; i < fd_orig_num; i++) {
810                 lseek(fd_orig[i].fd, fd_orig[i].offset, SEEK_SET);
811                 ftruncate(fd_orig[i].fd, fd_orig[i].size);
812                 /* Free up any file descriptors we dup'ed. */
813                 if (fd_orig[i].dupped)
814                         close(fd_orig[i].fd);
815         }
816
817         free_everything();
818         tell_parent(SUCCESS);
819         exit(0);
820 }