+ trace("cleaning up mmap @%p (opener %p)\n",
+ mmap->ret, mmap->opener);
+ if (restore)
+ restore_contents(mmap->opener, mmap->saved, false, "mmap");
+ free(mmap->saved);
+}
+
+void *failtest_mmap(void *addr, size_t length, int prot, int flags,
+ int fd, off_t offset, const char *file, unsigned line)
+{
+ struct failtest_call *p;
+ struct mmap_call call;
+
+ call.addr = addr;
+ call.length = length;
+ call.prot = prot;
+ call.flags = flags;
+ call.offset = offset;
+ call.fd = fd;
+ call.opener = opener_of(fd);
+
+ /* If we don't know what file it was, don't fail. */
+ if (!call.opener) {
+ if (fd != -1) {
+ fwarnx("failtest_mmap: couldn't figure out source for"
+ " fd %i at %s:%u", fd, file, line);
+ }
+ addr = mmap(addr, length, prot, flags, fd, offset);
+ trace("mmap of fd %i -> %p (opener = NULL)\n", fd, addr);
+ return addr;
+ }
+
+ p = add_history(FAILTEST_MMAP, false, file, line, &call);
+ if (should_fail(p)) {
+ p->u.mmap.ret = MAP_FAILED;
+ p->error = ENOMEM;
+ } else {
+ p->u.mmap.ret = mmap(addr, length, prot, flags, fd, offset);
+ /* Save contents if we're writing to a normal file */
+ if (p->u.mmap.ret != MAP_FAILED
+ && (prot & PROT_WRITE)
+ && call.opener->type == FAILTEST_OPEN) {
+ const char *fname = call.opener->u.open.pathname;
+ p->u.mmap.saved = save_contents(fname, fd, length,
+ offset, "being mmapped");
+ set_cleanup(p, cleanup_mmap, struct mmap_call);
+ }
+ }
+ trace("mmap of fd %i %s:%u -> %p (opener = %p)\n",
+ fd, file, line, addr, call.opener);
+ errno = p->error;
+ 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",
+ call->fds[0], call->closed[0] ? "(already closed)" : "",
+ call->fds[1], call->closed[1] ? "(already closed)" : "");