[Midnightbsd-cvs] src [11974] trunk/tests/sys/file: add file tests

laffer1 at midnightbsd.org laffer1 at midnightbsd.org
Sat Jul 28 17:14:09 EDT 2018


Revision: 11974
          http://svnweb.midnightbsd.org/src/?rev=11974
Author:   laffer1
Date:     2018-07-28 17:14:08 -0400 (Sat, 28 Jul 2018)
Log Message:
-----------
add file tests

Added Paths:
-----------
    trunk/tests/sys/file/
    trunk/tests/sys/file/Makefile
    trunk/tests/sys/file/closefrom_test.c
    trunk/tests/sys/file/dup_test.c
    trunk/tests/sys/file/fcntlflags_test.c
    trunk/tests/sys/file/flock_helper.c
    trunk/tests/sys/file/flock_test.sh
    trunk/tests/sys/file/ftruncate_test.c
    trunk/tests/sys/file/newfileops_on_fork_test.c

Added: trunk/tests/sys/file/Makefile
===================================================================
--- trunk/tests/sys/file/Makefile	                        (rev 0)
+++ trunk/tests/sys/file/Makefile	2018-07-28 21:14:08 UTC (rev 11974)
@@ -0,0 +1,26 @@
+# $MidnightBSD$
+# $FreeBSD: stable/10/tests/sys/file/Makefile 282067 2015-04-27 08:15:17Z ngie $
+
+TESTSDIR=	${TESTSBASE}/sys/file
+
+BINDIR=		${TESTSDIR}
+
+TAP_TESTS_C+=	closefrom_test
+TAP_TESTS_C+=	dup_test
+TAP_TESTS_C+=	fcntlflags_test
+TAP_TESTS_SH+=	flock_test
+PLAIN_TESTS_C+=	ftruncate_test
+PLAIN_TESTS_C+=	newfileops_on_fork_test
+
+PROGS+=		flock_helper
+
+DPADD.closefrom_test=	${LIBUTIL}
+LDADD.closefrom_test=	-lutil
+
+DPADD.flock_helper=	${LIBPTHREAD}
+LDADD.flock_helper=	-lpthread
+
+DPADD.newfileops_on_fork_test=	${LIBPTHREAD}
+LDADD.newfileops_on_fork_test=	-lpthread
+
+.include <bsd.test.mk>


Property changes on: trunk/tests/sys/file/Makefile
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/tests/sys/file/closefrom_test.c
===================================================================
--- trunk/tests/sys/file/closefrom_test.c	                        (rev 0)
+++ trunk/tests/sys/file/closefrom_test.c	2018-07-28 21:14:08 UTC (rev 11974)
@@ -0,0 +1,276 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2009 Hudson River Trading LLC
+ * Written by: John H. Baldwin <jhb at FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/10/tests/sys/file/closefrom_test.c 282067 2015-04-27 08:15:17Z ngie $");
+
+/*
+ * Regression tests for the closefrom(2) system call.
+ */
+
+#include <sys/param.h>
+#include <sys/mman.h>
+#include <sys/user.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libutil.h>
+#include <paths.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+struct shared_info {
+	int	failed;
+	char	tag[64];
+	char	message[0];
+};
+
+static int test = 1;
+
+static void
+ok(const char *descr)
+{
+
+	printf("ok %d - %s\n", test, descr);
+	test++;
+}
+
+static void
+fail(const char *descr, const char *fmt, ...)
+{
+	va_list ap;
+
+	printf("not ok %d - %s", test, descr);
+	test++;
+	if (fmt) {
+		va_start(ap, fmt);
+		printf(" # ");
+		vprintf(fmt, ap);
+		va_end(ap);
+	}
+	printf("\n");
+	exit(1);
+}
+
+#define	fail_err(descr)		fail((descr), "%s", strerror(errno))
+
+static void
+cok(struct shared_info *info, const char *descr)
+{
+
+	info->failed = 0;
+	strlcpy(info->tag, descr, sizeof(info->tag));
+	exit(0);
+}
+
+static void
+cfail(struct shared_info *info, const char *descr, const char *fmt, ...)
+{
+	va_list ap;
+
+	info->failed = 1;
+	strlcpy(info->tag, descr, sizeof(info->tag));
+	if (fmt) {
+		va_start(ap, fmt);
+		vsprintf(info->message, fmt, ap);
+		va_end(ap);
+	}
+	exit(0);
+}
+
+#define	cfail_err(info, descr)	cfail((info), (descr), "%s", strerror(errno))
+
+/*
+ * Use kinfo_getfile() to fetch the list of file descriptors and figure out
+ * the highest open file descriptor.
+ */
+static int
+highest_fd(void)
+{
+	struct kinfo_file *kif;
+	int cnt, i, highest;
+
+	kif = kinfo_getfile(getpid(), &cnt);
+	if (kif == NULL)
+		fail_err("kinfo_getfile");
+	highest = INT_MIN;
+	for (i = 0; i < cnt; i++)
+		if (kif[i].kf_fd > highest)
+			highest = kif[i].kf_fd;
+	free(kif);
+	return (highest);
+}
+
+static int
+devnull(void)
+{
+	int fd;
+
+	fd = open(_PATH_DEVNULL, O_RDONLY);
+	if (fd < 0)
+		fail_err("open(\" "_PATH_DEVNULL" \")");
+	return (fd);
+}
+
+int
+main(void)
+{
+	struct shared_info *info;
+	pid_t pid;
+	int fd, i, start;
+
+	printf("1..15\n");
+
+	/* We better start up with fd's 0, 1, and 2 open. */
+	start = devnull();
+	if (start == -1)
+		fail("open", "bad descriptor %d", start);
+	ok("open");
+
+	/* Make sure highest_fd() works. */
+	fd = highest_fd();
+	if (start != fd)
+		fail("highest_fd", "bad descriptor %d != %d", start, fd);
+	ok("highest_fd");
+
+	/* Try to use closefrom() for just closing fd 3. */
+	closefrom(start + 1);
+	fd = highest_fd();
+	if (fd != start)
+		fail("closefrom", "highest fd %d", fd);
+	ok("closefrom");
+
+	/* Eat up 16 descriptors. */
+	for (i = 0; i < 16; i++)
+		(void)devnull();
+	fd = highest_fd();
+	if (fd != start + 16)
+		fail("open 16", "highest fd %d", fd);
+	ok("open 16");
+
+	/* Close half of them. */
+	closefrom(11);
+	fd = highest_fd();
+	if (fd != 10)
+		fail("closefrom", "highest fd %d", fd);
+	ok("closefrom");
+
+	/* Explicitly close descriptors 6 and 8 to create holes. */
+	if (close(6) < 0 || close(8) < 0)
+		fail_err("close2 ");
+	ok("close 2");
+
+	/* Verify that close on 6 and 8 fails with EBADF. */
+	if (close(6) == 0)
+		fail("close(6)", "did not fail");
+	if (errno != EBADF)
+		fail_err("close(6)");
+	ok("close(6)");
+	if (close(8) == 0)
+		fail("close(8)", "did not fail");
+	if (errno != EBADF)
+		fail_err("close(8)");
+	ok("close(8)");
+
+	/* Close from 4 on. */
+	closefrom(4);
+	fd = highest_fd();
+	if (fd != 3)
+		fail("closefrom", "highest fd %d", fd);
+	ok("closefrom");
+
+	/* Allocate a small SHM region for IPC with our child. */
+	info = mmap(NULL, getpagesize(), PROT_READ | PROT_WRITE, MAP_ANON |
+	    MAP_SHARED, -1, 0);
+	if (info == MAP_FAILED)
+		fail_err("mmap");
+	ok("mmap");
+
+	/* Fork a child process to test closefrom(0). */
+	pid = fork();
+	if (pid < 0)
+		fail_err("fork");
+	if (pid == 0) {
+		/* Child. */
+		closefrom(0);
+		fd = highest_fd();
+		if (fd >= 0)
+			cfail(info, "closefrom(0)", "highest fd %d", fd);
+		cok(info, "closefrom(0)");
+	}
+	if (wait(NULL) < 0)
+		fail_err("wait");
+	if (info->failed)
+		fail(info->tag, "%s", info->message);
+	ok(info->tag);
+
+	/* Fork a child process to test closefrom(-1). */
+	pid = fork();
+	if (pid < 0)
+		fail_err("fork");
+	if (pid == 0) {
+		/* Child. */
+		closefrom(-1);
+		fd = highest_fd();
+		if (fd >= 0)
+			cfail(info, "closefrom(-1)", "highest fd %d", fd);
+		cok(info, "closefrom(-1)");
+	}
+	if (wait(NULL) < 0)
+		fail_err("wait");
+	if (info->failed)
+		fail(info->tag, "%s", info->message);
+	ok(info->tag);
+
+	/* Dup stdout to 6. */
+	if (dup2(1, 6) < 0)
+		fail_err("dup2");
+	fd = highest_fd();
+	if (fd != 6)
+		fail("dup2", "highest fd %d", fd);
+	ok("dup2");
+
+	/* Do a closefrom() starting in a hole. */
+	closefrom(4);
+	fd = highest_fd();
+	if (fd != 3)
+		fail("closefrom", "highest fd %d", fd);
+	ok("closefrom");
+
+	/* Do a closefrom() beyond our highest open fd. */
+	closefrom(32);
+	fd = highest_fd();
+	if (fd != 3)
+		fail("closefrom", "highest fd %d", fd);
+	ok("closefrom");
+
+	return (0);
+}


Property changes on: trunk/tests/sys/file/closefrom_test.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/tests/sys/file/dup_test.c
===================================================================
--- trunk/tests/sys/file/dup_test.c	                        (rev 0)
+++ trunk/tests/sys/file/dup_test.c	2018-07-28 21:14:08 UTC (rev 11974)
@@ -0,0 +1,387 @@
+/* $MidnightBSD$ */
+/*
+ * $OpenBSD: dup2test.c,v 1.3 2003/07/31 21:48:08 deraadt Exp $
+ * $OpenBSD: dup2_self.c,v 1.3 2003/07/31 21:48:08 deraadt Exp $
+ * $OpenBSD: fcntl_dup.c,v 1.2 2003/07/31 21:48:08 deraadt Exp $
+ *
+ * Written by Artur Grabowski <art at openbsd.org> 2002 Public Domain.
+ *
+ * $FreeBSD: stable/10/tests/sys/file/dup_test.c 281432 2015-04-11 10:14:59Z ngie $
+ */
+
+/*
+ * Test #1:  check if dup(2) works.
+ * Test #2:  check if dup2(2) works.
+ * Test #3:  check if dup2(2) returned a fd we asked for.
+ * Test #4:  check if dup2(2) cleared close-on-exec flag for duped fd.
+ * Test #5:  check if dup2(2) allows to dup fd to itself.
+ * Test #6:  check if dup2(2) returned a fd we asked for.
+ * Test #7:  check if dup2(2) did not clear close-on-exec flag for duped fd.
+ * Test #8:  check if fcntl(F_DUPFD) works.
+ * Test #9:  check if fcntl(F_DUPFD) cleared close-on-exec flag for duped fd.
+ * Test #10: check if dup2() to a fd > current maximum number of open files
+ *           limit work.
+ * Test #11: check if fcntl(F_DUP2FD) works.
+ * Test #12: check if fcntl(F_DUP2FD) returned a fd we asked for.
+ * Test #13: check if fcntl(F_DUP2FD) cleared close-on-exec flag for duped fd.
+ * Test #14: check if fcntl(F_DUP2FD) allows to dup fd to itself.
+ * Test #15: check if fcntl(F_DUP2FD) returned a fd we asked for.
+ * Test #16: check if fcntl(F_DUP2FD) did not clear close-on-exec flag for
+ *           duped fd.
+ * Test #17: check if fcntl(F_DUP2FD) to a fd > current maximum number of open
+ *           files limit work.
+ * Test #18: check if fcntl(F_DUPFD_CLOEXEC) works.
+ * Test #19: check if fcntl(F_DUPFD_CLOEXEC) set close-on-exec flag for duped
+ *           fd.
+ * Test #20: check if fcntl(F_DUP2FD_CLOEXEC) works.
+ * Test #21: check if fcntl(F_DUP2FD_CLOEXEC) returned a fd we asked for.
+ * Test #22: check if fcntl(F_DUP2FD_CLOEXEC) set close-on-exec flag for duped
+ *           fd.
+ * Test #23: check if fcntl(F_DUP2FD_CLOEXEC) to a fd > current maximum number
+ *           of open files limit work.
+ * Test #24: check if dup3(O_CLOEXEC) works.
+ * Test #25: check if dup3(O_CLOEXEC) returned a fd we asked for.
+ * Test #26: check if dup3(O_CLOEXEC) set close-on-exec flag for duped fd.
+ * Test #27: check if dup3(0) works.
+ * Test #28: check if dup3(0) returned a fd we asked for.
+ * Test #29: check if dup3(0) cleared close-on-exec flag for duped fd.
+ * Test #30: check if dup3(O_CLOEXEC) fails if oldfd == newfd.
+ * Test #31: check if dup3(0) fails if oldfd == newfd.
+ * Test #32: check if dup3(O_CLOEXEC) to a fd > current maximum number of
+ *           open files limit work.
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+#include <err.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+static int	getafile(void);
+
+static int
+getafile(void)
+{
+	int fd;
+
+	char temp[] = "/tmp/dup2XXXXXXXXX";
+	if ((fd = mkstemp(temp)) < 0)
+		err(1, "mkstemp");
+	remove(temp);
+	if (ftruncate(fd, 1024) != 0)
+		err(1, "ftruncate");
+	return (fd);
+}
+
+int
+main(int __unused argc, char __unused *argv[])
+{
+	struct rlimit rlp;
+	int orgfd, fd1, fd2, test = 0;
+
+	orgfd = getafile();
+
+	printf("1..32\n");
+
+	/* If dup(2) ever work? */
+	if ((fd1 = dup(orgfd)) < 0)
+		err(1, "dup");
+	printf("ok %d - dup(2) works\n", ++test);
+
+	/* Set close-on-exec */
+	if (fcntl(fd1, F_SETFD, 1) != 0)
+		err(1, "fcntl(F_SETFD)");
+
+	/* If dup2(2) ever work? */
+	if ((fd2 = dup2(fd1, fd1 + 1)) < 0)
+		err(1, "dup2");
+	printf("ok %d - dup2(2) works\n", ++test);
+
+	/* Do we get the right fd? */
+	++test;
+	if (fd2 != fd1 + 1)
+		printf("no ok %d - dup2(2) didn't give us the right fd\n",
+		    test);
+	else
+		printf("ok %d - dup2(2) returned a correct fd\n", test);
+
+	/* Was close-on-exec cleared? */
+	++test;
+	if (fcntl(fd2, F_GETFD) != 0)
+		printf("not ok %d - dup2(2) didn't clear close-on-exec\n",
+		    test);
+	else
+		printf("ok %d - dup2(2) cleared close-on-exec\n", test);
+
+	/*
+	 * Dup to itself.
+	 *
+	 * We're testing a small tweak in dup2 semantics.
+	 * Normally dup and dup2 will clear the close-on-exec
+	 * flag on the new fd (which appears to be an implementation
+	 * mistake from start and not some planned behavior).
+	 * In today's implementations of dup and dup2 we have to make
+	 * an effort to really clear that flag.  But all tested
+	 * implementations of dup2 have another tweak.  If we
+	 * dup2(old, new) when old == new, the syscall short-circuits
+	 * and returns early (because there is no need to do all the
+	 * work (and there is a risk for serious mistakes)).
+	 * So although the docs say that dup2 should "take 'old',
+	 * close 'new' perform a dup(2) of 'old' into 'new'"
+	 * the docs are not really followed because close-on-exec
+	 * is not cleared on 'new'.
+	 *
+	 * Since everyone has this bug, we pretend that this is
+	 * the way it is supposed to be and test here that it really
+	 * works that way.
+	 *
+	 * This is a fine example on where two separate implementation
+	 * fuckups take out each other and make the end-result the way
+	 * it was meant to be.
+	 */
+	if ((fd2 = dup2(fd1, fd1)) < 0)
+		err(1, "dup2");
+	printf("ok %d - dup2(2) to itself works\n", ++test);
+
+	/* Do we get the right fd? */
+	++test;
+	if (fd2 != fd1)
+		printf("not ok %d - dup2(2) didn't give us the right fd\n",
+		    test);
+	else
+		printf("ok %d - dup2(2) to itself returned a correct fd\n",
+		    test);
+
+	/* Was close-on-exec cleared? */
+	++test;
+	if (fcntl(fd2, F_GETFD) == 0)
+		printf("not ok %d - dup2(2) cleared close-on-exec\n", test);
+	else
+		printf("ok %d - dup2(2) didn't clear close-on-exec\n", test);
+
+	/* Does fcntl(F_DUPFD) work? */
+	if ((fd2 = fcntl(fd1, F_DUPFD, 10)) < 0)
+		err(1, "fcntl(F_DUPFD)");
+	if (fd2 < 10)
+		printf("not ok %d - fcntl(F_DUPFD) returned wrong fd %d\n",
+		    ++test, fd2);
+	else
+		printf("ok %d - fcntl(F_DUPFD) works\n", ++test);
+
+	/* Was close-on-exec cleared? */
+	++test;
+        if (fcntl(fd2, F_GETFD) != 0)
+		printf(
+		    "not ok %d - fcntl(F_DUPFD) didn't clear close-on-exec\n",
+		    test);
+	else
+		printf("ok %d - fcntl(F_DUPFD) cleared close-on-exec\n", test);
+
+	++test;
+	if (getrlimit(RLIMIT_NOFILE, &rlp) < 0)
+		err(1, "getrlimit");
+	if ((fd2 = dup2(fd1, rlp.rlim_cur + 1)) >= 0)
+		printf("not ok %d - dup2(2) bypassed NOFILE limit\n", test);
+	else
+		printf("ok %d - dup2(2) didn't bypass NOFILE limit\n", test);
+
+	/* If fcntl(F_DUP2FD) ever work? */
+	if ((fd2 = fcntl(fd1, F_DUP2FD, fd1 + 1)) < 0)
+		err(1, "fcntl(F_DUP2FD)");
+	printf("ok %d - fcntl(F_DUP2FD) works\n", ++test);
+
+	/* Do we get the right fd? */
+	++test;
+	if (fd2 != fd1 + 1)
+		printf(
+		    "no ok %d - fcntl(F_DUP2FD) didn't give us the right fd\n",
+		    test);
+	else
+		printf("ok %d - fcntl(F_DUP2FD) returned a correct fd\n",
+		    test);
+
+	/* Was close-on-exec cleared? */
+	++test;
+	if (fcntl(fd2, F_GETFD) != 0)
+		printf(
+		    "not ok %d - fcntl(F_DUP2FD) didn't clear close-on-exec\n",
+		    test);
+	else
+		printf("ok %d - fcntl(F_DUP2FD) cleared close-on-exec\n",
+		    test);
+
+	/* Dup to itself */
+	if ((fd2 = fcntl(fd1, F_DUP2FD, fd1)) < 0)
+		err(1, "fcntl(F_DUP2FD)");
+	printf("ok %d - fcntl(F_DUP2FD) to itself works\n", ++test);
+
+	/* Do we get the right fd? */
+	++test;
+	if (fd2 != fd1)
+		printf(
+		    "not ok %d - fcntl(F_DUP2FD) didn't give us the right fd\n",
+		    test);
+	else
+		printf(
+		    "ok %d - fcntl(F_DUP2FD) to itself returned a correct fd\n",
+		    test);
+
+	/* Was close-on-exec cleared? */
+	++test;
+	if (fcntl(fd2, F_GETFD) == 0)
+		printf("not ok %d - fcntl(F_DUP2FD) cleared close-on-exec\n",
+		    test);
+	else
+		printf("ok %d - fcntl(F_DUP2FD) didn't clear close-on-exec\n",
+		    test);
+
+	++test;
+	if (getrlimit(RLIMIT_NOFILE, &rlp) < 0)
+		err(1, "getrlimit");
+	if ((fd2 = fcntl(fd1, F_DUP2FD, rlp.rlim_cur + 1)) >= 0)
+		printf("not ok %d - fcntl(F_DUP2FD) bypassed NOFILE limit\n",
+		    test);
+	else
+		printf("ok %d - fcntl(F_DUP2FD) didn't bypass NOFILE limit\n",
+		    test);
+
+	/* Does fcntl(F_DUPFD_CLOEXEC) work? */
+	if ((fd2 = fcntl(fd1, F_DUPFD_CLOEXEC, 10)) < 0)
+		err(1, "fcntl(F_DUPFD_CLOEXEC)");
+	if (fd2 < 10)
+		printf("not ok %d - fcntl(F_DUPFD_CLOEXEC) returned wrong fd %d\n",
+		    ++test, fd2);
+	else
+		printf("ok %d - fcntl(F_DUPFD_CLOEXEC) works\n", ++test);
+
+	/* Was close-on-exec cleared? */
+	++test;
+        if (fcntl(fd2, F_GETFD) != 1)
+		printf(
+		    "not ok %d - fcntl(F_DUPFD_CLOEXEC) didn't set close-on-exec\n",
+		    test);
+	else
+		printf("ok %d - fcntl(F_DUPFD_CLOEXEC) set close-on-exec\n",
+		    test);
+
+	/* If fcntl(F_DUP2FD_CLOEXEC) ever work? */
+	if ((fd2 = fcntl(fd1, F_DUP2FD_CLOEXEC, fd1 + 1)) < 0)
+		err(1, "fcntl(F_DUP2FD_CLOEXEC)");
+	printf("ok %d - fcntl(F_DUP2FD_CLOEXEC) works\n", ++test);
+
+	/* Do we get the right fd? */
+	++test;
+	if (fd2 != fd1 + 1)
+		printf(
+		    "no ok %d - fcntl(F_DUP2FD_CLOEXEC) didn't give us the right fd\n",
+		    test);
+	else
+		printf("ok %d - fcntl(F_DUP2FD_CLOEXEC) returned a correct fd\n",
+		    test);
+
+	/* Was close-on-exec set? */
+	++test;
+	if (fcntl(fd2, F_GETFD) != FD_CLOEXEC)
+		printf(
+		    "not ok %d - fcntl(F_DUP2FD_CLOEXEC) didn't set close-on-exec\n",
+		    test);
+	else
+		printf("ok %d - fcntl(F_DUP2FD_CLOEXEC) set close-on-exec\n",
+		    test);
+
+	/*
+	 * It is unclear what F_DUP2FD_CLOEXEC should do when duplicating a
+	 * file descriptor onto itself.
+	 */
+
+	++test;
+	if (getrlimit(RLIMIT_NOFILE, &rlp) < 0)
+		err(1, "getrlimit");
+	if ((fd2 = fcntl(fd1, F_DUP2FD_CLOEXEC, rlp.rlim_cur + 1)) >= 0)
+		printf("not ok %d - fcntl(F_DUP2FD_CLOEXEC) bypassed NOFILE limit\n",
+		    test);
+	else
+		printf("ok %d - fcntl(F_DUP2FD_CLOEXEC) didn't bypass NOFILE limit\n",
+		    test);
+
+	/* Does dup3(O_CLOEXEC) ever work? */
+	if ((fd2 = dup3(fd1, fd1 + 1, O_CLOEXEC)) < 0)
+		err(1, "dup3(O_CLOEXEC)");
+	printf("ok %d - dup3(O_CLOEXEC) works\n", ++test);
+
+	/* Do we get the right fd? */
+	++test;
+	if (fd2 != fd1 + 1)
+		printf(
+		    "no ok %d - dup3(O_CLOEXEC) didn't give us the right fd\n",
+		    test);
+	else
+		printf("ok %d - dup3(O_CLOEXEC) returned a correct fd\n",
+		    test);
+
+	/* Was close-on-exec set? */
+	++test;
+	if (fcntl(fd2, F_GETFD) != FD_CLOEXEC)
+		printf(
+		    "not ok %d - dup3(O_CLOEXEC) didn't set close-on-exec\n",
+		    test);
+	else
+		printf("ok %d - dup3(O_CLOEXEC) set close-on-exec\n",
+		    test);
+
+	/* Does dup3(0) ever work? */
+	if ((fd2 = dup3(fd1, fd1 + 1, 0)) < 0)
+		err(1, "dup3(0)");
+	printf("ok %d - dup3(0) works\n", ++test);
+
+	/* Do we get the right fd? */
+	++test;
+	if (fd2 != fd1 + 1)
+		printf(
+		    "no ok %d - dup3(0) didn't give us the right fd\n",
+		    test);
+	else
+		printf("ok %d - dup3(0) returned a correct fd\n",
+		    test);
+
+	/* Was close-on-exec cleared? */
+	++test;
+	if (fcntl(fd2, F_GETFD) != 0)
+		printf(
+		    "not ok %d - dup3(0) didn't clear close-on-exec\n",
+		    test);
+	else
+		printf("ok %d - dup3(0) cleared close-on-exec\n",
+		    test);
+
+	/* dup3() does not allow duplicating to the same fd */
+	++test;
+	if (dup3(fd1, fd1, O_CLOEXEC) != -1)
+		printf(
+		    "not ok %d - dup3(fd1, fd1, O_CLOEXEC) succeeded\n", test);
+	else
+		printf("ok %d - dup3(fd1, fd1, O_CLOEXEC) failed\n", test);
+
+	++test;
+	if (dup3(fd1, fd1, 0) != -1)
+		printf(
+		    "not ok %d - dup3(fd1, fd1, 0) succeeded\n", test);
+	else
+		printf("ok %d - dup3(fd1, fd1, 0) failed\n", test);
+
+	++test;
+	if (getrlimit(RLIMIT_NOFILE, &rlp) < 0)
+		err(1, "getrlimit");
+	if ((fd2 = dup3(fd1, rlp.rlim_cur + 1, O_CLOEXEC)) >= 0)
+		printf("not ok %d - dup3(O_CLOEXEC) bypassed NOFILE limit\n",
+		    test);
+	else
+		printf("ok %d - dup3(O_CLOEXEC) didn't bypass NOFILE limit\n",
+		    test);
+
+	return (0);
+}


Property changes on: trunk/tests/sys/file/dup_test.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/tests/sys/file/fcntlflags_test.c
===================================================================
--- trunk/tests/sys/file/fcntlflags_test.c	                        (rev 0)
+++ trunk/tests/sys/file/fcntlflags_test.c	2018-07-28 21:14:08 UTC (rev 11974)
@@ -0,0 +1,111 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2013 Jilles Tjoelker
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: stable/10/tests/sys/file/fcntlflags_test.c 281432 2015-04-11 10:14:59Z ngie $
+ */
+
+#include <sys/cdefs.h>
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <unistd.h>
+
+/*
+ * O_ACCMODE is currently defined incorrectly. This is what it should be.
+ * Various code depends on the incorrect value.
+ */
+#define CORRECT_O_ACCMODE (O_ACCMODE | O_EXEC)
+
+static int testnum;
+
+static void
+subtests(const char *path, int omode, const char *omodetext)
+{
+	int fd, flags1, flags2, flags3;
+
+	fd = open(path, omode);
+	if (fd == -1)
+		printf("not ok %d - open(\"%s\", %s) failed\n",
+		    testnum++, path, omodetext);
+	else
+		printf("ok %d - open(\"%s\", %s) succeeded\n",
+		    testnum++, path, omodetext);
+	flags1 = fcntl(fd, F_GETFL);
+	if (flags1 == -1)
+		printf("not ok %d - fcntl(F_GETFL) failed\n", testnum++);
+	else if ((flags1 & CORRECT_O_ACCMODE) == omode)
+		printf("ok %d - fcntl(F_GETFL) gave correct result\n",
+		    testnum++);
+	else
+		printf("not ok %d - fcntl(F_GETFL) gave incorrect result "
+		    "(%#x & %#x != %#x)\n",
+		    testnum++, flags1, CORRECT_O_ACCMODE, omode);
+	if (fcntl(fd, F_SETFL, flags1) == -1)
+		printf("not ok %d - fcntl(F_SETFL) same flags failed\n",
+		    testnum++);
+	else
+		printf("ok %d - fcntl(F_SETFL) same flags succeeded\n",
+		    testnum++);
+	flags2 = fcntl(fd, F_GETFL);
+	if (flags2 == -1)
+		printf("not ok %d - fcntl(F_GETFL) failed\n", testnum++);
+	else if (flags2 == flags1)
+		printf("ok %d - fcntl(F_GETFL) gave same result\n",
+		    testnum++);
+	else
+		printf("not ok %d - fcntl(F_SETFL) caused fcntl(F_GETFL) to "
+		    "change from %#x to %#x\n",
+		    testnum++, flags1, flags2);
+	if (fcntl(fd, F_SETFL, flags2 | O_NONBLOCK) == -1)
+		printf("not ok %d - fcntl(F_SETFL) O_NONBLOCK failed\n",
+		    testnum++);
+	else
+		printf("ok %d - fcntl(F_SETFL) O_NONBLOCK succeeded\n",
+		    testnum++);
+	flags3 = fcntl(fd, F_GETFL);
+	if (flags3 == -1)
+		printf("not ok %d - fcntl(F_GETFL) failed\n", testnum++);
+	else if (flags3 == (flags2 | O_NONBLOCK))
+		printf("ok %d - fcntl(F_GETFL) gave expected result\n",
+		    testnum++);
+	else
+		printf("not ok %d - fcntl(F_SETFL) gave unexpected result "
+		    "(%#x != %#x)\n",
+		    testnum++, flags3, flags2 | O_NONBLOCK);
+	(void)close(fd);
+}
+
+int
+main(int argc __unused, char **argv __unused)
+{
+	printf("1..24\n");
+	testnum = 1;
+	subtests("/dev/null", O_RDONLY, "O_RDONLY");
+	subtests("/dev/null", O_WRONLY, "O_WRONLY");
+	subtests("/dev/null", O_RDWR, "O_RDWR");
+	subtests("/bin/sh", O_EXEC, "O_EXEC");
+	return (0);
+}


Property changes on: trunk/tests/sys/file/fcntlflags_test.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/tests/sys/file/flock_helper.c
===================================================================
--- trunk/tests/sys/file/flock_helper.c	                        (rev 0)
+++ trunk/tests/sys/file/flock_helper.c	2018-07-28 21:14:08 UTC (rev 11974)
@@ -0,0 +1,1599 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2008 Isilon Inc http://www.isilon.com/
+ * Authors: Doug Rabson <dfr at rabson.org>
+ * Developed with Red Inc: Alfred Perlstein <alfred at freebsd.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: stable/10/tests/sys/file/flock_helper.c 298490 2016-04-22 21:30:42Z ngie $
+ */
+
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#ifdef __FreeBSD__
+#include <sys/mount.h>
+#endif
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifdef __FreeBSD__
+#if __FreeBSD_version >= 800028
+#define HAVE_SYSID
+#endif
+#include <sys/cdefs.h>
+#else
+#ifndef nitems
+#define	nitems(x)	(sizeof((x)) / sizeof((x)[0]))
+#endif
+
+#ifndef __unused
+#ifdef __GNUC__
+#define	__unused	__attribute__((__unused__))
+#else
+#define __unused
+#endif
+#endif
+#endif
+
+static int verbose = 0;
+
+static int
+make_file(const char *pathname, off_t sz)
+{
+	struct stat st;
+	const char *template = "/flocktempXXXXXX";
+	size_t len;
+	char *filename;
+	int fd;
+
+	if (stat(pathname, &st) == 0) {
+		if (S_ISREG(st.st_mode)) {
+			fd = open(pathname, O_RDWR);
+			if (fd < 0)
+				err(1, "open(%s)", pathname);
+			if (ftruncate(fd, sz) < 0)
+				err(1, "ftruncate");
+			return (fd);
+		}
+	}
+
+	len = strlen(pathname) + strlen(template) + 1;
+	filename = malloc(len);
+	strcpy(filename, pathname);
+	strcat(filename, template);
+	fd = mkstemp(filename);
+	if (fd < 0)
+		err(1, "mkstemp");
+	if (ftruncate(fd, sz) < 0)
+		err(1, "ftruncate");
+	if (unlink(filename) < 0)
+		err(1, "unlink");
+	free(filename);
+
+	return (fd);
+}
+
+static void
+ignore_alarm(int __unused sig)
+{
+}
+
+static int
+safe_waitpid(pid_t pid)
+{
+	int save_errno;
+	int status;
+
+	save_errno = errno;
+	errno = 0;
+	while (waitpid(pid, &status, 0) != pid) {
+		if (errno == EINTR)
+			continue;
+		err(1, "waitpid");
+	}
+	errno = save_errno;
+
+	return (status);
+}
+
+#define FAIL(test)					\
+	do {						\
+		if (test) {				\
+			printf("FAIL (%s)\n", #test);	\
+			return -1;			\
+		}					\
+	} while (0)
+
+#define SUCCEED \
+	do { printf("SUCCEED\n"); return 0; } while (0)
+
+/*
+ * Test 1 - F_GETLK on unlocked region
+ *
+ * If no lock is found that would prevent this lock from being
+ * created, the structure is left unchanged by this function call
+ * except for the lock type which is set to F_UNLCK.
+ */
+static int
+test1(int fd, __unused int argc, const __unused char **argv)
+{
+	struct flock fl1, fl2;
+
+	memset(&fl1, 1, sizeof(fl1));
+	fl1.l_type = F_WRLCK;
+	fl1.l_whence = SEEK_SET;
+	fl2 = fl1;
+
+	if (fcntl(fd, F_GETLK, &fl1) < 0)
+		err(1, "F_GETLK");
+
+	printf("1 - F_GETLK on unlocked region: ");
+	FAIL(fl1.l_start != fl2.l_start);
+	FAIL(fl1.l_len != fl2.l_len);
+	FAIL(fl1.l_pid != fl2.l_pid);
+	FAIL(fl1.l_type != F_UNLCK);
+	FAIL(fl1.l_whence != fl2.l_whence);
+#ifdef HAVE_SYSID
+	FAIL(fl1.l_sysid != fl2.l_sysid);
+#endif
+
+	SUCCEED;
+}
+
+/*
+ * Test 2 - F_SETLK on locked region
+ *
+ * If a shared or exclusive lock cannot be set, fcntl returns
+ * immediately with EACCES or EAGAIN.
+ */
+static int
+test2(int fd, __unused int argc, const __unused char **argv)
+{
+	/*
+	 * We create a child process to hold the lock which we will
+	 * test. We use a pipe to communicate with the child.
+	 */
+	int pid;
+	int pfd[2];
+	struct flock fl;
+	char ch;
+	int res;
+
+	if (pipe(pfd) < 0)
+		err(1, "pipe");
+
+	fl.l_start = 0;
+	fl.l_len = 0;
+	fl.l_type = F_WRLCK;
+	fl.l_whence = SEEK_SET;
+
+	pid = fork();
+	if (pid < 0)
+		err(1, "fork");
+
+	if (pid == 0) {
+		/*
+		 * We are the child. We set a write lock and then
+		 * write one byte back to the parent to tell it. The
+		 * parent will kill us when its done.
+		 */
+		if (fcntl(fd, F_SETLK, &fl) < 0)
+			err(1, "F_SETLK (child)");
+		if (write(pfd[1], "a", 1) < 0)
+			err(1, "writing to pipe (child)");
+		pause();
+		exit(0);
+	}
+
+	/*
+	 * Wait until the child has set its lock and then perform the
+	 * test.
+	 */
+	if (read(pfd[0], &ch, 1) != 1)
+		err(1, "reading from pipe (child)");
+
+	/*
+	 * fcntl should return -1 with errno set to either EACCES or
+	 * EAGAIN.
+	 */
+	printf("2 - F_SETLK on locked region: ");
+	res = fcntl(fd, F_SETLK, &fl);
+	kill(pid, SIGTERM);
+	safe_waitpid(pid);
+	close(pfd[0]);
+	close(pfd[1]);
+	FAIL(res == 0);
+	FAIL(errno != EACCES && errno != EAGAIN);
+
+	SUCCEED;
+}
+
+/*
+ * Test 3 - F_SETLKW on locked region
+ *
+ * If a shared or exclusive lock is blocked by other locks, the
+ * process waits until the request can be satisfied.
+ *
+ * XXX this test hangs on FreeBSD NFS filesystems due to limitations
+ * in FreeBSD's client (and server) lockd implementation.
+ */
+static int
+test3(int fd, __unused int argc, const __unused char **argv)
+{
+	/*
+	 * We create a child process to hold the lock which we will
+	 * test. We use a pipe to communicate with the child.
+	 */
+	int pid;
+	int pfd[2];
+	struct flock fl;
+	char ch;
+	int res;
+
+	if (pipe(pfd) < 0)
+		err(1, "pipe");
+
+	fl.l_start = 0;
+	fl.l_len = 0;
+	fl.l_type = F_WRLCK;
+	fl.l_whence = SEEK_SET;
+
+	pid = fork();
+	if (pid < 0)
+		err(1, "fork");
+
+	if (pid == 0) {
+		/*
+		 * We are the child. We set a write lock and then
+		 * write one byte back to the parent to tell it. The
+		 * parent will kill us when its done.
+		 */
+		if (fcntl(fd, F_SETLK, &fl) < 0)
+			err(1, "F_SETLK (child)");
+		if (write(pfd[1], "a", 1) < 0)
+			err(1, "writing to pipe (child)");
+		pause();
+		exit(0);
+	}
+
+	/*
+	 * Wait until the child has set its lock and then perform the
+	 * test.
+	 */
+	if (read(pfd[0], &ch, 1) != 1)
+		err(1, "reading from pipe (child)");
+
+	/*
+	 * fcntl should wait until the alarm and then return -1 with
+	 * errno set to EINTR.
+	 */
+	printf("3 - F_SETLKW on locked region: ");
+
+	alarm(1);
+
+	res = fcntl(fd, F_SETLKW, &fl);
+	kill(pid, SIGTERM);
+	safe_waitpid(pid);
+	close(pfd[0]);
+	close(pfd[1]);
+	FAIL(res == 0);
+	FAIL(errno != EINTR);
+
+	SUCCEED;
+}
+
+/*
+ * Test 4 - F_GETLK on locked region
+ *
+ * Get the first lock that blocks the lock.
+ */
+static int
+test4(int fd, __unused int argc, const __unused char **argv)
+{
+	/*
+	 * We create a child process to hold the lock which we will
+	 * test. We use a pipe to communicate with the child.
+	 */
+	int pid;
+	int pfd[2];
+	struct flock fl;
+	char ch;
+
+	if (pipe(pfd) < 0)
+		err(1, "pipe");
+
+	fl.l_start = 0;
+	fl.l_len = 99;
+	fl.l_type = F_WRLCK;
+	fl.l_whence = SEEK_SET;
+
+	pid = fork();
+	if (pid < 0)
+		err(1, "fork");
+
+	if (pid == 0) {
+		/*
+		 * We are the child. We set a write lock and then
+		 * write one byte back to the parent to tell it. The
+		 * parent will kill us when its done.
+		 */
+		if (fcntl(fd, F_SETLK, &fl) < 0)
+			err(1, "F_SETLK (child)");
+		if (write(pfd[1], "a", 1) < 0)
+			err(1, "writing to pipe (child)");
+		pause();
+		exit(0);
+	}
+
+	/*
+	 * Wait until the child has set its lock and then perform the
+	 * test.
+	 */
+	if (read(pfd[0], &ch, 1) != 1)
+		err(1, "reading from pipe (child)");
+
+	/*
+	 * fcntl should return a lock structure reflecting the lock we
+	 * made in the child process.
+	 */
+	if (fcntl(fd, F_GETLK, &fl) < 0)
+		err(1, "F_GETLK");
+
+	printf("4 - F_GETLK on locked region: ");
+	FAIL(fl.l_start != 0);
+	FAIL(fl.l_len != 99);
+	FAIL(fl.l_type != F_WRLCK);
+	FAIL(fl.l_pid != pid);
+#ifdef HAVE_SYSID
+	FAIL(fl.l_sysid != 0);
+#endif
+
+	kill(pid, SIGTERM);
+	safe_waitpid(pid);
+	close(pfd[0]);
+	close(pfd[1]);
+
+	SUCCEED;
+}
+
+/*
+ * Test 5 - F_SETLKW simple deadlock
+ *
+ * If a blocking shared lock request would cause a deadlock (i.e. the
+ * lock request is blocked by a process which is itself blocked on a
+ * lock currently owned by the process making the new request),
+ * EDEADLK is returned.
+ */
+static int
+test5(int fd, __unused int argc, const __unused char **argv)
+{
+	/*
+	 * We create a child process to hold the lock which we will
+	 * test. Because our test relies on the child process being
+	 * blocked on the parent's lock, we can't easily use a pipe to
+	 * synchronize so we just sleep in the parent to given the
+	 * child a chance to setup.
+	 *
+	 * To create the deadlock condition, we arrange for the parent
+	 * to lock the first byte of the file and the child to lock
+	 * the second byte.  After locking the second byte, the child
+	 * will attempt to lock the first byte of the file, and
+	 * block. The parent will then attempt to lock the second byte
+	 * (owned by the child) which should cause deadlock.
+	 */
+	int pid;
+	struct flock fl;
+	int res;
+
+	/*
+	 * Lock the first byte in the parent.
+	 */
+	fl.l_start = 0;
+	fl.l_len = 1;
+	fl.l_type = F_WRLCK;
+	fl.l_whence = SEEK_SET;
+	if (fcntl(fd, F_SETLK, &fl) < 0)
+		err(1, "F_SETLK 1 (parent)");
+
+	pid = fork();
+	if (pid < 0)
+		err(1, "fork");
+
+	if (pid == 0) {
+		/*
+		 * Lock the second byte in the child and then block on
+		 * the parent's lock.
+		 */
+		fl.l_start = 1;
+		if (fcntl(fd, F_SETLK, &fl) < 0)
+			err(1, "F_SETLK (child)");
+		fl.l_start = 0;
+		if (fcntl(fd, F_SETLKW, &fl) < 0)
+			err(1, "F_SETLKW (child)");
+		exit(0);
+	}
+
+	/*
+	 * Wait until the child has set its lock and then perform the
+	 * test.
+	 */
+	sleep(1);
+
+	/*
+	 * fcntl should immediately return -1 with errno set to
+	 * EDEADLK. If the alarm fires, we failed to detect the
+	 * deadlock.
+	 */
+	alarm(1);
+	printf("5 - F_SETLKW simple deadlock: ");
+
+	fl.l_start = 1;
+	res = fcntl(fd, F_SETLKW, &fl);
+	kill(pid, SIGTERM);
+	safe_waitpid(pid);
+	
+	FAIL(res == 0);
+	FAIL(errno != EDEADLK);
+
+	fl.l_start = 0;
+	fl.l_len = 0;
+	fl.l_type = F_UNLCK;
+	if (fcntl(fd, F_SETLK, &fl) < 0)
+		err(1, "F_UNLCK");
+
+	/*
+	 * Cancel the alarm to avoid confusing later tests.
+	 */
+	alarm(0);
+
+	SUCCEED;
+}
+
+/*
+ * Test 6 - F_SETLKW complex deadlock.
+ *
+ * This test involves three process, P, C1 and C2. We set things up so
+ * that P locks byte zero, C1 locks byte 1 and C2 locks byte 2. We
+ * also block C2 by attempting to lock byte zero. Lastly, P attempts
+ * to lock a range including byte 1 and 2. This represents a deadlock
+ * (due to C2's blocking attempt to lock byte zero).
+ */
+static int
+test6(int fd, __unused int argc, const __unused char **argv)
+{
+	/*
+	 * Because our test relies on the child process being blocked
+	 * on the parent's lock, we can't easily use a pipe to
+	 * synchronize so we just sleep in the parent to given the
+	 * children a chance to setup.
+	 */
+	int pid1, pid2;
+	struct flock fl;
+	int res;
+
+	/*
+	 * Lock the first byte in the parent.
+	 */
+	fl.l_start = 0;
+	fl.l_len = 1;
+	fl.l_type = F_WRLCK;
+	fl.l_whence = SEEK_SET;
+	if (fcntl(fd, F_SETLK, &fl) < 0)
+		err(1, "F_SETLK 1 (parent)");
+
+	pid1 = fork();
+	if (pid1 < 0)
+		err(1, "fork");
+
+	if (pid1 == 0) {
+		/*
+		 * C1
+		 * Lock the second byte in the child and then sleep
+		 */
+		fl.l_start = 1;
+		if (fcntl(fd, F_SETLK, &fl) < 0)
+			err(1, "F_SETLK (child1)");
+		pause();
+		exit(0);
+	}
+
+	pid2 = fork();
+	if (pid2 < 0)
+		err(1, "fork");
+
+	if (pid2 == 0) {
+		/*
+		 * C2
+		 * Lock the third byte in the child and then block on
+		 * the parent's lock.
+		 */
+		fl.l_start = 2;
+		if (fcntl(fd, F_SETLK, &fl) < 0)
+			err(1, "F_SETLK (child2)");
+		fl.l_start = 0;
+		if (fcntl(fd, F_SETLKW, &fl) < 0)
+			err(1, "F_SETLKW (child2)");
+		exit(0);
+	}
+
+	/*
+	 * Wait until the children have set their locks and then
+	 * perform the test.
+	 */
+	sleep(1);
+
+	/*
+	 * fcntl should immediately return -1 with errno set to
+	 * EDEADLK. If the alarm fires, we failed to detect the
+	 * deadlock.
+	 */
+	alarm(1);
+	printf("6 - F_SETLKW complex deadlock: ");
+
+	fl.l_start = 1;
+	fl.l_len = 2;
+	res = fcntl(fd, F_SETLKW, &fl);
+	kill(pid1, SIGTERM);
+	safe_waitpid(pid1);
+	kill(pid2, SIGTERM);
+	safe_waitpid(pid2);
+
+	fl.l_start = 0;
+	fl.l_len = 0;
+	fl.l_type = F_UNLCK;
+	if (fcntl(fd, F_SETLK, &fl) < 0)
+		err(1, "F_UNLCK");
+
+	FAIL(res == 0);
+	FAIL(errno != EDEADLK);
+
+	/*
+	 * Cancel the alarm to avoid confusing later tests.
+	 */
+	alarm(0);
+
+	SUCCEED;
+}
+
+/*
+ * Test 7 - F_SETLK shared lock on exclusive locked region
+ *
+ * If a shared or exclusive lock cannot be set, fcntl returns
+ * immediately with EACCES or EAGAIN.
+ */
+static int
+test7(int fd, __unused int argc, const __unused char **argv)
+{
+	/*
+	 * We create a child process to hold the lock which we will
+	 * test. We use a pipe to communicate with the child.
+	 */
+	int pid;
+	int pfd[2];
+	struct flock fl;
+	char ch;
+	int res;
+
+	if (pipe(pfd) < 0)
+		err(1, "pipe");
+
+	fl.l_start = 0;
+	fl.l_len = 0;
+	fl.l_type = F_WRLCK;
+	fl.l_whence = SEEK_SET;
+
+	pid = fork();
+	if (pid < 0)
+		err(1, "fork");
+
+	if (pid == 0) {
+		/*
+		 * We are the child. We set a write lock and then
+		 * write one byte back to the parent to tell it. The
+		 * parent will kill us when its done.
+		 */
+		if (fcntl(fd, F_SETLK, &fl) < 0)
+			err(1, "F_SETLK (child)");
+		if (write(pfd[1], "a", 1) < 0)
+			err(1, "writing to pipe (child)");
+		pause();
+		exit(0);
+	}
+
+	/*
+	 * Wait until the child has set its lock and then perform the
+	 * test.
+	 */
+	if (read(pfd[0], &ch, 1) != 1)
+		err(1, "reading from pipe (child)");
+
+	/*
+	 * fcntl should wait until the alarm and then return -1 with
+	 * errno set to EINTR.
+	 */
+	printf("7 - F_SETLK shared lock on exclusive locked region: ");
+
+	fl.l_type = F_RDLCK;
+	res = fcntl(fd, F_SETLK, &fl);
+	kill(pid, SIGTERM);
+	safe_waitpid(pid);
+	close(pfd[0]);
+	close(pfd[1]);
+
+	FAIL(res == 0);
+	FAIL(errno != EACCES && errno != EAGAIN);
+
+	SUCCEED;
+}
+
+/*
+ * Test 8 - F_SETLK shared lock on share locked region
+ *
+ * When a shared lock is set on a segment of a file, other processes
+ * shall be able to set shared locks on that segment or a portion of
+ * it.
+ */
+static int
+test8(int fd, __unused int argc, const __unused char **argv)
+{
+	/*
+	 * We create a child process to hold the lock which we will
+	 * test. We use a pipe to communicate with the child.
+	 */
+	int pid;
+	int pfd[2];
+	struct flock fl;
+	char ch;
+	int res;
+
+	if (pipe(pfd) < 0)
+		err(1, "pipe");
+
+	fl.l_start = 0;
+	fl.l_len = 0;
+	fl.l_type = F_RDLCK;
+	fl.l_whence = SEEK_SET;
+
+	pid = fork();
+	if (pid < 0)
+		err(1, "fork");
+
+	if (pid == 0) {
+		/*
+		 * We are the child. We set a write lock and then
+		 * write one byte back to the parent to tell it. The
+		 * parent will kill us when its done.
+		 */
+		if (fcntl(fd, F_SETLK, &fl) < 0)
+			err(1, "F_SETLK (child)");
+		if (write(pfd[1], "a", 1) < 0)
+			err(1, "writing to pipe (child)");
+		pause();
+		exit(0);
+	}
+
+	/*
+	 * Wait until the child has set its lock and then perform the
+	 * test.
+	 */
+	if (read(pfd[0], &ch, 1) != 1)
+		err(1, "reading from pipe (child)");
+
+	/*
+	 * fcntl should wait until the alarm and then return -1 with
+	 * errno set to EINTR.
+	 */
+	printf("8 - F_SETLK shared lock on share locked region: ");
+
+	fl.l_type = F_RDLCK;
+	res = fcntl(fd, F_SETLK, &fl);
+
+	kill(pid, SIGTERM);
+	safe_waitpid(pid);
+	close(pfd[0]);
+	close(pfd[1]);
+
+	fl.l_start = 0;
+	fl.l_len = 0;
+	fl.l_type = F_UNLCK;
+	if (fcntl(fd, F_SETLK, &fl) < 0)
+		err(1, "F_UNLCK");
+
+	FAIL(res != 0);
+
+	SUCCEED;
+}
+
+/*
+ * Test 9 - F_SETLK exclusive lock on share locked region
+ *
+ * If a shared or exclusive lock cannot be set, fcntl returns
+ * immediately with EACCES or EAGAIN.
+ */
+static int
+test9(int fd, __unused int argc, const __unused char **argv)
+{
+	/*
+	 * We create a child process to hold the lock which we will
+	 * test. We use a pipe to communicate with the child.
+	 */
+	int pid;
+	int pfd[2];
+	struct flock fl;
+	char ch;
+	int res;
+
+	if (pipe(pfd) < 0)
+		err(1, "pipe");
+
+	fl.l_start = 0;
+	fl.l_len = 0;
+	fl.l_type = F_RDLCK;
+	fl.l_whence = SEEK_SET;
+
+	pid = fork();
+	if (pid < 0)
+		err(1, "fork");
+
+	if (pid == 0) {
+		/*
+		 * We are the child. We set a write lock and then
+		 * write one byte back to the parent to tell it. The
+		 * parent will kill us when its done.
+		 */
+		if (fcntl(fd, F_SETLK, &fl) < 0)
+			err(1, "F_SETLK (child)");
+		if (write(pfd[1], "a", 1) < 0)
+			err(1, "writing to pipe (child)");
+		pause();
+		exit(0);
+	}
+
+	/*
+	 * Wait until the child has set its lock and then perform the
+	 * test.
+	 */
+	if (read(pfd[0], &ch, 1) != 1)
+		err(1, "reading from pipe (child)");
+
+	/*
+	 * fcntl should wait until the alarm and then return -1 with
+	 * errno set to EINTR.
+	 */
+	printf("9 - F_SETLK exclusive lock on share locked region: ");
+
+	fl.l_type = F_WRLCK;
+	res = fcntl(fd, F_SETLK, &fl);
+	kill(pid, SIGTERM);
+	safe_waitpid(pid);
+	close(pfd[0]);
+	close(pfd[1]);
+
+	FAIL(res == 0);
+	FAIL(errno != EACCES && errno != EAGAIN);
+
+	SUCCEED;
+}
+
+/*
+ * Test 10 - trying to set bogus pid or sysid values
+ *
+ * The l_pid and l_sysid fields are only used with F_GETLK to return
+ * the process ID of the process holding a blocking lock and the
+ * system ID of the system that owns that process
+ */
+static int
+test10(int fd, __unused int argc, const __unused char **argv)
+{
+	/*
+	 * We create a child process to hold the lock which we will
+	 * test. We use a pipe to communicate with the child.
+	 */
+	int pid;
+	int pfd[2];
+	struct flock fl;
+	char ch;
+
+	if (pipe(pfd) < 0)
+		err(1, "pipe");
+
+	fl.l_start = 0;
+	fl.l_len = 0;
+	fl.l_type = F_WRLCK;
+	fl.l_whence = SEEK_SET;
+	fl.l_pid = 9999;
+#ifdef HAVE_SYSID
+	fl.l_sysid = 9999;
+#endif
+
+	pid = fork();
+	if (pid < 0)
+		err(1, "fork");
+
+	if (pid == 0) {
+		/*
+		 * We are the child. We set a write lock and then
+		 * write one byte back to the parent to tell it. The
+		 * parent will kill us when its done.
+		 */
+		if (fcntl(fd, F_SETLK, &fl) < 0)
+			err(1, "F_SETLK (child)");
+		if (write(pfd[1], "a", 1) < 0)
+			err(1, "writing to pipe (child)");
+		pause();
+		exit(0);
+	}
+
+	/*
+	 * Wait until the child has set its lock and then perform the
+	 * test.
+	 */
+	if (read(pfd[0], &ch, 1) != 1)
+		err(1, "reading from pipe (child)");
+
+	printf("10 - trying to set bogus pid or sysid values: ");
+
+	if (fcntl(fd, F_GETLK, &fl) < 0)
+		err(1, "F_GETLK");
+
+	kill(pid, SIGTERM);
+	safe_waitpid(pid);
+	close(pfd[0]);
+	close(pfd[1]);
+
+	FAIL(fl.l_pid != pid);
+#ifdef HAVE_SYSID
+	FAIL(fl.l_sysid != 0);
+#endif
+
+	SUCCEED;
+}
+
+/*
+ * Test 11 - remote locks
+ *
+ * XXX temporary interface which will be removed when the kernel lockd
+ * is added.
+ */
+static int
+test11(int fd, __unused int argc, const __unused char **argv)
+{
+#ifdef F_SETLK_REMOTE
+	struct flock fl;
+	int res;
+
+	if (geteuid() != 0)
+		return 0;
+
+	fl.l_start = 0;
+	fl.l_len = 0;
+	fl.l_type = F_WRLCK;
+	fl.l_whence = SEEK_SET;
+	fl.l_pid = 9999;
+	fl.l_sysid = 1001;
+
+	printf("11 - remote locks: ");
+
+	res = fcntl(fd, F_SETLK_REMOTE, &fl);
+	FAIL(res != 0);
+
+	fl.l_sysid = 1002;
+	res = fcntl(fd, F_SETLK_REMOTE, &fl);
+	FAIL(res == 0);
+	FAIL(errno != EACCES && errno != EAGAIN);
+
+	res = fcntl(fd, F_GETLK, &fl);
+	FAIL(res != 0);
+	FAIL(fl.l_pid != 9999);
+	FAIL(fl.l_sysid != 1001);
+
+	fl.l_type = F_UNLCK;
+	fl.l_sysid = 1001;
+	fl.l_start = 0;
+	fl.l_len = 0;
+	res = fcntl(fd, F_SETLK_REMOTE, &fl);
+	FAIL(res != 0);
+
+	fl.l_pid = 1234;
+	fl.l_sysid = 1001;
+	fl.l_start = 0;
+	fl.l_len = 1;
+	fl.l_whence = SEEK_SET;
+	fl.l_type = F_RDLCK;
+	res = fcntl(fd, F_SETLK_REMOTE, &fl);
+	FAIL(res != 0);
+
+	fl.l_sysid = 1002;
+	res = fcntl(fd, F_SETLK_REMOTE, &fl);
+	FAIL(res != 0);
+
+	fl.l_type = F_UNLCKSYS;
+	fl.l_sysid = 1001;
+	res = fcntl(fd, F_SETLK_REMOTE, &fl);
+	FAIL(res != 0);
+
+	fl.l_type = F_WRLCK;
+	res = fcntl(fd, F_GETLK, &fl);
+	FAIL(res != 0);
+	FAIL(fl.l_pid != 1234);
+	FAIL(fl.l_sysid != 1002);
+
+	fl.l_type = F_UNLCKSYS;
+	fl.l_sysid = 1002;
+	res = fcntl(fd, F_SETLK_REMOTE, &fl);
+	FAIL(res != 0);
+
+	SUCCEED;
+#else
+	return 0;
+#endif
+}
+
+/*
+ * Test 12 - F_SETLKW on locked region which is then unlocked
+ *
+ * If a shared or exclusive lock is blocked by other locks, the
+ * process waits until the request can be satisfied.
+ */
+static int
+test12(int fd, __unused int argc, const __unused char **argv)
+{
+	/*
+	 * We create a child process to hold the lock which we will
+	 * test. We use a pipe to communicate with the child.
+	 */
+	int pid;
+	int pfd[2];
+	struct flock fl;
+	char ch;
+	int res;
+
+	if (pipe(pfd) < 0)
+		err(1, "pipe");
+
+	fl.l_start = 0;
+	fl.l_len = 0;
+	fl.l_type = F_WRLCK;
+	fl.l_whence = SEEK_SET;
+
+	pid = fork();
+	if (pid < 0)
+		err(1, "fork");
+
+	if (pid == 0) {
+		/*
+		 * We are the child. We set a write lock and then
+		 * write one byte back to the parent to tell it. The
+		 * parent will kill us when its done.
+		 */
+		if (fcntl(fd, F_SETLK, &fl) < 0)
+			err(1, "F_SETLK (child)");
+		if (write(pfd[1], "a", 1) < 0)
+			err(1, "writing to pipe (child)");
+
+		sleep(1);
+		exit(0);
+	}
+
+	/*
+	 * Wait until the child has set its lock and then perform the
+	 * test.
+	 */
+	if (read(pfd[0], &ch, 1) != 1)
+		err(1, "reading from pipe (child)");
+
+	/*
+	 * fcntl should wait until the alarm and then return -1 with
+	 * errno set to EINTR.
+	 */
+	printf("12 - F_SETLKW on locked region which is then unlocked: ");
+
+	//alarm(1);
+
+	res = fcntl(fd, F_SETLKW, &fl);
+	kill(pid, SIGTERM);
+	safe_waitpid(pid);
+	close(pfd[0]);
+	close(pfd[1]);
+	FAIL(res != 0);
+
+	fl.l_start = 0;
+	fl.l_len = 0;
+	fl.l_type = F_UNLCK;
+	if (fcntl(fd, F_SETLK, &fl) < 0)
+		err(1, "F_UNLCK");
+
+	SUCCEED;
+}
+
+/*
+ * Test 13 - F_SETLKW on locked region, race with owner
+ *
+ * If a shared or exclusive lock is blocked by other locks, the
+ * process waits until the request can be satisfied.
+ */
+static int
+test13(int fd, __unused int argc, const __unused char **argv)
+{
+	/*
+	 * We create a child process to hold the lock which we will
+	 * test. We use a pipe to communicate with the child.
+	 */
+	int i;
+	int pid;
+	int pfd[2];
+	struct flock fl;
+	char ch;
+	int res;
+	struct itimerval itv;
+
+	printf("13 - F_SETLKW on locked region, race with owner: ");
+	fflush(stdout);
+
+	for (i = 0; i < 100; i++) {
+		if (pipe(pfd) < 0)
+			err(1, "pipe");
+
+		fl.l_start = 0;
+		fl.l_len = 0;
+		fl.l_type = F_WRLCK;
+		fl.l_whence = SEEK_SET;
+
+		pid = fork();
+		if (pid < 0)
+			err(1, "fork");
+
+		if (pid == 0) {
+			/*
+			 * We are the child. We set a write lock and then
+			 * write one byte back to the parent to tell it. The
+			 * parent will kill us when its done.
+			 */
+			if (fcntl(fd, F_SETLK, &fl) < 0)
+				err(1, "F_SETLK (child)");
+			if (write(pfd[1], "a", 1) < 0)
+				err(1, "writing to pipe (child)");
+
+			usleep(1);
+			exit(0);
+		}
+
+		/*
+		 * Wait until the child has set its lock and then perform the
+		 * test.
+		 */
+		while (read(pfd[0], &ch, 1) != 1) {
+			if (errno == EINTR)
+				continue;
+			err(1, "reading from pipe (child)");
+		}
+
+		/*
+		 * fcntl should wait until the alarm and then return -1 with
+		 * errno set to EINTR.
+		 */
+		itv.it_interval.tv_sec = 0;
+		itv.it_interval.tv_usec = 0;
+		itv.it_value.tv_sec = 0;
+		itv.it_value.tv_usec = 2;
+		setitimer(ITIMER_REAL, &itv, NULL);
+
+		res = fcntl(fd, F_SETLKW, &fl);
+		kill(pid, SIGTERM);
+		safe_waitpid(pid);
+		close(pfd[0]);
+		close(pfd[1]);
+		FAIL(!(res == 0 || (res == -1 && errno == EINTR)));
+
+		fl.l_start = 0;
+		fl.l_len = 0;
+		fl.l_type = F_UNLCK;
+		if (fcntl(fd, F_SETLK, &fl) < 0)
+			err(1, "F_UNLCK");
+	}
+	SUCCEED;
+}
+
+/*
+ * Test 14 - soak test
+ */
+static int
+test14(int fd, int argc, const char **argv)
+{
+#define CHILD_COUNT 20
+	/*
+	 * We create a set of child processes and let each one run
+	 * through a random sequence of locks and unlocks.
+	 */
+	int i, j, id, id_base;
+	int pids[CHILD_COUNT], pid;
+	char buf[128];
+	char tbuf[128];
+	int map[128];
+	char outbuf[512];
+	struct flock fl;
+	struct itimerval itv;
+	int status;
+
+	id_base = 0;
+	if (argc >= 2)
+		id_base = strtol(argv[1], NULL, 0);
+
+	printf("14 - soak test: ");
+	fflush(stdout);
+
+	for (i = 0; i < 128; i++)
+		map[i] = F_UNLCK;
+
+	for (i = 0; i < CHILD_COUNT; i++) {
+
+		pid = fork();
+		if (pid < 0)
+			err(1, "fork");
+		if (pid) {
+			/*
+			 * Parent - record the pid and continue.
+			 */
+			pids[i] = pid;
+			continue;
+		}
+
+		/*
+		 * Child - do some work and exit.
+		 */
+		id = id_base + i;
+		srandom(getpid());
+
+		for (j = 0; j < 50; j++) {
+			int start, end, len;
+			int set, wrlock;
+
+			do {
+				start = random() & 127;
+				end = random() & 127;
+			} while (end <= start);
+
+			set = random() & 1;
+			wrlock = random() & 1;
+
+			len = end - start;
+			fl.l_start = start;
+			fl.l_len = len;
+			fl.l_whence = SEEK_SET;
+			if (set)
+				fl.l_type = wrlock ? F_WRLCK : F_RDLCK;
+			else
+				fl.l_type = F_UNLCK;
+
+			itv.it_interval.tv_sec = 0;
+			itv.it_interval.tv_usec = 0;
+			itv.it_value.tv_sec = 0;
+			itv.it_value.tv_usec = 3000;
+			setitimer(ITIMER_REAL, &itv, NULL);
+
+			if (fcntl(fd, F_SETLKW, &fl) < 0) {
+				if (errno == EDEADLK || errno == EINTR) {
+					if (verbose) {
+						snprintf(outbuf, sizeof(outbuf),
+						    "%d[%d]: %s [%d .. %d] %s\n",
+						    id, j,
+						    set ? (wrlock ? "write lock"
+							: "read lock")
+						    : "unlock", start, end,
+						    errno == EDEADLK
+						    ? "deadlock"
+						    : "interrupted");
+						write(1, outbuf,
+						    strlen(outbuf));
+					}
+					continue;
+				} else {
+					perror("fcntl");
+				}
+			}
+
+			itv.it_interval.tv_sec = 0;
+			itv.it_interval.tv_usec = 0;
+			itv.it_value.tv_sec = 0;
+			itv.it_value.tv_usec = 0;
+			setitimer(ITIMER_REAL, &itv, NULL);
+
+			if (verbose) {
+				snprintf(outbuf, sizeof(outbuf),
+				    "%d[%d]: %s [%d .. %d] succeeded\n",
+				    id, j,
+				    set ? (wrlock ? "write lock" : "read lock")
+				    : "unlock", start, end);
+				write(1, outbuf, strlen(outbuf));
+			}
+
+			if (set) {
+				if (wrlock) {
+					/*
+					 * We got a write lock - write
+					 * our ID to each byte that we
+					 * managed to claim.
+					 */
+					for (i = start; i < end; i++)
+						map[i] = F_WRLCK;
+					memset(&buf[start], id, len);
+					if (pwrite(fd, &buf[start], len,
+						start) != len) {
+						printf("%d: short write\n", id);
+						exit(1);
+					}
+				} else {
+					/*
+					 * We got a read lock - read
+					 * the bytes which we claimed
+					 * so that we can check that
+					 * they don't change
+					 * unexpectedly.
+					 */
+					for (i = start; i < end; i++)
+						map[i] = F_RDLCK;
+					if (pread(fd, &buf[start], len,
+						start) != len) {
+						printf("%d: short read\n", id);
+						exit(1);
+					}
+				}
+			} else {
+				for (i = start; i < end; i++)
+					map[i] = F_UNLCK;
+			}
+
+			usleep(1000);
+
+			/*
+			 * Read back the whole region so that we can
+			 * check that all the bytes we have some kind
+			 * of claim to have the correct value.
+			 */
+			if (pread(fd, tbuf, sizeof(tbuf), 0) != sizeof(tbuf)) {
+				printf("%d: short read\n", id);
+				exit(1);
+			}
+
+			for (i = 0; i < 128; i++) {
+				if (map[i] != F_UNLCK && buf[i] != tbuf[i]) {
+					snprintf(outbuf, sizeof(outbuf),
+					    "%d: byte %d expected %d, "
+					    "got %d\n", id, i, buf[i], tbuf[i]);
+					write(1, outbuf, strlen(outbuf));
+					exit(1);
+				}
+			}
+		}
+		if (verbose)
+			printf("%d[%d]: done\n", id, j);
+
+		exit(0);
+	}
+
+	status = 0;
+	for (i = 0; i < CHILD_COUNT; i++) {
+		status += safe_waitpid(pids[i]);
+	}
+	if (status)
+		FAIL(status != 0);
+
+	SUCCEED;
+}
+
+/*
+ * Test 15 - flock(2) semantcs
+ *
+ * When a lock holder has a shared lock and attempts to upgrade that
+ * shared lock to exclusive, it must drop the shared lock before
+ * blocking on the exclusive lock.
+ *
+ * To test this, we first arrange for two shared locks on the file,
+ * and then attempt to upgrade one of them to exclusive. This should
+ * drop one of the shared locks and block. We interrupt the blocking
+ * lock request and examine the lock state of the file after dropping
+ * the other shared lock - there should be no active locks at this
+ * point.
+ */
+static int
+test15(int fd, __unused int argc, const __unused char **argv)
+{
+#ifdef LOCK_EX
+	/*
+	 * We create a child process to hold the lock which we will
+	 * test. We use a pipe to communicate with the child.
+	 *
+	 * Since we only have one file descriptors and lock ownership
+	 * for flock(2) goes with the file descriptor, we use fcntl to
+	 * set the child's shared lock.
+	 */
+	int pid;
+	int pfd[2];
+	struct flock fl;
+	char ch;
+	int res;
+
+	if (pipe(pfd) < 0)
+		err(1, "pipe");
+
+	pid = fork();
+	if (pid < 0)
+		err(1, "fork");
+
+	if (pid == 0) {
+		/*
+		 * We are the child. We set a shared lock and then
+		 * write one byte back to the parent to tell it. The
+		 * parent will kill us when its done.
+		 */
+		fl.l_start = 0;
+		fl.l_len = 0;
+		fl.l_type = F_RDLCK;
+		fl.l_whence = SEEK_SET;
+		if (fcntl(fd, F_SETLK, &fl) < 0)
+			err(1, "fcntl(F_SETLK) (child)");
+		if (write(pfd[1], "a", 1) < 0)
+			err(1, "writing to pipe (child)");
+		pause();
+		exit(0);
+	}
+
+	/*
+	 * Wait until the child has set its lock and then perform the
+	 * test.
+	 */
+	if (read(pfd[0], &ch, 1) != 1)
+		err(1, "reading from pipe (child)");
+
+	(void)dup(fd);
+	if (flock(fd, LOCK_SH) < 0)
+		err(1, "flock shared");
+
+	/*
+	 * flock should wait until the alarm and then return -1 with
+	 * errno set to EINTR.
+	 */
+	printf("15 - flock(2) semantics: ");
+
+	alarm(1);
+	flock(fd, LOCK_EX);
+
+	/*
+	 * Kill the child to force it to drop its locks.
+	 */
+	kill(pid, SIGTERM);
+	safe_waitpid(pid);
+
+	fl.l_start = 0;
+	fl.l_len = 0;
+	fl.l_type = F_WRLCK;
+	fl.l_whence = SEEK_SET;
+	res = fcntl(fd, F_GETLK, &fl);
+
+	close(pfd[0]);
+	close(pfd[1]);
+	FAIL(res != 0);
+	FAIL(fl.l_type != F_UNLCK);
+
+	SUCCEED;
+#else
+	return 0;
+#endif
+}
+
+struct test_ctx {
+	struct flock tc_fl;
+	int tc_fd;
+};
+
+static void *
+test16_func(void *tc_in)
+{
+	uintptr_t error;
+	struct test_ctx *tc = tc_in;
+
+	error = fcntl(tc->tc_fd, F_SETLKW, &tc->tc_fl);
+
+	pthread_exit((void *)error);
+}
+
+#define THREADS 10
+
+/*
+ * Test 16 - F_SETLKW from two threads
+ *
+ * If two threads within a process are blocked on a lock and the lock
+ * is granted, make sure things are sane.
+ */
+static int
+test16(int fd, __unused int argc, const __unused char **argv)
+{
+	/*
+	 * We create a child process to hold the lock which we will
+	 * test. We use a pipe to communicate with the child.
+	 */
+	int pid;
+	int pfd[2];
+	struct test_ctx tc = { .tc_fd = fd };
+	char ch;
+	int i;
+	int error;
+	pthread_t thr[THREADS];
+
+	if (pipe(pfd) < 0)
+		err(1, "pipe");
+
+	tc.tc_fl.l_start = 0;
+	tc.tc_fl.l_len = 0;
+	tc.tc_fl.l_type = F_WRLCK;
+	tc.tc_fl.l_whence = SEEK_SET;
+
+	pid = fork();
+	if (pid < 0)
+		err(1, "fork");
+
+	if (pid == 0) {
+		/*
+		 * We are the child. We set a write lock and then
+		 * write one byte back to the parent to tell it. The
+		 * parent will kill us when its done.
+		 */
+		if (fcntl(fd, F_SETLK, &tc.tc_fl) < 0)
+			err(1, "F_SETLK (child)");
+		if (write(pfd[1], "a", 1) < 0)
+			err(1, "writing to pipe (child)");
+		pause();
+		exit(0);
+	}
+
+	/*
+	 * Wait until the child has set its lock and then perform the
+	 * test.
+	 */
+	if (read(pfd[0], &ch, 1) != 1)
+		err(1, "reading from pipe (child)");
+
+	/*
+	 * fcntl should wait until the alarm and then return -1 with
+	 * errno set to EINTR.
+	 */
+	printf("16 - F_SETLKW on locked region by two threads: ");
+
+	for (i = 0; i < THREADS; i++) {
+		error = pthread_create(&thr[i], NULL, test16_func, &tc);
+		if (error)
+			err(1, "pthread_create");
+	}
+
+	/*
+	 * Sleep, then kill the child. This makes me a little sad, but it's
+	 * tricky to tell whether the threads are all really blocked by this
+	 * point.
+	 */
+	sleep(1);
+	kill(pid, SIGTERM);
+	safe_waitpid(pid);
+	close(pfd[0]);
+	close(pfd[1]);
+
+	for (i = 0; i < THREADS; i++) {
+		void *res;
+		error = pthread_join(thr[i], &res);
+		if (error)
+			err(1, "pthread_join");
+		FAIL((uintptr_t)res != 0);
+	}
+
+	SUCCEED;
+}
+
+struct test {
+	int (*testfn)(int, int, const char **);	/* function to perform the test */
+	int num;		/* test number */
+	int intr;		/* non-zero if the test interrupts a lock */
+};
+
+static struct test tests[] = {
+	{	test1,		1,	0	},
+	{	test2,		2,	0	},
+	{	test3,		3,	1	},
+	{	test4,		4,	0	},
+	{	test5,		5,	1	},
+	{	test6,		6,	1	},
+	{	test7,		7,	0	},
+	{	test8,		8,	0	},
+	{	test9,		9,	0	},
+	{	test10,		10,	0	},
+	{	test11,		11,	1	},
+	{	test12,		12,	0	},
+	{	test13,		13,	1	},
+	{	test14,		14,	0	},
+	{	test15,		15,	1	},
+	{	test16,		16,	1	},
+};
+
+int
+main(int argc, const char *argv[])
+{
+	int testnum;
+	int fd;
+	int nointr;
+	unsigned i;
+	struct sigaction sa;
+	int test_argc;
+	const char **test_argv;
+
+	if (argc < 2) {
+		errx(1, "usage: flock <directory> [test number] ...");
+	}
+
+	fd = make_file(argv[1], 1024);
+	if (argc >= 3) {
+		testnum = strtol(argv[2], NULL, 0);
+		test_argc = argc - 2;
+		test_argv = argv + 2;
+	} else {
+		testnum = 0;
+		test_argc = 0;
+		test_argv = NULL;
+	}
+
+	sa.sa_handler = ignore_alarm;
+	sigemptyset(&sa.sa_mask);
+	sa.sa_flags = 0;
+	sigaction(SIGALRM, &sa, 0);
+
+	nointr = 0;
+#if defined(__FreeBSD__) && __FreeBSD_version < 800040
+	{
+		/*
+		 * FreeBSD with userland NLM can't interrupt a blocked
+		 * lock request on an NFS mounted filesystem.
+		 */
+		struct statfs st;
+		fstatfs(fd, &st);
+		nointr = !strcmp(st.f_fstypename, "nfs");
+	}
+#endif
+
+	for (i = 0; i < nitems(tests); i++) {
+		if (tests[i].intr && nointr)
+			continue;
+		if (!testnum || tests[i].num == testnum)
+			tests[i].testfn(fd, test_argc, test_argv);
+	}
+
+	return 0;
+}


Property changes on: trunk/tests/sys/file/flock_helper.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/tests/sys/file/flock_test.sh
===================================================================
--- trunk/tests/sys/file/flock_test.sh	                        (rev 0)
+++ trunk/tests/sys/file/flock_test.sh	2018-07-28 21:14:08 UTC (rev 11974)
@@ -0,0 +1,58 @@
+#!/bin/sh
+#
+# Copyright 2014 EMC Corp.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# * Neither the name of Google Inc. nor the names of its contributors
+#   may be used to endorse or promote products derived from this software
+#   without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# $MidnightBSD$
+
+# Testcase # 11 is racy; uses an undocumented kernel interface for testing
+#            locking
+# Testcase # 16 is racy/doesn't handle EINTR properly
+last_testcase=16
+
+echo "1..$last_testcase"
+
+for n in `seq 1 $last_testcase`; do
+	todomsg=""
+
+	if [ $n -eq 11 ]; then
+		todomsg=" # TODO: racy testcase"
+	# Test 16 fails:
+	# F_SETLKW on locked region by two threads: FAIL ((uintptr_t)res != 0)
+	elif [ $n -eq 16 ]; then
+		todomsg=" # TODO: racy testcase (doesn't handle EINTR properly)"
+	fi
+
+	output=$($(dirname $0)/flock_helper . $n)
+	if echo "$output" | grep -q SUCCEED; then
+		echo "ok $n$todomsg"
+	else
+		echo "not ok $n$todomsg"
+		echo "$output" >&2
+	fi
+done


Property changes on: trunk/tests/sys/file/flock_test.sh
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/tests/sys/file/ftruncate_test.c
===================================================================
--- trunk/tests/sys/file/ftruncate_test.c	                        (rev 0)
+++ trunk/tests/sys/file/ftruncate_test.c	2018-07-28 21:14:08 UTC (rev 11974)
@@ -0,0 +1,177 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2006 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: stable/10/tests/sys/file/ftruncate_test.c 319301 2017-05-31 08:36:47Z ngie $
+ */
+
+/*
+ * Very simple regression test.
+ *
+ * Future tests that might be of interest:
+ *
+ * - Make sure we get EISDIR on a directory.
+ */
+
+#include <sys/types.h>
+#include <sys/event.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <stdio.h>
+#include <unistd.h>
+
+/*
+ * Select various potentially interesting lengths at and around power of 2
+ * edges.
+ */
+static off_t lengths[] = {0, 1, 2, 3, 4, 127, 128, 129, 511, 512, 513, 1023,
+    1024, 1025, 2047, 2048, 2049, 4095, 4096, 4097, 8191, 8192, 8193, 16383,
+    16384, 16385};
+static int lengths_count = sizeof(lengths) / sizeof(off_t);
+
+int
+main(void)
+{
+	int error, fd, fds[2], i, read_only_fd;
+	char path[] = "ftruncate_file";
+	struct stat sb;
+	ssize_t size;
+	off_t len;
+	char ch;
+
+	/*
+	 * Tests using a writable file: grow and then shrink a file
+	 * using ftruncate and various lengths.  Make sure that a negative
+	 * file length is rejected.  Make sure that when we grow the file,
+	 * bytes now in the range of the file size return 0.
+	 *
+	 * Save a read-only reference to the file to use later for read-only
+	 * descriptor tests.
+	 */
+	fd = open(path, O_RDWR|O_CREAT, 0600);
+	if (fd < 0)
+		err(1, "open(%s, O_RDWR|O_CREAT, 0600)", path);
+	read_only_fd = open(path, O_RDONLY);
+	if (read_only_fd < 0) {
+		error = errno;
+		(void)unlink(path);
+		errno = error;
+		err(1, "open(%s, O_RDONLY)", path);
+	}
+	(void)unlink(path);
+
+	if (ftruncate(fd, -1) == 0)
+		errx(1, "ftruncate(fd, -1) succeeded unexpectedly");
+	if (errno != EINVAL)
+		err(1, "ftruncate(fd, -1) returned wrong error");
+
+	for (i = 0; i < lengths_count; i++) {
+		len = lengths[i];
+		if (ftruncate(fd, len) < 0)
+			err(1, "ftruncate(%jd) up", (intmax_t)len);
+		if (fstat(fd, &sb) < 0)
+			err(1, "stat");
+		if (sb.st_size != len)
+			errx(-1, "fstat with len=%jd returned len %jd up",
+			    (intmax_t)len, (intmax_t)sb.st_size);
+		if (len != 0) {
+			size = pread(fd, &ch, sizeof(ch), len - 1);
+			if (size < 0)
+				err(1, "pread on len %jd up", (intmax_t)len);
+			if (size != sizeof(ch))
+				errx(-1, "pread len %jd size %jd up",
+				    (intmax_t)len, (intmax_t)size);
+			if (ch != 0)
+				errx(-1,
+				    "pread length %jd size %jd ch %d up",
+				    (intmax_t)len, (intmax_t)size, ch);
+		}
+	}
+
+	for (i = lengths_count - 1; i >= 0; i--) {
+		len = lengths[i];
+		if (ftruncate(fd, len) < 0)
+			err(1, "ftruncate(%jd) down", (intmax_t)len);
+		if (fstat(fd, &sb) < 0)
+			err(1, "stat");
+		if (sb.st_size != len)
+			errx(-1, "fstat(%jd) returned %jd down", (intmax_t)len,
+			    sb.st_size);
+	}
+	close(fd);
+
+	/*
+	 * Make sure that a read-only descriptor can't be truncated.
+	 */
+	if (ftruncate(read_only_fd, 0) == 0)
+		errx(-1, "ftruncate(read_only_fd) succeeded");
+	if (errno != EINVAL)
+		err(1, "ftruncate(read_only_fd) returned wrong error");
+	close(read_only_fd);
+
+	/*
+	 * Make sure that ftruncate on sockets doesn't work.
+	 */
+	fd = socket(PF_UNIX, SOCK_STREAM, 0);
+	if (fd < 0)
+		err(1, "socket(PF_UNIX, SOCK_STREAM, 0)");
+	if (ftruncate(fd, 0) == 0)
+		errx(-1, "ftruncate(socket) succeeded");
+	if (errno != EINVAL)
+		err(1, "ftruncate(socket) returned wrong error");
+	close(fd);
+
+	/*
+	 * Make sure that ftruncate on pipes doesn't work.
+	 */
+	if (pipe(fds) < 0)
+		err(1, "pipe");
+	if (ftruncate(fds[0], 0) == 0)
+		errx(-1, "ftruncate(pipe) succeeded");
+	if (errno != EINVAL)
+		err(1, "ftruncate(pipe) returned wrong error");
+	close(fds[0]);
+	close(fds[1]);
+
+	/*
+	 * Make sure that ftruncate on kqueues doesn't work.
+	 */
+	fd = kqueue();
+	if (fd < 0)
+		err(1, "kqueue");
+	if (ftruncate(fds[0], 0) == 0)
+		errx(-1, "ftruncate(kqueue) succeeded");
+	if (errno != EINVAL)
+		err(1, "ftruncate(kqueue) returned wrong error");
+	close(fd);
+
+	return (0);
+}


Property changes on: trunk/tests/sys/file/ftruncate_test.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/tests/sys/file/newfileops_on_fork_test.c
===================================================================
--- trunk/tests/sys/file/newfileops_on_fork_test.c	                        (rev 0)
+++ trunk/tests/sys/file/newfileops_on_fork_test.c	2018-07-28 21:14:08 UTC (rev 11974)
@@ -0,0 +1,123 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2009 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * This software was developed at the University of Cambridge Computer
+ * Laboratory with support from a grant from Google, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: stable/10/tests/sys/file/newfileops_on_fork_test.c 319301 2017-05-31 08:36:47Z ngie $
+ */
+
+/*
+ * When a multi-threaded application calls fork(2) from one thread while
+ * another thread is blocked in accept(2), we prefer that the file descriptor
+ * to be returned by accept(2) not appear in the child process.  Test this by
+ * creating a thread blocked in accept(2), then forking a child and seeing if
+ * the fd it would have returned is defined in the child or not.
+ */
+
+#include <sys/socket.h>
+#include <sys/wait.h>
+
+#include <netinet/in.h>
+
+#include <err.h>
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define	PORT	9000
+
+static int listen_fd;
+
+static void *
+do_accept(__unused void *arg)
+{
+	int accept_fd;
+
+	accept_fd = accept(listen_fd, NULL, NULL);
+	if (accept_fd < 0)
+		err(1, "accept");
+
+	close(accept_fd);
+	return (NULL);
+}
+
+static void
+do_fork(void)
+{
+	int pid;
+
+	pid = fork();
+	if (pid < 0)
+		err(1, "fork");
+	if (pid > 0) {
+		waitpid(pid, NULL, 0);
+		exit(0);
+	}
+
+	/*
+	 * We will call ftruncate(2) on the next available file descriptor,
+	 * listen_fd+1, and get back EBADF if it's not a valid descriptor,
+	 * and EINVAL if it is.  This (currently) works fine in practice.
+	 */
+	if (ftruncate(listen_fd + 1, 0) < 0) {
+		if (errno == EBADF)
+			exit(0);
+		else if (errno == EINVAL)
+			errx(1, "file descriptor still open in child");
+		else
+			err(1, "unexpected error");
+	} else
+		errx(1, "ftruncate succeeded");
+}
+
+int
+main(void)
+{
+	struct sockaddr_in sin;
+	pthread_t accept_thread;
+
+	listen_fd = socket(PF_INET, SOCK_STREAM, 0);
+	if (listen_fd < 0)
+		err(1, "socket");
+	bzero(&sin, sizeof(sin));
+	sin.sin_family = AF_INET;
+	sin.sin_len = sizeof(sin);
+	sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+	sin.sin_port = htons(PORT);
+	if (bind(listen_fd, (struct sockaddr *)&sin, sizeof(sin)) < 0)
+		err(1, "bind");
+	if (listen(listen_fd, -1) <0)
+		err(1, "listen");
+	if (pthread_create(&accept_thread, NULL, do_accept, NULL) != 0)
+		err(1, "pthread_create");
+	sleep(1);	/* Easier than using a CV. */
+	do_fork();
+	exit(0);
+}


Property changes on: trunk/tests/sys/file/newfileops_on_fork_test.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property


More information about the Midnightbsd-cvs mailing list