]> git.ozlabs.org Git - ccan/blob - ccan/failtest/failtest.c
failtest: fix history when --failpath used
[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                 call->fail = isupper(*(failpath++));
269                 return call->fail;
270         }
271
272         if (!failtest_hook(history, history_num)) {
273                 call->fail = false;
274                 return false;
275         }
276
277         /* We're going to fail in the child. */
278         call->fail = true;
279         if (pipe(control) != 0 || pipe(output) != 0)
280                 err(1, "opening pipe");
281
282         /* Prevent double-printing (in child and parent) */
283         fflush(stdout);
284         child = fork();
285         if (child == -1)
286                 err(1, "forking failed");
287
288         if (child == 0) {
289                 close(control[0]);
290                 close(output[0]);
291                 dup2(output[1], STDOUT_FILENO);
292                 dup2(output[1], STDERR_FILENO);
293                 if (output[1] != STDOUT_FILENO && output[1] != STDERR_FILENO)
294                         close(output[1]);
295                 control_fd = control[1];
296                 return true;
297         }
298
299         signal(SIGUSR1, hand_down);
300
301         close(control[1]);
302         close(output[1]);
303
304         /* We grab output so we can display it; we grab writes so we
305          * can compare. */
306         do {
307                 struct pollfd pfd[2];
308                 int ret;
309
310                 pfd[0].fd = output[0];
311                 pfd[0].events = POLLIN|POLLHUP;
312                 pfd[1].fd = control[0];
313                 pfd[1].events = POLLIN|POLLHUP;
314
315                 if (type == SUCCESS)
316                         ret = poll(pfd, 1, failtest_timeout_ms);
317                 else
318                         ret = poll(pfd, 2, failtest_timeout_ms);
319
320                 if (ret <= 0)
321                         hand_down(SIGUSR1);
322
323                 if (pfd[0].revents & POLLIN) {
324                         ssize_t len;
325
326                         out = realloc(out, outlen + 8192);
327                         len = read(output[0], out + outlen, 8192);
328                         outlen += len;
329                 } else if (type != SUCCESS && (pfd[1].revents & POLLIN)) {
330                         if (read_all(control[0], &type, sizeof(type))) {
331                                 if (type == WRITE) {
332                                         if (!read_write_info(control[0]))
333                                                 break;
334                                 } else if (type == RELEASE_LOCKS) {
335                                         release_locks();
336                                         /* FIXME: Tell them we're done... */
337                                 }
338                         }
339                 } else if (pfd[0].revents & POLLHUP) {
340                         break;
341                 }
342         } while (type != FAILURE);
343
344         close(output[0]);
345         close(control[0]);
346         waitpid(child, &status, 0);
347         if (!WIFEXITED(status))
348                 child_fail(out, outlen, "Killed by signal %u: ",
349                            WTERMSIG(status));
350         /* Child printed failure already, just pass up exit code. */
351         if (type == FAILURE) {
352                 fprintf(stderr, "%.*s", (int)outlen, out);
353                 tell_parent(type);
354                 exit(WEXITSTATUS(status) ? WEXITSTATUS(status) : 1);
355         }
356         if (WEXITSTATUS(status) != 0)
357                 child_fail(out, outlen, "Exited with status %i: ",
358                            WEXITSTATUS(status));
359
360         free(out);
361         signal(SIGUSR1, SIG_DFL);
362
363         /* We continue onwards without failing. */
364         call->fail = false;
365         return false;
366 }
367
368 void *failtest_calloc(size_t nmemb, size_t size,
369                       const char *file, unsigned line)
370 {
371         struct failtest_call *p;
372         struct calloc_call call;
373         call.nmemb = nmemb;
374         call.size = size;
375         p = add_history(FAILTEST_CALLOC, file, line, &call);
376
377         if (should_fail(p)) {
378                 p->u.calloc.ret = NULL;
379                 p->error = ENOMEM;
380         } else {
381                 p->u.calloc.ret = calloc(nmemb, size);
382         }
383         errno = p->error;
384         return p->u.calloc.ret;
385 }
386
387 void *failtest_malloc(size_t size, const char *file, unsigned line)
388 {
389         struct failtest_call *p;
390         struct malloc_call call;
391         call.size = size;
392
393         p = add_history(FAILTEST_MALLOC, file, line, &call);
394         if (should_fail(p)) {
395                 p->u.calloc.ret = NULL;
396                 p->error = ENOMEM;
397         } else {
398                 p->u.calloc.ret = malloc(size);
399         }
400         errno = p->error;
401         return p->u.calloc.ret;
402 }
403
404 void *failtest_realloc(void *ptr, size_t size, const char *file, unsigned line)
405 {
406         struct failtest_call *p;
407         struct realloc_call call;
408         call.size = size;
409         p = add_history(FAILTEST_REALLOC, file, line, &call);
410
411         /* FIXME: Try one child moving allocation, one not. */
412         if (should_fail(p)) {
413                 p->u.realloc.ret = NULL;
414                 p->error = ENOMEM;
415         } else {
416                 p->u.realloc.ret = realloc(ptr, size);
417         }
418         errno = p->error;
419         return p->u.realloc.ret;
420 }
421
422 int failtest_open(const char *pathname,
423                   const char *file, unsigned line, ...)
424 {
425         struct failtest_call *p;
426         struct open_call call;
427         va_list ap;
428
429         call.pathname = strdup(pathname);
430         va_start(ap, line);
431         call.flags = va_arg(ap, int);
432         if (call.flags & O_CREAT) {
433                 call.mode = va_arg(ap, mode_t);
434                 va_end(ap);
435         }
436         p = add_history(FAILTEST_OPEN, file, line, &call);
437         /* Avoid memory leak! */
438         if (p == &unrecorded_call)
439                 free((char *)call.pathname);
440         if (should_fail(p)) {
441                 p->u.open.ret = -1;
442                 /* FIXME: Play with error codes? */
443                 p->error = EACCES;
444         } else {
445                 p->u.open.ret = open(pathname, call.flags, call.mode);
446         }
447         errno = p->error;
448         return p->u.open.ret;
449 }
450
451 int failtest_pipe(int pipefd[2], const char *file, unsigned line)
452 {
453         struct failtest_call *p;
454         struct pipe_call call;
455
456         p = add_history(FAILTEST_PIPE, file, line, &call);
457         if (should_fail(p)) {
458                 p->u.open.ret = -1;
459                 /* FIXME: Play with error codes? */
460                 p->error = EMFILE;
461         } else {
462                 p->u.pipe.ret = pipe(p->u.pipe.fds);
463         }
464         /* This causes valgrind to notice if they use pipefd[] after failure */
465         memcpy(pipefd, p->u.pipe.fds, sizeof(p->u.pipe.fds));
466         errno = p->error;
467         return p->u.pipe.ret;
468 }
469
470 ssize_t failtest_pread(int fd, void *buf, size_t count, off_t off,
471                        const char *file, unsigned line)
472 {
473         struct failtest_call *p;
474         struct read_call call;
475         call.fd = fd;
476         call.buf = buf;
477         call.count = count;
478         call.off = off;
479         p = add_history(FAILTEST_READ, file, line, &call);
480
481         /* This is going to change seek offset, so save it. */
482         if (control_fd != -1)
483                 save_fd_orig(fd);
484
485         /* FIXME: Try partial read returns. */
486         if (should_fail(p)) {
487                 p->u.read.ret = -1;
488                 p->error = EIO;
489         } else {
490                 p->u.read.ret = pread(fd, buf, count, off);
491         }
492         errno = p->error;
493         return p->u.read.ret;
494 }
495
496 static struct write_info *new_write(void)
497 {
498         writes = realloc(writes, (writes_num + 1) * sizeof(*writes));
499         return &writes[writes_num++];
500 }
501
502 ssize_t failtest_pwrite(int fd, const void *buf, size_t count, off_t off,
503                         const char *file, unsigned line)
504 {
505         struct failtest_call *p;
506         struct write_call call;
507         off_t offset;
508
509         call.fd = fd;
510         call.buf = buf;
511         call.count = count;
512         call.off = off;
513         p = add_history(FAILTEST_WRITE, file, line, &call);
514
515         offset = lseek(fd, 0, SEEK_CUR);
516
517         /* If we're a child, save contents and tell parent about write. */
518         if (control_fd != -1) {
519                 struct write_info *winfo = new_write();
520                 enum info_type type = WRITE;
521
522                 save_fd_orig(fd);
523
524                 winfo->hdr.len = count;
525                 winfo->hdr.fd = fd;
526                 winfo->data = malloc(count);
527                 memcpy(winfo->data, buf, count);
528                 winfo->hdr.offset = offset;
529                 if (winfo->hdr.offset != (off_t)-1) {
530                         lseek(fd, offset, SEEK_SET);
531                         winfo->olddata = malloc(count);
532                         winfo->oldlen = read(fd, winfo->olddata, count);
533                         if (winfo->oldlen == -1)
534                                 winfo->oldlen = 0;
535                 }
536                 write_all(control_fd, &type, sizeof(type));
537                 write_all(control_fd, &winfo->hdr, sizeof(winfo->hdr));
538                 write_all(control_fd, winfo->data, count);
539         }
540
541         /* FIXME: Try partial write returns. */
542         if (should_fail(p)) {
543                 p->u.write.ret = -1;
544                 p->error = EIO;
545         } else {
546                 /* FIXME: We assume same write order in parent and child */
547                 if (child_writes_num != 0) {
548                         if (child_writes[0].hdr.fd != fd)
549                                 errx(1, "Child wrote to fd %u, not %u?",
550                                      child_writes[0].hdr.fd, fd);
551                         if (child_writes[0].hdr.offset != offset)
552                                 errx(1, "Child wrote to offset %zu, not %zu?",
553                                      (size_t)child_writes[0].hdr.offset,
554                                      (size_t)offset);
555                         if (child_writes[0].hdr.len != count)
556                                 errx(1, "Child wrote length %zu, not %zu?",
557                                      child_writes[0].hdr.len, count);
558                         if (memcmp(child_writes[0].data, buf, count)) {
559                                 child_fail(NULL, 0,
560                                            "Child wrote differently to"
561                                            " fd %u than we did!\n", fd);
562                         }
563                         free(child_writes[0].data);
564                         child_writes_num--;
565                         memmove(&child_writes[0], &child_writes[1],
566                                 sizeof(child_writes[0]) * child_writes_num);
567
568                         /* Is this is a socket or pipe, child wrote it
569                            already. */
570                         if (offset == (off_t)-1) {
571                                 p->u.write.ret = count;
572                                 errno = p->error;
573                                 return p->u.write.ret;
574                         }
575                 }
576                 p->u.write.ret = pwrite(fd, buf, count, off);
577         }
578         errno = p->error;
579         return p->u.write.ret;
580 }
581
582 ssize_t failtest_read(int fd, void *buf, size_t count,
583                       const char *file, unsigned line)
584 {
585         return failtest_pread(fd, buf, count, lseek(fd, 0, SEEK_CUR),
586                               file, line);
587 }
588
589 ssize_t failtest_write(int fd, const void *buf, size_t count,
590                        const char *file, unsigned line)
591 {
592         return failtest_pwrite(fd, buf, count, lseek(fd, 0, SEEK_CUR),
593                                file, line);
594 }
595
596 static struct lock_info *WARN_UNUSED_RESULT
597 add_lock(struct lock_info *locks, int fd, off_t start, off_t end, int type)
598 {
599         unsigned int i;
600         struct lock_info *l;
601
602         for (i = 0; i < lock_num; i++) {
603                 l = &locks[i];
604
605                 if (l->fd != fd)
606                         continue;
607                 /* Four cases we care about:
608                  * Start overlap:
609                  *      l =    |      |
610                  *      new = |   |
611                  * Mid overlap:
612                  *      l =    |      |
613                  *      new =    |  |
614                  * End overlap:
615                  *      l =    |      |
616                  *      new =      |    |
617                  * Total overlap:
618                  *      l =    |      |
619                  *      new = |         |
620                  */
621                 if (start > l->start && end < l->end) {
622                         /* Mid overlap: trim entry, add new one. */
623                         off_t new_start, new_end;
624                         new_start = end + 1;
625                         new_end = l->end;
626                         l->end = start - 1;
627                         locks = add_lock(locks,
628                                          fd, new_start, new_end, l->type);
629                         l = &locks[i];
630                 } else if (start <= l->start && end >= l->end) {
631                         /* Total overlap: eliminate entry. */
632                         l->end = 0;
633                         l->start = 1;
634                 } else if (end >= l->start && end < l->end) {
635                         /* Start overlap: trim entry. */
636                         l->start = end + 1;
637                 } else if (start > l->start && start <= l->end) {
638                         /* End overlap: trim entry. */
639                         l->end = start-1;
640                 }
641                 /* Nothing left?  Remove it. */
642                 if (l->end < l->start) {
643                         memmove(l, l + 1, (--lock_num - i) * sizeof(l[0]));
644                         i--;
645                 }
646         }
647
648         if (type != F_UNLCK) {
649                 locks = realloc(locks, (lock_num + 1) * sizeof(*locks));
650                 l = &locks[lock_num++];
651                 l->fd = fd;
652                 l->start = start;
653                 l->end = end;
654                 l->type = type;
655         }
656         return locks;
657 }
658
659 /* We only trap this so we can dup fds in case we need to restore. */
660 int failtest_close(int fd)
661 {
662         unsigned int i;
663         int newfd = -1;
664
665         for (i = 0; i < fd_orig_num; i++) {
666                 if (fd_orig[i].fd == fd) {
667                         fd_orig[i].fd = newfd = dup(fd);
668                         fd_orig[i].dupped = true;
669                 }
670         }
671
672         for (i = 0; i < writes_num; i++) {
673                 if (writes[i].hdr.fd == fd)
674                         writes[i].hdr.fd = newfd;
675         }
676
677         locks = add_lock(locks, fd, 0, off_max(), F_UNLCK);
678         return close(fd);
679 }
680
681 /* Zero length means "to end of file" */
682 static off_t end_of(off_t start, off_t len)
683 {
684         if (len == 0)
685                 return off_max();
686         return start + len - 1;
687 }
688
689 /* FIXME: This only handles locks, really. */
690 int failtest_fcntl(int fd, const char *file, unsigned line, int cmd, ...)
691 {
692         struct failtest_call *p;
693         struct fcntl_call call;
694         va_list ap;
695
696         call.fd = fd;
697         call.cmd = cmd;
698
699         /* Argument extraction. */
700         switch (cmd) {
701         case F_SETFL:
702         case F_SETFD:
703                 va_start(ap, cmd);
704                 call.arg.l = va_arg(ap, long);
705                 va_end(ap);
706                 return fcntl(fd, cmd, call.arg.l);
707         case F_GETFD:
708         case F_GETFL:
709                 return fcntl(fd, cmd);
710         case F_GETLK:
711                 get_locks();
712                 va_start(ap, cmd);
713                 call.arg.fl = *va_arg(ap, struct flock *);
714                 va_end(ap);
715                 return fcntl(fd, cmd, &call.arg.fl);
716         case F_SETLK:
717         case F_SETLKW:
718                 va_start(ap, cmd);
719                 call.arg.fl = *va_arg(ap, struct flock *);
720                 va_end(ap);
721                 break;
722         default:
723                 /* This means you need to implement it here. */
724                 err(1, "failtest: unknown fcntl %u", cmd);
725         }
726
727         p = add_history(FAILTEST_FCNTL, file, line, &call);
728         get_locks();
729
730         if (should_fail(p)) {
731                 p->u.fcntl.ret = -1;
732                 if (p->u.fcntl.cmd == F_SETLK)
733                         p->error = EAGAIN;
734                 else
735                         p->error = EDEADLK;
736         } else {
737                 p->u.fcntl.ret = fcntl(p->u.fcntl.fd, p->u.fcntl.cmd,
738                                        &p->u.fcntl.arg.fl);
739                 if (p->u.fcntl.ret == -1)
740                         p->error = errno;
741                 else {
742                         /* We don't handle anything else yet. */
743                         assert(p->u.fcntl.arg.fl.l_whence == SEEK_SET);
744                         locks = add_lock(locks,
745                                          p->u.fcntl.fd,
746                                          p->u.fcntl.arg.fl.l_start,
747                                          end_of(p->u.fcntl.arg.fl.l_start,
748                                                 p->u.fcntl.arg.fl.l_len),
749                                          p->u.fcntl.arg.fl.l_type);
750                 }
751         }
752         errno = p->error;
753         return p->u.fcntl.ret;
754 }
755
756 void failtest_init(int argc, char *argv[])
757 {
758         if (argc == 2
759             && strncmp(argv[1], "--failpath=", strlen("--failpath=")) == 0) {
760                 failpath = argv[1] + strlen("--failpath=");
761         }
762 }
763
764 /* Free up memory, so valgrind doesn't report leaks. */
765 static void free_everything(void)
766 {
767         unsigned int i;
768
769         for (i = 0; i < writes_num; i++) {
770                 free(writes[i].data);
771                 if (writes[i].hdr.offset != (off_t)-1)
772                         free(writes[i].olddata);
773         }
774         free(writes);
775         free(fd_orig);
776         for (i = 0; i < history_num; i++) {
777                 if (history[i].type == FAILTEST_OPEN)
778                         free((char *)history[i].u.open.pathname);
779         }
780         free(history);
781 }
782
783 void failtest_exit(int status)
784 {
785         unsigned int i;
786
787         if (control_fd == -1) {
788                 free_everything();
789                 exit(status);
790         }
791
792         if (failtest_exit_check) {
793                 if (!failtest_exit_check(history, history_num))
794                         child_fail(NULL, 0, "failtest_exit_check failed\n");
795         }
796
797         /* Restore any stuff we overwrote. */
798         for (i = 0; i < writes_num; i++) {
799                 if (writes[i].hdr.offset == (off_t)-1)
800                         continue;
801                 if (writes[i].oldlen != 0) {
802                         lseek(writes[i].hdr.fd, writes[i].hdr.offset,
803                               SEEK_SET);
804                         write(writes[i].hdr.fd, writes[i].olddata,
805                               writes[i].oldlen);
806                 }
807         }
808
809         /* Fix up fd offsets, restore sizes. */
810         for (i = 0; i < fd_orig_num; i++) {
811                 lseek(fd_orig[i].fd, fd_orig[i].offset, SEEK_SET);
812                 ftruncate(fd_orig[i].fd, fd_orig[i].size);
813                 /* Free up any file descriptors we dup'ed. */
814                 if (fd_orig[i].dupped)
815                         close(fd_orig[i].fd);
816         }
817
818         free_everything();
819         tell_parent(SUCCESS);
820         exit(0);
821 }