xref: /freebsd/tests/sys/file/flock_helper.c (revision b3e7694832e81d7a904a10f525f8797b753bf0d3)
13cedbec3SEnji Cooper /*-
23cedbec3SEnji Cooper  * Copyright (c) 2008 Isilon Inc http://www.isilon.com/
33cedbec3SEnji Cooper  * Authors: Doug Rabson <dfr@rabson.org>
43cedbec3SEnji Cooper  * Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org>
53cedbec3SEnji Cooper  *
63cedbec3SEnji Cooper  * Redistribution and use in source and binary forms, with or without
73cedbec3SEnji Cooper  * modification, are permitted provided that the following conditions
83cedbec3SEnji Cooper  * are met:
93cedbec3SEnji Cooper  * 1. Redistributions of source code must retain the above copyright
103cedbec3SEnji Cooper  *    notice, this list of conditions and the following disclaimer.
113cedbec3SEnji Cooper  * 2. Redistributions in binary form must reproduce the above copyright
123cedbec3SEnji Cooper  *    notice, this list of conditions and the following disclaimer in the
133cedbec3SEnji Cooper  *    documentation and/or other materials provided with the distribution.
143cedbec3SEnji Cooper  *
153cedbec3SEnji Cooper  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
163cedbec3SEnji Cooper  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
173cedbec3SEnji Cooper  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
183cedbec3SEnji Cooper  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
193cedbec3SEnji Cooper  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
203cedbec3SEnji Cooper  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
213cedbec3SEnji Cooper  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
223cedbec3SEnji Cooper  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
233cedbec3SEnji Cooper  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
243cedbec3SEnji Cooper  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
253cedbec3SEnji Cooper  * SUCH DAMAGE.
263cedbec3SEnji Cooper  */
273cedbec3SEnji Cooper 
283cedbec3SEnji Cooper #include <sys/param.h>
293cedbec3SEnji Cooper #include <sys/file.h>
303cedbec3SEnji Cooper #include <sys/time.h>
313cedbec3SEnji Cooper #ifdef __FreeBSD__
323cedbec3SEnji Cooper #include <sys/mount.h>
333cedbec3SEnji Cooper #endif
343cedbec3SEnji Cooper #include <sys/stat.h>
353cedbec3SEnji Cooper #include <sys/wait.h>
363cedbec3SEnji Cooper 
373cedbec3SEnji Cooper #include <err.h>
383cedbec3SEnji Cooper #include <errno.h>
393cedbec3SEnji Cooper #include <fcntl.h>
403cedbec3SEnji Cooper #include <pthread.h>
413cedbec3SEnji Cooper #include <signal.h>
423cedbec3SEnji Cooper #include <stdint.h>
433cedbec3SEnji Cooper #include <stdio.h>
443cedbec3SEnji Cooper #include <stdlib.h>
453cedbec3SEnji Cooper #include <string.h>
463cedbec3SEnji Cooper #include <unistd.h>
473cedbec3SEnji Cooper 
483cedbec3SEnji Cooper #ifdef __FreeBSD__
493cedbec3SEnji Cooper #if __FreeBSD_version >= 800028
503cedbec3SEnji Cooper #define HAVE_SYSID
513cedbec3SEnji Cooper #endif
523cedbec3SEnji Cooper #include <sys/cdefs.h>
533cedbec3SEnji Cooper #else
543cedbec3SEnji Cooper #ifndef nitems
553cedbec3SEnji Cooper #define	nitems(x)	(sizeof((x)) / sizeof((x)[0]))
563cedbec3SEnji Cooper #endif
573cedbec3SEnji Cooper 
583cedbec3SEnji Cooper #ifndef __unused
593cedbec3SEnji Cooper #ifdef __GNUC__
603cedbec3SEnji Cooper #define	__unused	__attribute__((__unused__))
613cedbec3SEnji Cooper #else
623cedbec3SEnji Cooper #define __unused
633cedbec3SEnji Cooper #endif
643cedbec3SEnji Cooper #endif
653cedbec3SEnji Cooper #endif
663cedbec3SEnji Cooper 
673cedbec3SEnji Cooper static int verbose = 0;
683cedbec3SEnji Cooper 
693cedbec3SEnji Cooper static int
make_file(const char * pathname,off_t sz)703cedbec3SEnji Cooper make_file(const char *pathname, off_t sz)
713cedbec3SEnji Cooper {
723cedbec3SEnji Cooper 	struct stat st;
733cedbec3SEnji Cooper 	const char *template = "/flocktempXXXXXX";
743cedbec3SEnji Cooper 	size_t len;
753cedbec3SEnji Cooper 	char *filename;
763cedbec3SEnji Cooper 	int fd;
773cedbec3SEnji Cooper 
783cedbec3SEnji Cooper 	if (stat(pathname, &st) == 0) {
793cedbec3SEnji Cooper 		if (S_ISREG(st.st_mode)) {
803cedbec3SEnji Cooper 			fd = open(pathname, O_RDWR);
813cedbec3SEnji Cooper 			if (fd < 0)
823cedbec3SEnji Cooper 				err(1, "open(%s)", pathname);
833cedbec3SEnji Cooper 			if (ftruncate(fd, sz) < 0)
843cedbec3SEnji Cooper 				err(1, "ftruncate");
853cedbec3SEnji Cooper 			return (fd);
863cedbec3SEnji Cooper 		}
873cedbec3SEnji Cooper 	}
883cedbec3SEnji Cooper 
893cedbec3SEnji Cooper 	len = strlen(pathname) + strlen(template) + 1;
903cedbec3SEnji Cooper 	filename = malloc(len);
913cedbec3SEnji Cooper 	strcpy(filename, pathname);
923cedbec3SEnji Cooper 	strcat(filename, template);
933cedbec3SEnji Cooper 	fd = mkstemp(filename);
943cedbec3SEnji Cooper 	if (fd < 0)
953cedbec3SEnji Cooper 		err(1, "mkstemp");
963cedbec3SEnji Cooper 	if (ftruncate(fd, sz) < 0)
973cedbec3SEnji Cooper 		err(1, "ftruncate");
983cedbec3SEnji Cooper 	if (unlink(filename) < 0)
993cedbec3SEnji Cooper 		err(1, "unlink");
1003cedbec3SEnji Cooper 	free(filename);
1013cedbec3SEnji Cooper 
1023cedbec3SEnji Cooper 	return (fd);
1033cedbec3SEnji Cooper }
1043cedbec3SEnji Cooper 
1053cedbec3SEnji Cooper static void
ignore_alarm(int __unused sig)1063cedbec3SEnji Cooper ignore_alarm(int __unused sig)
1073cedbec3SEnji Cooper {
1083cedbec3SEnji Cooper }
1093cedbec3SEnji Cooper 
1103cedbec3SEnji Cooper static int
safe_waitpid(pid_t pid)1113cedbec3SEnji Cooper safe_waitpid(pid_t pid)
1123cedbec3SEnji Cooper {
1133cedbec3SEnji Cooper 	int save_errno;
1143cedbec3SEnji Cooper 	int status;
1153cedbec3SEnji Cooper 
1163cedbec3SEnji Cooper 	save_errno = errno;
1173cedbec3SEnji Cooper 	errno = 0;
1183cedbec3SEnji Cooper 	while (waitpid(pid, &status, 0) != pid) {
1193cedbec3SEnji Cooper 		if (errno == EINTR)
1203cedbec3SEnji Cooper 			continue;
1213cedbec3SEnji Cooper 		err(1, "waitpid");
1223cedbec3SEnji Cooper 	}
1233cedbec3SEnji Cooper 	errno = save_errno;
1243cedbec3SEnji Cooper 
1253cedbec3SEnji Cooper 	return (status);
1263cedbec3SEnji Cooper }
1273cedbec3SEnji Cooper 
1283cedbec3SEnji Cooper #define FAIL(test)					\
1293cedbec3SEnji Cooper 	do {						\
1303cedbec3SEnji Cooper 		if (test) {				\
1313cedbec3SEnji Cooper 			printf("FAIL (%s)\n", #test);	\
1323cedbec3SEnji Cooper 			return -1;			\
1333cedbec3SEnji Cooper 		}					\
1343cedbec3SEnji Cooper 	} while (0)
1353cedbec3SEnji Cooper 
1363cedbec3SEnji Cooper #define SUCCEED \
1373cedbec3SEnji Cooper 	do { printf("SUCCEED\n"); return 0; } while (0)
1383cedbec3SEnji Cooper 
1393cedbec3SEnji Cooper /*
1403cedbec3SEnji Cooper  * Test 1 - F_GETLK on unlocked region
1413cedbec3SEnji Cooper  *
1423cedbec3SEnji Cooper  * If no lock is found that would prevent this lock from being
1433cedbec3SEnji Cooper  * created, the structure is left unchanged by this function call
1443cedbec3SEnji Cooper  * except for the lock type which is set to F_UNLCK.
1453cedbec3SEnji Cooper  */
1463cedbec3SEnji Cooper static int
test1(int fd,__unused int argc,const __unused char ** argv)1473cedbec3SEnji Cooper test1(int fd, __unused int argc, const __unused char **argv)
1483cedbec3SEnji Cooper {
1493cedbec3SEnji Cooper 	struct flock fl1, fl2;
1503cedbec3SEnji Cooper 
1513cedbec3SEnji Cooper 	memset(&fl1, 1, sizeof(fl1));
1523cedbec3SEnji Cooper 	fl1.l_type = F_WRLCK;
1533cedbec3SEnji Cooper 	fl1.l_whence = SEEK_SET;
1543cedbec3SEnji Cooper 	fl2 = fl1;
1553cedbec3SEnji Cooper 
1563cedbec3SEnji Cooper 	if (fcntl(fd, F_GETLK, &fl1) < 0)
1573cedbec3SEnji Cooper 		err(1, "F_GETLK");
1583cedbec3SEnji Cooper 
1593cedbec3SEnji Cooper 	printf("1 - F_GETLK on unlocked region: ");
1603cedbec3SEnji Cooper 	FAIL(fl1.l_start != fl2.l_start);
1613cedbec3SEnji Cooper 	FAIL(fl1.l_len != fl2.l_len);
1623cedbec3SEnji Cooper 	FAIL(fl1.l_pid != fl2.l_pid);
1633cedbec3SEnji Cooper 	FAIL(fl1.l_type != F_UNLCK);
1643cedbec3SEnji Cooper 	FAIL(fl1.l_whence != fl2.l_whence);
1653cedbec3SEnji Cooper #ifdef HAVE_SYSID
1663cedbec3SEnji Cooper 	FAIL(fl1.l_sysid != fl2.l_sysid);
1673cedbec3SEnji Cooper #endif
1683cedbec3SEnji Cooper 
1693cedbec3SEnji Cooper 	SUCCEED;
1703cedbec3SEnji Cooper }
1713cedbec3SEnji Cooper 
1723cedbec3SEnji Cooper /*
1733cedbec3SEnji Cooper  * Test 2 - F_SETLK on locked region
1743cedbec3SEnji Cooper  *
1753cedbec3SEnji Cooper  * If a shared or exclusive lock cannot be set, fcntl returns
1763cedbec3SEnji Cooper  * immediately with EACCES or EAGAIN.
1773cedbec3SEnji Cooper  */
1783cedbec3SEnji Cooper static int
test2(int fd,__unused int argc,const __unused char ** argv)1793cedbec3SEnji Cooper test2(int fd, __unused int argc, const __unused char **argv)
1803cedbec3SEnji Cooper {
1813cedbec3SEnji Cooper 	/*
1823cedbec3SEnji Cooper 	 * We create a child process to hold the lock which we will
1833cedbec3SEnji Cooper 	 * test. We use a pipe to communicate with the child.
1843cedbec3SEnji Cooper 	 */
1853cedbec3SEnji Cooper 	int pid;
1863cedbec3SEnji Cooper 	int pfd[2];
1873cedbec3SEnji Cooper 	struct flock fl;
1883cedbec3SEnji Cooper 	char ch;
1893cedbec3SEnji Cooper 	int res;
1903cedbec3SEnji Cooper 
1913cedbec3SEnji Cooper 	if (pipe(pfd) < 0)
1923cedbec3SEnji Cooper 		err(1, "pipe");
1933cedbec3SEnji Cooper 
1943cedbec3SEnji Cooper 	fl.l_start = 0;
1953cedbec3SEnji Cooper 	fl.l_len = 0;
1963cedbec3SEnji Cooper 	fl.l_type = F_WRLCK;
1973cedbec3SEnji Cooper 	fl.l_whence = SEEK_SET;
1983cedbec3SEnji Cooper 
1993cedbec3SEnji Cooper 	pid = fork();
2003cedbec3SEnji Cooper 	if (pid < 0)
2013cedbec3SEnji Cooper 		err(1, "fork");
2023cedbec3SEnji Cooper 
2033cedbec3SEnji Cooper 	if (pid == 0) {
2043cedbec3SEnji Cooper 		/*
2053cedbec3SEnji Cooper 		 * We are the child. We set a write lock and then
2063cedbec3SEnji Cooper 		 * write one byte back to the parent to tell it. The
2073cedbec3SEnji Cooper 		 * parent will kill us when its done.
2083cedbec3SEnji Cooper 		 */
2093cedbec3SEnji Cooper 		if (fcntl(fd, F_SETLK, &fl) < 0)
2103cedbec3SEnji Cooper 			err(1, "F_SETLK (child)");
2113cedbec3SEnji Cooper 		if (write(pfd[1], "a", 1) < 0)
2123cedbec3SEnji Cooper 			err(1, "writing to pipe (child)");
2133cedbec3SEnji Cooper 		pause();
2143cedbec3SEnji Cooper 		exit(0);
2153cedbec3SEnji Cooper 	}
2163cedbec3SEnji Cooper 
2173cedbec3SEnji Cooper 	/*
2183cedbec3SEnji Cooper 	 * Wait until the child has set its lock and then perform the
2193cedbec3SEnji Cooper 	 * test.
2203cedbec3SEnji Cooper 	 */
2213cedbec3SEnji Cooper 	if (read(pfd[0], &ch, 1) != 1)
2223cedbec3SEnji Cooper 		err(1, "reading from pipe (child)");
2233cedbec3SEnji Cooper 
2243cedbec3SEnji Cooper 	/*
2253cedbec3SEnji Cooper 	 * fcntl should return -1 with errno set to either EACCES or
2263cedbec3SEnji Cooper 	 * EAGAIN.
2273cedbec3SEnji Cooper 	 */
2283cedbec3SEnji Cooper 	printf("2 - F_SETLK on locked region: ");
2293cedbec3SEnji Cooper 	res = fcntl(fd, F_SETLK, &fl);
2303cedbec3SEnji Cooper 	kill(pid, SIGTERM);
2313cedbec3SEnji Cooper 	safe_waitpid(pid);
2323cedbec3SEnji Cooper 	close(pfd[0]);
2333cedbec3SEnji Cooper 	close(pfd[1]);
2343cedbec3SEnji Cooper 	FAIL(res == 0);
2353cedbec3SEnji Cooper 	FAIL(errno != EACCES && errno != EAGAIN);
2363cedbec3SEnji Cooper 
2373cedbec3SEnji Cooper 	SUCCEED;
2383cedbec3SEnji Cooper }
2393cedbec3SEnji Cooper 
2403cedbec3SEnji Cooper /*
2413cedbec3SEnji Cooper  * Test 3 - F_SETLKW on locked region
2423cedbec3SEnji Cooper  *
2433cedbec3SEnji Cooper  * If a shared or exclusive lock is blocked by other locks, the
2443cedbec3SEnji Cooper  * process waits until the request can be satisfied.
2453cedbec3SEnji Cooper  *
2463cedbec3SEnji Cooper  * XXX this test hangs on FreeBSD NFS filesystems due to limitations
2473cedbec3SEnji Cooper  * in FreeBSD's client (and server) lockd implementation.
2483cedbec3SEnji Cooper  */
2493cedbec3SEnji Cooper static int
test3(int fd,__unused int argc,const __unused char ** argv)2503cedbec3SEnji Cooper test3(int fd, __unused int argc, const __unused char **argv)
2513cedbec3SEnji Cooper {
2523cedbec3SEnji Cooper 	/*
2533cedbec3SEnji Cooper 	 * We create a child process to hold the lock which we will
2543cedbec3SEnji Cooper 	 * test. We use a pipe to communicate with the child.
2553cedbec3SEnji Cooper 	 */
2563cedbec3SEnji Cooper 	int pid;
2573cedbec3SEnji Cooper 	int pfd[2];
2583cedbec3SEnji Cooper 	struct flock fl;
2593cedbec3SEnji Cooper 	char ch;
2603cedbec3SEnji Cooper 	int res;
2613cedbec3SEnji Cooper 
2623cedbec3SEnji Cooper 	if (pipe(pfd) < 0)
2633cedbec3SEnji Cooper 		err(1, "pipe");
2643cedbec3SEnji Cooper 
2653cedbec3SEnji Cooper 	fl.l_start = 0;
2663cedbec3SEnji Cooper 	fl.l_len = 0;
2673cedbec3SEnji Cooper 	fl.l_type = F_WRLCK;
2683cedbec3SEnji Cooper 	fl.l_whence = SEEK_SET;
2693cedbec3SEnji Cooper 
2703cedbec3SEnji Cooper 	pid = fork();
2713cedbec3SEnji Cooper 	if (pid < 0)
2723cedbec3SEnji Cooper 		err(1, "fork");
2733cedbec3SEnji Cooper 
2743cedbec3SEnji Cooper 	if (pid == 0) {
2753cedbec3SEnji Cooper 		/*
2763cedbec3SEnji Cooper 		 * We are the child. We set a write lock and then
2773cedbec3SEnji Cooper 		 * write one byte back to the parent to tell it. The
2783cedbec3SEnji Cooper 		 * parent will kill us when its done.
2793cedbec3SEnji Cooper 		 */
2803cedbec3SEnji Cooper 		if (fcntl(fd, F_SETLK, &fl) < 0)
2813cedbec3SEnji Cooper 			err(1, "F_SETLK (child)");
2823cedbec3SEnji Cooper 		if (write(pfd[1], "a", 1) < 0)
2833cedbec3SEnji Cooper 			err(1, "writing to pipe (child)");
2843cedbec3SEnji Cooper 		pause();
2853cedbec3SEnji Cooper 		exit(0);
2863cedbec3SEnji Cooper 	}
2873cedbec3SEnji Cooper 
2883cedbec3SEnji Cooper 	/*
2893cedbec3SEnji Cooper 	 * Wait until the child has set its lock and then perform the
2903cedbec3SEnji Cooper 	 * test.
2913cedbec3SEnji Cooper 	 */
2923cedbec3SEnji Cooper 	if (read(pfd[0], &ch, 1) != 1)
2933cedbec3SEnji Cooper 		err(1, "reading from pipe (child)");
2943cedbec3SEnji Cooper 
2953cedbec3SEnji Cooper 	/*
2963cedbec3SEnji Cooper 	 * fcntl should wait until the alarm and then return -1 with
2973cedbec3SEnji Cooper 	 * errno set to EINTR.
2983cedbec3SEnji Cooper 	 */
2993cedbec3SEnji Cooper 	printf("3 - F_SETLKW on locked region: ");
3003cedbec3SEnji Cooper 
3013cedbec3SEnji Cooper 	alarm(1);
3023cedbec3SEnji Cooper 
3033cedbec3SEnji Cooper 	res = fcntl(fd, F_SETLKW, &fl);
3043cedbec3SEnji Cooper 	kill(pid, SIGTERM);
3053cedbec3SEnji Cooper 	safe_waitpid(pid);
3063cedbec3SEnji Cooper 	close(pfd[0]);
3073cedbec3SEnji Cooper 	close(pfd[1]);
3083cedbec3SEnji Cooper 	FAIL(res == 0);
3093cedbec3SEnji Cooper 	FAIL(errno != EINTR);
3103cedbec3SEnji Cooper 
3113cedbec3SEnji Cooper 	SUCCEED;
3123cedbec3SEnji Cooper }
3133cedbec3SEnji Cooper 
3143cedbec3SEnji Cooper /*
3153cedbec3SEnji Cooper  * Test 4 - F_GETLK on locked region
3163cedbec3SEnji Cooper  *
3173cedbec3SEnji Cooper  * Get the first lock that blocks the lock.
3183cedbec3SEnji Cooper  */
3193cedbec3SEnji Cooper static int
test4(int fd,__unused int argc,const __unused char ** argv)3203cedbec3SEnji Cooper test4(int fd, __unused int argc, const __unused char **argv)
3213cedbec3SEnji Cooper {
3223cedbec3SEnji Cooper 	/*
3233cedbec3SEnji Cooper 	 * We create a child process to hold the lock which we will
3243cedbec3SEnji Cooper 	 * test. We use a pipe to communicate with the child.
3253cedbec3SEnji Cooper 	 */
3263cedbec3SEnji Cooper 	int pid;
3273cedbec3SEnji Cooper 	int pfd[2];
3283cedbec3SEnji Cooper 	struct flock fl;
3293cedbec3SEnji Cooper 	char ch;
3303cedbec3SEnji Cooper 
3313cedbec3SEnji Cooper 	if (pipe(pfd) < 0)
3323cedbec3SEnji Cooper 		err(1, "pipe");
3333cedbec3SEnji Cooper 
3343cedbec3SEnji Cooper 	fl.l_start = 0;
3353cedbec3SEnji Cooper 	fl.l_len = 99;
3363cedbec3SEnji Cooper 	fl.l_type = F_WRLCK;
3373cedbec3SEnji Cooper 	fl.l_whence = SEEK_SET;
3383cedbec3SEnji Cooper 
3393cedbec3SEnji Cooper 	pid = fork();
3403cedbec3SEnji Cooper 	if (pid < 0)
3413cedbec3SEnji Cooper 		err(1, "fork");
3423cedbec3SEnji Cooper 
3433cedbec3SEnji Cooper 	if (pid == 0) {
3443cedbec3SEnji Cooper 		/*
3453cedbec3SEnji Cooper 		 * We are the child. We set a write lock and then
3463cedbec3SEnji Cooper 		 * write one byte back to the parent to tell it. The
3473cedbec3SEnji Cooper 		 * parent will kill us when its done.
3483cedbec3SEnji Cooper 		 */
3493cedbec3SEnji Cooper 		if (fcntl(fd, F_SETLK, &fl) < 0)
3503cedbec3SEnji Cooper 			err(1, "F_SETLK (child)");
3513cedbec3SEnji Cooper 		if (write(pfd[1], "a", 1) < 0)
3523cedbec3SEnji Cooper 			err(1, "writing to pipe (child)");
3533cedbec3SEnji Cooper 		pause();
3543cedbec3SEnji Cooper 		exit(0);
3553cedbec3SEnji Cooper 	}
3563cedbec3SEnji Cooper 
3573cedbec3SEnji Cooper 	/*
3583cedbec3SEnji Cooper 	 * Wait until the child has set its lock and then perform the
3593cedbec3SEnji Cooper 	 * test.
3603cedbec3SEnji Cooper 	 */
3613cedbec3SEnji Cooper 	if (read(pfd[0], &ch, 1) != 1)
3623cedbec3SEnji Cooper 		err(1, "reading from pipe (child)");
3633cedbec3SEnji Cooper 
3643cedbec3SEnji Cooper 	/*
3653cedbec3SEnji Cooper 	 * fcntl should return a lock structure reflecting the lock we
3663cedbec3SEnji Cooper 	 * made in the child process.
3673cedbec3SEnji Cooper 	 */
3683cedbec3SEnji Cooper 	if (fcntl(fd, F_GETLK, &fl) < 0)
3693cedbec3SEnji Cooper 		err(1, "F_GETLK");
3703cedbec3SEnji Cooper 
3713cedbec3SEnji Cooper 	printf("4 - F_GETLK on locked region: ");
3723cedbec3SEnji Cooper 	FAIL(fl.l_start != 0);
3733cedbec3SEnji Cooper 	FAIL(fl.l_len != 99);
3743cedbec3SEnji Cooper 	FAIL(fl.l_type != F_WRLCK);
3753cedbec3SEnji Cooper 	FAIL(fl.l_pid != pid);
3763cedbec3SEnji Cooper #ifdef HAVE_SYSID
3773cedbec3SEnji Cooper 	FAIL(fl.l_sysid != 0);
3783cedbec3SEnji Cooper #endif
3793cedbec3SEnji Cooper 
3803cedbec3SEnji Cooper 	kill(pid, SIGTERM);
3813cedbec3SEnji Cooper 	safe_waitpid(pid);
3823cedbec3SEnji Cooper 	close(pfd[0]);
3833cedbec3SEnji Cooper 	close(pfd[1]);
3843cedbec3SEnji Cooper 
3853cedbec3SEnji Cooper 	SUCCEED;
3863cedbec3SEnji Cooper }
3873cedbec3SEnji Cooper 
3883cedbec3SEnji Cooper /*
3893cedbec3SEnji Cooper  * Test 5 - F_SETLKW simple deadlock
3903cedbec3SEnji Cooper  *
3913cedbec3SEnji Cooper  * If a blocking shared lock request would cause a deadlock (i.e. the
3923cedbec3SEnji Cooper  * lock request is blocked by a process which is itself blocked on a
3933cedbec3SEnji Cooper  * lock currently owned by the process making the new request),
3943cedbec3SEnji Cooper  * EDEADLK is returned.
3953cedbec3SEnji Cooper  */
3963cedbec3SEnji Cooper static int
test5(int fd,__unused int argc,const __unused char ** argv)3973cedbec3SEnji Cooper test5(int fd, __unused int argc, const __unused char **argv)
3983cedbec3SEnji Cooper {
3993cedbec3SEnji Cooper 	/*
4003cedbec3SEnji Cooper 	 * We create a child process to hold the lock which we will
4013cedbec3SEnji Cooper 	 * test. Because our test relies on the child process being
4023cedbec3SEnji Cooper 	 * blocked on the parent's lock, we can't easily use a pipe to
4033cedbec3SEnji Cooper 	 * synchronize so we just sleep in the parent to given the
4043cedbec3SEnji Cooper 	 * child a chance to setup.
4053cedbec3SEnji Cooper 	 *
4063cedbec3SEnji Cooper 	 * To create the deadlock condition, we arrange for the parent
4073cedbec3SEnji Cooper 	 * to lock the first byte of the file and the child to lock
4083cedbec3SEnji Cooper 	 * the second byte.  After locking the second byte, the child
4093cedbec3SEnji Cooper 	 * will attempt to lock the first byte of the file, and
4103cedbec3SEnji Cooper 	 * block. The parent will then attempt to lock the second byte
4113cedbec3SEnji Cooper 	 * (owned by the child) which should cause deadlock.
4123cedbec3SEnji Cooper 	 */
4133cedbec3SEnji Cooper 	int pid;
4143cedbec3SEnji Cooper 	struct flock fl;
4153cedbec3SEnji Cooper 	int res;
4163cedbec3SEnji Cooper 
4173cedbec3SEnji Cooper 	/*
4183cedbec3SEnji Cooper 	 * Lock the first byte in the parent.
4193cedbec3SEnji Cooper 	 */
4203cedbec3SEnji Cooper 	fl.l_start = 0;
4213cedbec3SEnji Cooper 	fl.l_len = 1;
4223cedbec3SEnji Cooper 	fl.l_type = F_WRLCK;
4233cedbec3SEnji Cooper 	fl.l_whence = SEEK_SET;
4243cedbec3SEnji Cooper 	if (fcntl(fd, F_SETLK, &fl) < 0)
4253cedbec3SEnji Cooper 		err(1, "F_SETLK 1 (parent)");
4263cedbec3SEnji Cooper 
4273cedbec3SEnji Cooper 	pid = fork();
4283cedbec3SEnji Cooper 	if (pid < 0)
4293cedbec3SEnji Cooper 		err(1, "fork");
4303cedbec3SEnji Cooper 
4313cedbec3SEnji Cooper 	if (pid == 0) {
4323cedbec3SEnji Cooper 		/*
4333cedbec3SEnji Cooper 		 * Lock the second byte in the child and then block on
4343cedbec3SEnji Cooper 		 * the parent's lock.
4353cedbec3SEnji Cooper 		 */
4363cedbec3SEnji Cooper 		fl.l_start = 1;
4373cedbec3SEnji Cooper 		if (fcntl(fd, F_SETLK, &fl) < 0)
4383cedbec3SEnji Cooper 			err(1, "F_SETLK (child)");
4393cedbec3SEnji Cooper 		fl.l_start = 0;
4403cedbec3SEnji Cooper 		if (fcntl(fd, F_SETLKW, &fl) < 0)
4413cedbec3SEnji Cooper 			err(1, "F_SETLKW (child)");
4423cedbec3SEnji Cooper 		exit(0);
4433cedbec3SEnji Cooper 	}
4443cedbec3SEnji Cooper 
4453cedbec3SEnji Cooper 	/*
4463cedbec3SEnji Cooper 	 * Wait until the child has set its lock and then perform the
4473cedbec3SEnji Cooper 	 * test.
4483cedbec3SEnji Cooper 	 */
4493cedbec3SEnji Cooper 	sleep(1);
4503cedbec3SEnji Cooper 
4513cedbec3SEnji Cooper 	/*
4523cedbec3SEnji Cooper 	 * fcntl should immediately return -1 with errno set to
4533cedbec3SEnji Cooper 	 * EDEADLK. If the alarm fires, we failed to detect the
4543cedbec3SEnji Cooper 	 * deadlock.
4553cedbec3SEnji Cooper 	 */
4563cedbec3SEnji Cooper 	alarm(1);
4573cedbec3SEnji Cooper 	printf("5 - F_SETLKW simple deadlock: ");
4583cedbec3SEnji Cooper 
4593cedbec3SEnji Cooper 	fl.l_start = 1;
4603cedbec3SEnji Cooper 	res = fcntl(fd, F_SETLKW, &fl);
4613cedbec3SEnji Cooper 	kill(pid, SIGTERM);
4623cedbec3SEnji Cooper 	safe_waitpid(pid);
4633cedbec3SEnji Cooper 
4643cedbec3SEnji Cooper 	FAIL(res == 0);
4653cedbec3SEnji Cooper 	FAIL(errno != EDEADLK);
4663cedbec3SEnji Cooper 
4673cedbec3SEnji Cooper 	fl.l_start = 0;
4683cedbec3SEnji Cooper 	fl.l_len = 0;
4693cedbec3SEnji Cooper 	fl.l_type = F_UNLCK;
4703cedbec3SEnji Cooper 	if (fcntl(fd, F_SETLK, &fl) < 0)
4713cedbec3SEnji Cooper 		err(1, "F_UNLCK");
4723cedbec3SEnji Cooper 
4733cedbec3SEnji Cooper 	/*
4743cedbec3SEnji Cooper 	 * Cancel the alarm to avoid confusing later tests.
4753cedbec3SEnji Cooper 	 */
4763cedbec3SEnji Cooper 	alarm(0);
4773cedbec3SEnji Cooper 
4783cedbec3SEnji Cooper 	SUCCEED;
4793cedbec3SEnji Cooper }
4803cedbec3SEnji Cooper 
4813cedbec3SEnji Cooper /*
4823cedbec3SEnji Cooper  * Test 6 - F_SETLKW complex deadlock.
4833cedbec3SEnji Cooper  *
4843cedbec3SEnji Cooper  * This test involves three process, P, C1 and C2. We set things up so
4853cedbec3SEnji Cooper  * that P locks byte zero, C1 locks byte 1 and C2 locks byte 2. We
4863cedbec3SEnji Cooper  * also block C2 by attempting to lock byte zero. Lastly, P attempts
4873cedbec3SEnji Cooper  * to lock a range including byte 1 and 2. This represents a deadlock
4883cedbec3SEnji Cooper  * (due to C2's blocking attempt to lock byte zero).
4893cedbec3SEnji Cooper  */
4903cedbec3SEnji Cooper static int
test6(int fd,__unused int argc,const __unused char ** argv)4913cedbec3SEnji Cooper test6(int fd, __unused int argc, const __unused char **argv)
4923cedbec3SEnji Cooper {
4933cedbec3SEnji Cooper 	/*
4943cedbec3SEnji Cooper 	 * Because our test relies on the child process being blocked
4953cedbec3SEnji Cooper 	 * on the parent's lock, we can't easily use a pipe to
4963cedbec3SEnji Cooper 	 * synchronize so we just sleep in the parent to given the
4973cedbec3SEnji Cooper 	 * children a chance to setup.
4983cedbec3SEnji Cooper 	 */
4993cedbec3SEnji Cooper 	int pid1, pid2;
5003cedbec3SEnji Cooper 	struct flock fl;
5013cedbec3SEnji Cooper 	int res;
5023cedbec3SEnji Cooper 
5033cedbec3SEnji Cooper 	/*
5043cedbec3SEnji Cooper 	 * Lock the first byte in the parent.
5053cedbec3SEnji Cooper 	 */
5063cedbec3SEnji Cooper 	fl.l_start = 0;
5073cedbec3SEnji Cooper 	fl.l_len = 1;
5083cedbec3SEnji Cooper 	fl.l_type = F_WRLCK;
5093cedbec3SEnji Cooper 	fl.l_whence = SEEK_SET;
5103cedbec3SEnji Cooper 	if (fcntl(fd, F_SETLK, &fl) < 0)
5113cedbec3SEnji Cooper 		err(1, "F_SETLK 1 (parent)");
5123cedbec3SEnji Cooper 
5133cedbec3SEnji Cooper 	pid1 = fork();
5143cedbec3SEnji Cooper 	if (pid1 < 0)
5153cedbec3SEnji Cooper 		err(1, "fork");
5163cedbec3SEnji Cooper 
5173cedbec3SEnji Cooper 	if (pid1 == 0) {
5183cedbec3SEnji Cooper 		/*
5193cedbec3SEnji Cooper 		 * C1
5203cedbec3SEnji Cooper 		 * Lock the second byte in the child and then sleep
5213cedbec3SEnji Cooper 		 */
5223cedbec3SEnji Cooper 		fl.l_start = 1;
5233cedbec3SEnji Cooper 		if (fcntl(fd, F_SETLK, &fl) < 0)
5243cedbec3SEnji Cooper 			err(1, "F_SETLK (child1)");
5253cedbec3SEnji Cooper 		pause();
5263cedbec3SEnji Cooper 		exit(0);
5273cedbec3SEnji Cooper 	}
5283cedbec3SEnji Cooper 
5293cedbec3SEnji Cooper 	pid2 = fork();
5303cedbec3SEnji Cooper 	if (pid2 < 0)
5313cedbec3SEnji Cooper 		err(1, "fork");
5323cedbec3SEnji Cooper 
5333cedbec3SEnji Cooper 	if (pid2 == 0) {
5343cedbec3SEnji Cooper 		/*
5353cedbec3SEnji Cooper 		 * C2
5363cedbec3SEnji Cooper 		 * Lock the third byte in the child and then block on
5373cedbec3SEnji Cooper 		 * the parent's lock.
5383cedbec3SEnji Cooper 		 */
5393cedbec3SEnji Cooper 		fl.l_start = 2;
5403cedbec3SEnji Cooper 		if (fcntl(fd, F_SETLK, &fl) < 0)
5413cedbec3SEnji Cooper 			err(1, "F_SETLK (child2)");
5423cedbec3SEnji Cooper 		fl.l_start = 0;
5433cedbec3SEnji Cooper 		if (fcntl(fd, F_SETLKW, &fl) < 0)
5443cedbec3SEnji Cooper 			err(1, "F_SETLKW (child2)");
5453cedbec3SEnji Cooper 		exit(0);
5463cedbec3SEnji Cooper 	}
5473cedbec3SEnji Cooper 
5483cedbec3SEnji Cooper 	/*
5493cedbec3SEnji Cooper 	 * Wait until the children have set their locks and then
5503cedbec3SEnji Cooper 	 * perform the test.
5513cedbec3SEnji Cooper 	 */
5523cedbec3SEnji Cooper 	sleep(1);
5533cedbec3SEnji Cooper 
5543cedbec3SEnji Cooper 	/*
5553cedbec3SEnji Cooper 	 * fcntl should immediately return -1 with errno set to
5563cedbec3SEnji Cooper 	 * EDEADLK. If the alarm fires, we failed to detect the
5573cedbec3SEnji Cooper 	 * deadlock.
5583cedbec3SEnji Cooper 	 */
5593cedbec3SEnji Cooper 	alarm(1);
5603cedbec3SEnji Cooper 	printf("6 - F_SETLKW complex deadlock: ");
5613cedbec3SEnji Cooper 
5623cedbec3SEnji Cooper 	fl.l_start = 1;
5633cedbec3SEnji Cooper 	fl.l_len = 2;
5643cedbec3SEnji Cooper 	res = fcntl(fd, F_SETLKW, &fl);
5653cedbec3SEnji Cooper 	kill(pid1, SIGTERM);
5663cedbec3SEnji Cooper 	safe_waitpid(pid1);
5673cedbec3SEnji Cooper 	kill(pid2, SIGTERM);
5683cedbec3SEnji Cooper 	safe_waitpid(pid2);
5693cedbec3SEnji Cooper 
5703cedbec3SEnji Cooper 	fl.l_start = 0;
5713cedbec3SEnji Cooper 	fl.l_len = 0;
5723cedbec3SEnji Cooper 	fl.l_type = F_UNLCK;
5733cedbec3SEnji Cooper 	if (fcntl(fd, F_SETLK, &fl) < 0)
5743cedbec3SEnji Cooper 		err(1, "F_UNLCK");
5753cedbec3SEnji Cooper 
5763cedbec3SEnji Cooper 	FAIL(res == 0);
5773cedbec3SEnji Cooper 	FAIL(errno != EDEADLK);
5783cedbec3SEnji Cooper 
5793cedbec3SEnji Cooper 	/*
5803cedbec3SEnji Cooper 	 * Cancel the alarm to avoid confusing later tests.
5813cedbec3SEnji Cooper 	 */
5823cedbec3SEnji Cooper 	alarm(0);
5833cedbec3SEnji Cooper 
5843cedbec3SEnji Cooper 	SUCCEED;
5853cedbec3SEnji Cooper }
5863cedbec3SEnji Cooper 
5873cedbec3SEnji Cooper /*
5883cedbec3SEnji Cooper  * Test 7 - F_SETLK shared lock on exclusive locked region
5893cedbec3SEnji Cooper  *
5903cedbec3SEnji Cooper  * If a shared or exclusive lock cannot be set, fcntl returns
5913cedbec3SEnji Cooper  * immediately with EACCES or EAGAIN.
5923cedbec3SEnji Cooper  */
5933cedbec3SEnji Cooper static int
test7(int fd,__unused int argc,const __unused char ** argv)5943cedbec3SEnji Cooper test7(int fd, __unused int argc, const __unused char **argv)
5953cedbec3SEnji Cooper {
5963cedbec3SEnji Cooper 	/*
5973cedbec3SEnji Cooper 	 * We create a child process to hold the lock which we will
5983cedbec3SEnji Cooper 	 * test. We use a pipe to communicate with the child.
5993cedbec3SEnji Cooper 	 */
6003cedbec3SEnji Cooper 	int pid;
6013cedbec3SEnji Cooper 	int pfd[2];
6023cedbec3SEnji Cooper 	struct flock fl;
6033cedbec3SEnji Cooper 	char ch;
6043cedbec3SEnji Cooper 	int res;
6053cedbec3SEnji Cooper 
6063cedbec3SEnji Cooper 	if (pipe(pfd) < 0)
6073cedbec3SEnji Cooper 		err(1, "pipe");
6083cedbec3SEnji Cooper 
6093cedbec3SEnji Cooper 	fl.l_start = 0;
6103cedbec3SEnji Cooper 	fl.l_len = 0;
6113cedbec3SEnji Cooper 	fl.l_type = F_WRLCK;
6123cedbec3SEnji Cooper 	fl.l_whence = SEEK_SET;
6133cedbec3SEnji Cooper 
6143cedbec3SEnji Cooper 	pid = fork();
6153cedbec3SEnji Cooper 	if (pid < 0)
6163cedbec3SEnji Cooper 		err(1, "fork");
6173cedbec3SEnji Cooper 
6183cedbec3SEnji Cooper 	if (pid == 0) {
6193cedbec3SEnji Cooper 		/*
6203cedbec3SEnji Cooper 		 * We are the child. We set a write lock and then
6213cedbec3SEnji Cooper 		 * write one byte back to the parent to tell it. The
6223cedbec3SEnji Cooper 		 * parent will kill us when its done.
6233cedbec3SEnji Cooper 		 */
6243cedbec3SEnji Cooper 		if (fcntl(fd, F_SETLK, &fl) < 0)
6253cedbec3SEnji Cooper 			err(1, "F_SETLK (child)");
6263cedbec3SEnji Cooper 		if (write(pfd[1], "a", 1) < 0)
6273cedbec3SEnji Cooper 			err(1, "writing to pipe (child)");
6283cedbec3SEnji Cooper 		pause();
6293cedbec3SEnji Cooper 		exit(0);
6303cedbec3SEnji Cooper 	}
6313cedbec3SEnji Cooper 
6323cedbec3SEnji Cooper 	/*
6333cedbec3SEnji Cooper 	 * Wait until the child has set its lock and then perform the
6343cedbec3SEnji Cooper 	 * test.
6353cedbec3SEnji Cooper 	 */
6363cedbec3SEnji Cooper 	if (read(pfd[0], &ch, 1) != 1)
6373cedbec3SEnji Cooper 		err(1, "reading from pipe (child)");
6383cedbec3SEnji Cooper 
6393cedbec3SEnji Cooper 	/*
6403cedbec3SEnji Cooper 	 * fcntl should wait until the alarm and then return -1 with
6413cedbec3SEnji Cooper 	 * errno set to EINTR.
6423cedbec3SEnji Cooper 	 */
6433cedbec3SEnji Cooper 	printf("7 - F_SETLK shared lock on exclusive locked region: ");
6443cedbec3SEnji Cooper 
6453cedbec3SEnji Cooper 	fl.l_type = F_RDLCK;
6463cedbec3SEnji Cooper 	res = fcntl(fd, F_SETLK, &fl);
6473cedbec3SEnji Cooper 	kill(pid, SIGTERM);
6483cedbec3SEnji Cooper 	safe_waitpid(pid);
6493cedbec3SEnji Cooper 	close(pfd[0]);
6503cedbec3SEnji Cooper 	close(pfd[1]);
6513cedbec3SEnji Cooper 
6523cedbec3SEnji Cooper 	FAIL(res == 0);
6533cedbec3SEnji Cooper 	FAIL(errno != EACCES && errno != EAGAIN);
6543cedbec3SEnji Cooper 
6553cedbec3SEnji Cooper 	SUCCEED;
6563cedbec3SEnji Cooper }
6573cedbec3SEnji Cooper 
6583cedbec3SEnji Cooper /*
6593cedbec3SEnji Cooper  * Test 8 - F_SETLK shared lock on share locked region
6603cedbec3SEnji Cooper  *
6613cedbec3SEnji Cooper  * When a shared lock is set on a segment of a file, other processes
6623cedbec3SEnji Cooper  * shall be able to set shared locks on that segment or a portion of
6633cedbec3SEnji Cooper  * it.
6643cedbec3SEnji Cooper  */
6653cedbec3SEnji Cooper static int
test8(int fd,__unused int argc,const __unused char ** argv)6663cedbec3SEnji Cooper test8(int fd, __unused int argc, const __unused char **argv)
6673cedbec3SEnji Cooper {
6683cedbec3SEnji Cooper 	/*
6693cedbec3SEnji Cooper 	 * We create a child process to hold the lock which we will
6703cedbec3SEnji Cooper 	 * test. We use a pipe to communicate with the child.
6713cedbec3SEnji Cooper 	 */
6723cedbec3SEnji Cooper 	int pid;
6733cedbec3SEnji Cooper 	int pfd[2];
6743cedbec3SEnji Cooper 	struct flock fl;
6753cedbec3SEnji Cooper 	char ch;
6763cedbec3SEnji Cooper 	int res;
6773cedbec3SEnji Cooper 
6783cedbec3SEnji Cooper 	if (pipe(pfd) < 0)
6793cedbec3SEnji Cooper 		err(1, "pipe");
6803cedbec3SEnji Cooper 
6813cedbec3SEnji Cooper 	fl.l_start = 0;
6823cedbec3SEnji Cooper 	fl.l_len = 0;
6833cedbec3SEnji Cooper 	fl.l_type = F_RDLCK;
6843cedbec3SEnji Cooper 	fl.l_whence = SEEK_SET;
6853cedbec3SEnji Cooper 
6863cedbec3SEnji Cooper 	pid = fork();
6873cedbec3SEnji Cooper 	if (pid < 0)
6883cedbec3SEnji Cooper 		err(1, "fork");
6893cedbec3SEnji Cooper 
6903cedbec3SEnji Cooper 	if (pid == 0) {
6913cedbec3SEnji Cooper 		/*
6923cedbec3SEnji Cooper 		 * We are the child. We set a write lock and then
6933cedbec3SEnji Cooper 		 * write one byte back to the parent to tell it. The
6943cedbec3SEnji Cooper 		 * parent will kill us when its done.
6953cedbec3SEnji Cooper 		 */
6963cedbec3SEnji Cooper 		if (fcntl(fd, F_SETLK, &fl) < 0)
6973cedbec3SEnji Cooper 			err(1, "F_SETLK (child)");
6983cedbec3SEnji Cooper 		if (write(pfd[1], "a", 1) < 0)
6993cedbec3SEnji Cooper 			err(1, "writing to pipe (child)");
7003cedbec3SEnji Cooper 		pause();
7013cedbec3SEnji Cooper 		exit(0);
7023cedbec3SEnji Cooper 	}
7033cedbec3SEnji Cooper 
7043cedbec3SEnji Cooper 	/*
7053cedbec3SEnji Cooper 	 * Wait until the child has set its lock and then perform the
7063cedbec3SEnji Cooper 	 * test.
7073cedbec3SEnji Cooper 	 */
7083cedbec3SEnji Cooper 	if (read(pfd[0], &ch, 1) != 1)
7093cedbec3SEnji Cooper 		err(1, "reading from pipe (child)");
7103cedbec3SEnji Cooper 
7113cedbec3SEnji Cooper 	/*
7123cedbec3SEnji Cooper 	 * fcntl should wait until the alarm and then return -1 with
7133cedbec3SEnji Cooper 	 * errno set to EINTR.
7143cedbec3SEnji Cooper 	 */
7153cedbec3SEnji Cooper 	printf("8 - F_SETLK shared lock on share locked region: ");
7163cedbec3SEnji Cooper 
7173cedbec3SEnji Cooper 	fl.l_type = F_RDLCK;
7183cedbec3SEnji Cooper 	res = fcntl(fd, F_SETLK, &fl);
7193cedbec3SEnji Cooper 
7203cedbec3SEnji Cooper 	kill(pid, SIGTERM);
7213cedbec3SEnji Cooper 	safe_waitpid(pid);
7223cedbec3SEnji Cooper 	close(pfd[0]);
7233cedbec3SEnji Cooper 	close(pfd[1]);
7243cedbec3SEnji Cooper 
7253cedbec3SEnji Cooper 	fl.l_start = 0;
7263cedbec3SEnji Cooper 	fl.l_len = 0;
7273cedbec3SEnji Cooper 	fl.l_type = F_UNLCK;
7283cedbec3SEnji Cooper 	if (fcntl(fd, F_SETLK, &fl) < 0)
7293cedbec3SEnji Cooper 		err(1, "F_UNLCK");
7303cedbec3SEnji Cooper 
7313cedbec3SEnji Cooper 	FAIL(res != 0);
7323cedbec3SEnji Cooper 
7333cedbec3SEnji Cooper 	SUCCEED;
7343cedbec3SEnji Cooper }
7353cedbec3SEnji Cooper 
7363cedbec3SEnji Cooper /*
7373cedbec3SEnji Cooper  * Test 9 - F_SETLK exclusive lock on share locked region
7383cedbec3SEnji Cooper  *
7393cedbec3SEnji Cooper  * If a shared or exclusive lock cannot be set, fcntl returns
7403cedbec3SEnji Cooper  * immediately with EACCES or EAGAIN.
7413cedbec3SEnji Cooper  */
7423cedbec3SEnji Cooper static int
test9(int fd,__unused int argc,const __unused char ** argv)7433cedbec3SEnji Cooper test9(int fd, __unused int argc, const __unused char **argv)
7443cedbec3SEnji Cooper {
7453cedbec3SEnji Cooper 	/*
7463cedbec3SEnji Cooper 	 * We create a child process to hold the lock which we will
7473cedbec3SEnji Cooper 	 * test. We use a pipe to communicate with the child.
7483cedbec3SEnji Cooper 	 */
7493cedbec3SEnji Cooper 	int pid;
7503cedbec3SEnji Cooper 	int pfd[2];
7513cedbec3SEnji Cooper 	struct flock fl;
7523cedbec3SEnji Cooper 	char ch;
7533cedbec3SEnji Cooper 	int res;
7543cedbec3SEnji Cooper 
7553cedbec3SEnji Cooper 	if (pipe(pfd) < 0)
7563cedbec3SEnji Cooper 		err(1, "pipe");
7573cedbec3SEnji Cooper 
7583cedbec3SEnji Cooper 	fl.l_start = 0;
7593cedbec3SEnji Cooper 	fl.l_len = 0;
7603cedbec3SEnji Cooper 	fl.l_type = F_RDLCK;
7613cedbec3SEnji Cooper 	fl.l_whence = SEEK_SET;
7623cedbec3SEnji Cooper 
7633cedbec3SEnji Cooper 	pid = fork();
7643cedbec3SEnji Cooper 	if (pid < 0)
7653cedbec3SEnji Cooper 		err(1, "fork");
7663cedbec3SEnji Cooper 
7673cedbec3SEnji Cooper 	if (pid == 0) {
7683cedbec3SEnji Cooper 		/*
7693cedbec3SEnji Cooper 		 * We are the child. We set a write lock and then
7703cedbec3SEnji Cooper 		 * write one byte back to the parent to tell it. The
7713cedbec3SEnji Cooper 		 * parent will kill us when its done.
7723cedbec3SEnji Cooper 		 */
7733cedbec3SEnji Cooper 		if (fcntl(fd, F_SETLK, &fl) < 0)
7743cedbec3SEnji Cooper 			err(1, "F_SETLK (child)");
7753cedbec3SEnji Cooper 		if (write(pfd[1], "a", 1) < 0)
7763cedbec3SEnji Cooper 			err(1, "writing to pipe (child)");
7773cedbec3SEnji Cooper 		pause();
7783cedbec3SEnji Cooper 		exit(0);
7793cedbec3SEnji Cooper 	}
7803cedbec3SEnji Cooper 
7813cedbec3SEnji Cooper 	/*
7823cedbec3SEnji Cooper 	 * Wait until the child has set its lock and then perform the
7833cedbec3SEnji Cooper 	 * test.
7843cedbec3SEnji Cooper 	 */
7853cedbec3SEnji Cooper 	if (read(pfd[0], &ch, 1) != 1)
7863cedbec3SEnji Cooper 		err(1, "reading from pipe (child)");
7873cedbec3SEnji Cooper 
7883cedbec3SEnji Cooper 	/*
7893cedbec3SEnji Cooper 	 * fcntl should wait until the alarm and then return -1 with
7903cedbec3SEnji Cooper 	 * errno set to EINTR.
7913cedbec3SEnji Cooper 	 */
7923cedbec3SEnji Cooper 	printf("9 - F_SETLK exclusive lock on share locked region: ");
7933cedbec3SEnji Cooper 
7943cedbec3SEnji Cooper 	fl.l_type = F_WRLCK;
7953cedbec3SEnji Cooper 	res = fcntl(fd, F_SETLK, &fl);
7963cedbec3SEnji Cooper 	kill(pid, SIGTERM);
7973cedbec3SEnji Cooper 	safe_waitpid(pid);
7983cedbec3SEnji Cooper 	close(pfd[0]);
7993cedbec3SEnji Cooper 	close(pfd[1]);
8003cedbec3SEnji Cooper 
8013cedbec3SEnji Cooper 	FAIL(res == 0);
8023cedbec3SEnji Cooper 	FAIL(errno != EACCES && errno != EAGAIN);
8033cedbec3SEnji Cooper 
8043cedbec3SEnji Cooper 	SUCCEED;
8053cedbec3SEnji Cooper }
8063cedbec3SEnji Cooper 
8073cedbec3SEnji Cooper /*
8083cedbec3SEnji Cooper  * Test 10 - trying to set bogus pid or sysid values
8093cedbec3SEnji Cooper  *
8103cedbec3SEnji Cooper  * The l_pid and l_sysid fields are only used with F_GETLK to return
8113cedbec3SEnji Cooper  * the process ID of the process holding a blocking lock and the
8123cedbec3SEnji Cooper  * system ID of the system that owns that process
8133cedbec3SEnji Cooper  */
8143cedbec3SEnji Cooper static int
test10(int fd,__unused int argc,const __unused char ** argv)8153cedbec3SEnji Cooper test10(int fd, __unused int argc, const __unused char **argv)
8163cedbec3SEnji Cooper {
8173cedbec3SEnji Cooper 	/*
8183cedbec3SEnji Cooper 	 * We create a child process to hold the lock which we will
8193cedbec3SEnji Cooper 	 * test. We use a pipe to communicate with the child.
8203cedbec3SEnji Cooper 	 */
8213cedbec3SEnji Cooper 	int pid;
8223cedbec3SEnji Cooper 	int pfd[2];
8233cedbec3SEnji Cooper 	struct flock fl;
8243cedbec3SEnji Cooper 	char ch;
8253cedbec3SEnji Cooper 
8263cedbec3SEnji Cooper 	if (pipe(pfd) < 0)
8273cedbec3SEnji Cooper 		err(1, "pipe");
8283cedbec3SEnji Cooper 
8293cedbec3SEnji Cooper 	fl.l_start = 0;
8303cedbec3SEnji Cooper 	fl.l_len = 0;
8313cedbec3SEnji Cooper 	fl.l_type = F_WRLCK;
8323cedbec3SEnji Cooper 	fl.l_whence = SEEK_SET;
8333cedbec3SEnji Cooper 	fl.l_pid = 9999;
8343cedbec3SEnji Cooper #ifdef HAVE_SYSID
8353cedbec3SEnji Cooper 	fl.l_sysid = 9999;
8363cedbec3SEnji Cooper #endif
8373cedbec3SEnji Cooper 
8383cedbec3SEnji Cooper 	pid = fork();
8393cedbec3SEnji Cooper 	if (pid < 0)
8403cedbec3SEnji Cooper 		err(1, "fork");
8413cedbec3SEnji Cooper 
8423cedbec3SEnji Cooper 	if (pid == 0) {
8433cedbec3SEnji Cooper 		/*
8443cedbec3SEnji Cooper 		 * We are the child. We set a write lock and then
8453cedbec3SEnji Cooper 		 * write one byte back to the parent to tell it. The
8463cedbec3SEnji Cooper 		 * parent will kill us when its done.
8473cedbec3SEnji Cooper 		 */
8483cedbec3SEnji Cooper 		if (fcntl(fd, F_SETLK, &fl) < 0)
8493cedbec3SEnji Cooper 			err(1, "F_SETLK (child)");
8503cedbec3SEnji Cooper 		if (write(pfd[1], "a", 1) < 0)
8513cedbec3SEnji Cooper 			err(1, "writing to pipe (child)");
8523cedbec3SEnji Cooper 		pause();
8533cedbec3SEnji Cooper 		exit(0);
8543cedbec3SEnji Cooper 	}
8553cedbec3SEnji Cooper 
8563cedbec3SEnji Cooper 	/*
8573cedbec3SEnji Cooper 	 * Wait until the child has set its lock and then perform the
8583cedbec3SEnji Cooper 	 * test.
8593cedbec3SEnji Cooper 	 */
8603cedbec3SEnji Cooper 	if (read(pfd[0], &ch, 1) != 1)
8613cedbec3SEnji Cooper 		err(1, "reading from pipe (child)");
8623cedbec3SEnji Cooper 
8633cedbec3SEnji Cooper 	printf("10 - trying to set bogus pid or sysid values: ");
8643cedbec3SEnji Cooper 
8653cedbec3SEnji Cooper 	if (fcntl(fd, F_GETLK, &fl) < 0)
8663cedbec3SEnji Cooper 		err(1, "F_GETLK");
8673cedbec3SEnji Cooper 
8683cedbec3SEnji Cooper 	kill(pid, SIGTERM);
8693cedbec3SEnji Cooper 	safe_waitpid(pid);
8703cedbec3SEnji Cooper 	close(pfd[0]);
8713cedbec3SEnji Cooper 	close(pfd[1]);
8723cedbec3SEnji Cooper 
8733cedbec3SEnji Cooper 	FAIL(fl.l_pid != pid);
8743cedbec3SEnji Cooper #ifdef HAVE_SYSID
8753cedbec3SEnji Cooper 	FAIL(fl.l_sysid != 0);
8763cedbec3SEnji Cooper #endif
8773cedbec3SEnji Cooper 
8783cedbec3SEnji Cooper 	SUCCEED;
8793cedbec3SEnji Cooper }
8803cedbec3SEnji Cooper 
8813cedbec3SEnji Cooper /*
8823cedbec3SEnji Cooper  * Test 11 - remote locks
8833cedbec3SEnji Cooper  *
8843cedbec3SEnji Cooper  * XXX temporary interface which will be removed when the kernel lockd
8853cedbec3SEnji Cooper  * is added.
8863cedbec3SEnji Cooper  */
8873cedbec3SEnji Cooper static int
test11(int fd,__unused int argc,const __unused char ** argv)8883cedbec3SEnji Cooper test11(int fd, __unused int argc, const __unused char **argv)
8893cedbec3SEnji Cooper {
8903cedbec3SEnji Cooper #ifdef F_SETLK_REMOTE
8913cedbec3SEnji Cooper 	struct flock fl;
8923cedbec3SEnji Cooper 	int res;
8933cedbec3SEnji Cooper 
8943cedbec3SEnji Cooper 	if (geteuid() != 0)
8953cedbec3SEnji Cooper 		return 0;
8963cedbec3SEnji Cooper 
8973cedbec3SEnji Cooper 	fl.l_start = 0;
8983cedbec3SEnji Cooper 	fl.l_len = 0;
8993cedbec3SEnji Cooper 	fl.l_type = F_WRLCK;
9003cedbec3SEnji Cooper 	fl.l_whence = SEEK_SET;
9013cedbec3SEnji Cooper 	fl.l_pid = 9999;
9023cedbec3SEnji Cooper 	fl.l_sysid = 1001;
9033cedbec3SEnji Cooper 
9043cedbec3SEnji Cooper 	printf("11 - remote locks: ");
9053cedbec3SEnji Cooper 
9063cedbec3SEnji Cooper 	res = fcntl(fd, F_SETLK_REMOTE, &fl);
9073cedbec3SEnji Cooper 	FAIL(res != 0);
9083cedbec3SEnji Cooper 
9093cedbec3SEnji Cooper 	fl.l_sysid = 1002;
9103cedbec3SEnji Cooper 	res = fcntl(fd, F_SETLK_REMOTE, &fl);
9113cedbec3SEnji Cooper 	FAIL(res == 0);
9123cedbec3SEnji Cooper 	FAIL(errno != EACCES && errno != EAGAIN);
9133cedbec3SEnji Cooper 
9143cedbec3SEnji Cooper 	res = fcntl(fd, F_GETLK, &fl);
9153cedbec3SEnji Cooper 	FAIL(res != 0);
9163cedbec3SEnji Cooper 	FAIL(fl.l_pid != 9999);
9173cedbec3SEnji Cooper 	FAIL(fl.l_sysid != 1001);
9183cedbec3SEnji Cooper 
9193cedbec3SEnji Cooper 	fl.l_type = F_UNLCK;
9203cedbec3SEnji Cooper 	fl.l_sysid = 1001;
9213cedbec3SEnji Cooper 	fl.l_start = 0;
9223cedbec3SEnji Cooper 	fl.l_len = 0;
9233cedbec3SEnji Cooper 	res = fcntl(fd, F_SETLK_REMOTE, &fl);
9243cedbec3SEnji Cooper 	FAIL(res != 0);
9253cedbec3SEnji Cooper 
9263cedbec3SEnji Cooper 	fl.l_pid = 1234;
9273cedbec3SEnji Cooper 	fl.l_sysid = 1001;
9283cedbec3SEnji Cooper 	fl.l_start = 0;
9293cedbec3SEnji Cooper 	fl.l_len = 1;
9303cedbec3SEnji Cooper 	fl.l_whence = SEEK_SET;
9313cedbec3SEnji Cooper 	fl.l_type = F_RDLCK;
9323cedbec3SEnji Cooper 	res = fcntl(fd, F_SETLK_REMOTE, &fl);
9333cedbec3SEnji Cooper 	FAIL(res != 0);
9343cedbec3SEnji Cooper 
9353cedbec3SEnji Cooper 	fl.l_sysid = 1002;
9363cedbec3SEnji Cooper 	res = fcntl(fd, F_SETLK_REMOTE, &fl);
9373cedbec3SEnji Cooper 	FAIL(res != 0);
9383cedbec3SEnji Cooper 
9393cedbec3SEnji Cooper 	fl.l_type = F_UNLCKSYS;
9403cedbec3SEnji Cooper 	fl.l_sysid = 1001;
9413cedbec3SEnji Cooper 	res = fcntl(fd, F_SETLK_REMOTE, &fl);
9423cedbec3SEnji Cooper 	FAIL(res != 0);
9433cedbec3SEnji Cooper 
9443cedbec3SEnji Cooper 	fl.l_type = F_WRLCK;
9453cedbec3SEnji Cooper 	res = fcntl(fd, F_GETLK, &fl);
9463cedbec3SEnji Cooper 	FAIL(res != 0);
9473cedbec3SEnji Cooper 	FAIL(fl.l_pid != 1234);
9483cedbec3SEnji Cooper 	FAIL(fl.l_sysid != 1002);
9493cedbec3SEnji Cooper 
9503cedbec3SEnji Cooper 	fl.l_type = F_UNLCKSYS;
9513cedbec3SEnji Cooper 	fl.l_sysid = 1002;
9523cedbec3SEnji Cooper 	res = fcntl(fd, F_SETLK_REMOTE, &fl);
9533cedbec3SEnji Cooper 	FAIL(res != 0);
9543cedbec3SEnji Cooper 
9553cedbec3SEnji Cooper 	SUCCEED;
9563cedbec3SEnji Cooper #else
9573cedbec3SEnji Cooper 	return 0;
9583cedbec3SEnji Cooper #endif
9593cedbec3SEnji Cooper }
9603cedbec3SEnji Cooper 
9613cedbec3SEnji Cooper /*
9623cedbec3SEnji Cooper  * Test 12 - F_SETLKW on locked region which is then unlocked
9633cedbec3SEnji Cooper  *
9643cedbec3SEnji Cooper  * If a shared or exclusive lock is blocked by other locks, the
9653cedbec3SEnji Cooper  * process waits until the request can be satisfied.
9663cedbec3SEnji Cooper  */
9673cedbec3SEnji Cooper static int
test12(int fd,__unused int argc,const __unused char ** argv)9683cedbec3SEnji Cooper test12(int fd, __unused int argc, const __unused char **argv)
9693cedbec3SEnji Cooper {
9703cedbec3SEnji Cooper 	/*
9713cedbec3SEnji Cooper 	 * We create a child process to hold the lock which we will
9723cedbec3SEnji Cooper 	 * test. We use a pipe to communicate with the child.
9733cedbec3SEnji Cooper 	 */
9743cedbec3SEnji Cooper 	int pid;
9753cedbec3SEnji Cooper 	int pfd[2];
9763cedbec3SEnji Cooper 	struct flock fl;
9773cedbec3SEnji Cooper 	char ch;
9783cedbec3SEnji Cooper 	int res;
9793cedbec3SEnji Cooper 
9803cedbec3SEnji Cooper 	if (pipe(pfd) < 0)
9813cedbec3SEnji Cooper 		err(1, "pipe");
9823cedbec3SEnji Cooper 
9833cedbec3SEnji Cooper 	fl.l_start = 0;
9843cedbec3SEnji Cooper 	fl.l_len = 0;
9853cedbec3SEnji Cooper 	fl.l_type = F_WRLCK;
9863cedbec3SEnji Cooper 	fl.l_whence = SEEK_SET;
9873cedbec3SEnji Cooper 
9883cedbec3SEnji Cooper 	pid = fork();
9893cedbec3SEnji Cooper 	if (pid < 0)
9903cedbec3SEnji Cooper 		err(1, "fork");
9913cedbec3SEnji Cooper 
9923cedbec3SEnji Cooper 	if (pid == 0) {
9933cedbec3SEnji Cooper 		/*
9943cedbec3SEnji Cooper 		 * We are the child. We set a write lock and then
9953cedbec3SEnji Cooper 		 * write one byte back to the parent to tell it. The
9963cedbec3SEnji Cooper 		 * parent will kill us when its done.
9973cedbec3SEnji Cooper 		 */
9983cedbec3SEnji Cooper 		if (fcntl(fd, F_SETLK, &fl) < 0)
9993cedbec3SEnji Cooper 			err(1, "F_SETLK (child)");
10003cedbec3SEnji Cooper 		if (write(pfd[1], "a", 1) < 0)
10013cedbec3SEnji Cooper 			err(1, "writing to pipe (child)");
10023cedbec3SEnji Cooper 
10033cedbec3SEnji Cooper 		sleep(1);
10043cedbec3SEnji Cooper 		exit(0);
10053cedbec3SEnji Cooper 	}
10063cedbec3SEnji Cooper 
10073cedbec3SEnji Cooper 	/*
10083cedbec3SEnji Cooper 	 * Wait until the child has set its lock and then perform the
10093cedbec3SEnji Cooper 	 * test.
10103cedbec3SEnji Cooper 	 */
10113cedbec3SEnji Cooper 	if (read(pfd[0], &ch, 1) != 1)
10123cedbec3SEnji Cooper 		err(1, "reading from pipe (child)");
10133cedbec3SEnji Cooper 
10143cedbec3SEnji Cooper 	/*
10153cedbec3SEnji Cooper 	 * fcntl should wait until the alarm and then return -1 with
10163cedbec3SEnji Cooper 	 * errno set to EINTR.
10173cedbec3SEnji Cooper 	 */
10183cedbec3SEnji Cooper 	printf("12 - F_SETLKW on locked region which is then unlocked: ");
10193cedbec3SEnji Cooper 
10203cedbec3SEnji Cooper 	//alarm(1);
10213cedbec3SEnji Cooper 
10223cedbec3SEnji Cooper 	res = fcntl(fd, F_SETLKW, &fl);
10233cedbec3SEnji Cooper 	kill(pid, SIGTERM);
10243cedbec3SEnji Cooper 	safe_waitpid(pid);
10253cedbec3SEnji Cooper 	close(pfd[0]);
10263cedbec3SEnji Cooper 	close(pfd[1]);
10273cedbec3SEnji Cooper 	FAIL(res != 0);
10283cedbec3SEnji Cooper 
10293cedbec3SEnji Cooper 	fl.l_start = 0;
10303cedbec3SEnji Cooper 	fl.l_len = 0;
10313cedbec3SEnji Cooper 	fl.l_type = F_UNLCK;
10323cedbec3SEnji Cooper 	if (fcntl(fd, F_SETLK, &fl) < 0)
10333cedbec3SEnji Cooper 		err(1, "F_UNLCK");
10343cedbec3SEnji Cooper 
10353cedbec3SEnji Cooper 	SUCCEED;
10363cedbec3SEnji Cooper }
10373cedbec3SEnji Cooper 
10383cedbec3SEnji Cooper /*
10393cedbec3SEnji Cooper  * Test 13 - F_SETLKW on locked region, race with owner
10403cedbec3SEnji Cooper  *
10413cedbec3SEnji Cooper  * If a shared or exclusive lock is blocked by other locks, the
10423cedbec3SEnji Cooper  * process waits until the request can be satisfied.
10433cedbec3SEnji Cooper  */
10443cedbec3SEnji Cooper static int
test13(int fd,__unused int argc,const __unused char ** argv)10453cedbec3SEnji Cooper test13(int fd, __unused int argc, const __unused char **argv)
10463cedbec3SEnji Cooper {
10473cedbec3SEnji Cooper 	/*
10483cedbec3SEnji Cooper 	 * We create a child process to hold the lock which we will
10493cedbec3SEnji Cooper 	 * test. We use a pipe to communicate with the child.
10503cedbec3SEnji Cooper 	 */
10513cedbec3SEnji Cooper 	int i;
10523cedbec3SEnji Cooper 	int pid;
10533cedbec3SEnji Cooper 	int pfd[2];
10543cedbec3SEnji Cooper 	struct flock fl;
10553cedbec3SEnji Cooper 	char ch;
10563cedbec3SEnji Cooper 	int res;
10573cedbec3SEnji Cooper 	struct itimerval itv;
10583cedbec3SEnji Cooper 
10593cedbec3SEnji Cooper 	printf("13 - F_SETLKW on locked region, race with owner: ");
10603cedbec3SEnji Cooper 	fflush(stdout);
10613cedbec3SEnji Cooper 
10623cedbec3SEnji Cooper 	for (i = 0; i < 100; i++) {
10633cedbec3SEnji Cooper 		if (pipe(pfd) < 0)
10643cedbec3SEnji Cooper 			err(1, "pipe");
10653cedbec3SEnji Cooper 
10663cedbec3SEnji Cooper 		fl.l_start = 0;
10673cedbec3SEnji Cooper 		fl.l_len = 0;
10683cedbec3SEnji Cooper 		fl.l_type = F_WRLCK;
10693cedbec3SEnji Cooper 		fl.l_whence = SEEK_SET;
10703cedbec3SEnji Cooper 
10713cedbec3SEnji Cooper 		pid = fork();
10723cedbec3SEnji Cooper 		if (pid < 0)
10733cedbec3SEnji Cooper 			err(1, "fork");
10743cedbec3SEnji Cooper 
10753cedbec3SEnji Cooper 		if (pid == 0) {
10763cedbec3SEnji Cooper 			/*
10773cedbec3SEnji Cooper 			 * We are the child. We set a write lock and then
10783cedbec3SEnji Cooper 			 * write one byte back to the parent to tell it. The
10793cedbec3SEnji Cooper 			 * parent will kill us when its done.
10803cedbec3SEnji Cooper 			 */
10813cedbec3SEnji Cooper 			if (fcntl(fd, F_SETLK, &fl) < 0)
10823cedbec3SEnji Cooper 				err(1, "F_SETLK (child)");
10833cedbec3SEnji Cooper 			if (write(pfd[1], "a", 1) < 0)
10843cedbec3SEnji Cooper 				err(1, "writing to pipe (child)");
10853cedbec3SEnji Cooper 
10863cedbec3SEnji Cooper 			usleep(1);
10873cedbec3SEnji Cooper 			exit(0);
10883cedbec3SEnji Cooper 		}
10893cedbec3SEnji Cooper 
10903cedbec3SEnji Cooper 		/*
10913cedbec3SEnji Cooper 		 * Wait until the child has set its lock and then perform the
10923cedbec3SEnji Cooper 		 * test.
10933cedbec3SEnji Cooper 		 */
10943cedbec3SEnji Cooper 		while (read(pfd[0], &ch, 1) != 1) {
10953cedbec3SEnji Cooper 			if (errno == EINTR)
10963cedbec3SEnji Cooper 				continue;
10973cedbec3SEnji Cooper 			err(1, "reading from pipe (child)");
10983cedbec3SEnji Cooper 		}
10993cedbec3SEnji Cooper 
11003cedbec3SEnji Cooper 		/*
11013cedbec3SEnji Cooper 		 * fcntl should wait until the alarm and then return -1 with
11023cedbec3SEnji Cooper 		 * errno set to EINTR.
11033cedbec3SEnji Cooper 		 */
11043cedbec3SEnji Cooper 		itv.it_interval.tv_sec = 0;
11053cedbec3SEnji Cooper 		itv.it_interval.tv_usec = 0;
11063cedbec3SEnji Cooper 		itv.it_value.tv_sec = 0;
11073cedbec3SEnji Cooper 		itv.it_value.tv_usec = 2;
11083cedbec3SEnji Cooper 		setitimer(ITIMER_REAL, &itv, NULL);
11093cedbec3SEnji Cooper 
11103cedbec3SEnji Cooper 		res = fcntl(fd, F_SETLKW, &fl);
11113cedbec3SEnji Cooper 		kill(pid, SIGTERM);
11123cedbec3SEnji Cooper 		safe_waitpid(pid);
11133cedbec3SEnji Cooper 		close(pfd[0]);
11143cedbec3SEnji Cooper 		close(pfd[1]);
11153cedbec3SEnji Cooper 		FAIL(!(res == 0 || (res == -1 && errno == EINTR)));
11163cedbec3SEnji Cooper 
11173cedbec3SEnji Cooper 		fl.l_start = 0;
11183cedbec3SEnji Cooper 		fl.l_len = 0;
11193cedbec3SEnji Cooper 		fl.l_type = F_UNLCK;
11203cedbec3SEnji Cooper 		if (fcntl(fd, F_SETLK, &fl) < 0)
11213cedbec3SEnji Cooper 			err(1, "F_UNLCK");
11223cedbec3SEnji Cooper 	}
11233cedbec3SEnji Cooper 	SUCCEED;
11243cedbec3SEnji Cooper }
11253cedbec3SEnji Cooper 
11263cedbec3SEnji Cooper /*
11273cedbec3SEnji Cooper  * Test 14 - soak test
11283cedbec3SEnji Cooper  */
11293cedbec3SEnji Cooper static int
test14(int fd,int argc,const char ** argv)11303cedbec3SEnji Cooper test14(int fd, int argc, const char **argv)
11313cedbec3SEnji Cooper {
11323cedbec3SEnji Cooper #define CHILD_COUNT 20
11333cedbec3SEnji Cooper 	/*
11343cedbec3SEnji Cooper 	 * We create a set of child processes and let each one run
11353cedbec3SEnji Cooper 	 * through a random sequence of locks and unlocks.
11363cedbec3SEnji Cooper 	 */
11373cedbec3SEnji Cooper 	int i, j, id, id_base;
11383cedbec3SEnji Cooper 	int pids[CHILD_COUNT], pid;
11393cedbec3SEnji Cooper 	char buf[128];
11403cedbec3SEnji Cooper 	char tbuf[128];
11413cedbec3SEnji Cooper 	int map[128];
11423cedbec3SEnji Cooper 	char outbuf[512];
11433cedbec3SEnji Cooper 	struct flock fl;
11443cedbec3SEnji Cooper 	struct itimerval itv;
11453cedbec3SEnji Cooper 	int status;
11463cedbec3SEnji Cooper 
11473cedbec3SEnji Cooper 	id_base = 0;
11483cedbec3SEnji Cooper 	if (argc >= 2)
11493cedbec3SEnji Cooper 		id_base = strtol(argv[1], NULL, 0);
11503cedbec3SEnji Cooper 
11513cedbec3SEnji Cooper 	printf("14 - soak test: ");
11523cedbec3SEnji Cooper 	fflush(stdout);
11533cedbec3SEnji Cooper 
11543cedbec3SEnji Cooper 	for (i = 0; i < 128; i++)
11553cedbec3SEnji Cooper 		map[i] = F_UNLCK;
11563cedbec3SEnji Cooper 
11573cedbec3SEnji Cooper 	for (i = 0; i < CHILD_COUNT; i++) {
11583cedbec3SEnji Cooper 
11593cedbec3SEnji Cooper 		pid = fork();
11603cedbec3SEnji Cooper 		if (pid < 0)
11613cedbec3SEnji Cooper 			err(1, "fork");
11623cedbec3SEnji Cooper 		if (pid) {
11633cedbec3SEnji Cooper 			/*
11643cedbec3SEnji Cooper 			 * Parent - record the pid and continue.
11653cedbec3SEnji Cooper 			 */
11663cedbec3SEnji Cooper 			pids[i] = pid;
11673cedbec3SEnji Cooper 			continue;
11683cedbec3SEnji Cooper 		}
11693cedbec3SEnji Cooper 
11703cedbec3SEnji Cooper 		/*
11713cedbec3SEnji Cooper 		 * Child - do some work and exit.
11723cedbec3SEnji Cooper 		 */
11733cedbec3SEnji Cooper 		id = id_base + i;
11743cedbec3SEnji Cooper 		srandom(getpid());
11753cedbec3SEnji Cooper 
11763cedbec3SEnji Cooper 		for (j = 0; j < 50; j++) {
11773cedbec3SEnji Cooper 			int start, end, len;
11783cedbec3SEnji Cooper 			int set, wrlock;
11793cedbec3SEnji Cooper 
11803cedbec3SEnji Cooper 			do {
11813cedbec3SEnji Cooper 				start = random() & 127;
11823cedbec3SEnji Cooper 				end = random() & 127;
11833cedbec3SEnji Cooper 			} while (end <= start);
11843cedbec3SEnji Cooper 
11853cedbec3SEnji Cooper 			set = random() & 1;
11863cedbec3SEnji Cooper 			wrlock = random() & 1;
11873cedbec3SEnji Cooper 
11883cedbec3SEnji Cooper 			len = end - start;
11893cedbec3SEnji Cooper 			fl.l_start = start;
11903cedbec3SEnji Cooper 			fl.l_len = len;
11913cedbec3SEnji Cooper 			fl.l_whence = SEEK_SET;
11923cedbec3SEnji Cooper 			if (set)
11933cedbec3SEnji Cooper 				fl.l_type = wrlock ? F_WRLCK : F_RDLCK;
11943cedbec3SEnji Cooper 			else
11953cedbec3SEnji Cooper 				fl.l_type = F_UNLCK;
11963cedbec3SEnji Cooper 
11973cedbec3SEnji Cooper 			itv.it_interval.tv_sec = 0;
11983cedbec3SEnji Cooper 			itv.it_interval.tv_usec = 0;
11993cedbec3SEnji Cooper 			itv.it_value.tv_sec = 0;
12003cedbec3SEnji Cooper 			itv.it_value.tv_usec = 3000;
12013cedbec3SEnji Cooper 			setitimer(ITIMER_REAL, &itv, NULL);
12023cedbec3SEnji Cooper 
12033cedbec3SEnji Cooper 			if (fcntl(fd, F_SETLKW, &fl) < 0) {
12043cedbec3SEnji Cooper 				if (errno == EDEADLK || errno == EINTR) {
12053cedbec3SEnji Cooper 					if (verbose) {
12063cedbec3SEnji Cooper 						snprintf(outbuf, sizeof(outbuf),
12073cedbec3SEnji Cooper 						    "%d[%d]: %s [%d .. %d] %s\n",
12083cedbec3SEnji Cooper 						    id, j,
12093cedbec3SEnji Cooper 						    set ? (wrlock ? "write lock"
12103cedbec3SEnji Cooper 							: "read lock")
12113cedbec3SEnji Cooper 						    : "unlock", start, end,
12123cedbec3SEnji Cooper 						    errno == EDEADLK
12133cedbec3SEnji Cooper 						    ? "deadlock"
12143cedbec3SEnji Cooper 						    : "interrupted");
12153cedbec3SEnji Cooper 						write(1, outbuf,
12163cedbec3SEnji Cooper 						    strlen(outbuf));
12173cedbec3SEnji Cooper 					}
12183cedbec3SEnji Cooper 					continue;
12193cedbec3SEnji Cooper 				} else {
12203cedbec3SEnji Cooper 					perror("fcntl");
12213cedbec3SEnji Cooper 				}
12223cedbec3SEnji Cooper 			}
12233cedbec3SEnji Cooper 
12243cedbec3SEnji Cooper 			itv.it_interval.tv_sec = 0;
12253cedbec3SEnji Cooper 			itv.it_interval.tv_usec = 0;
12263cedbec3SEnji Cooper 			itv.it_value.tv_sec = 0;
12273cedbec3SEnji Cooper 			itv.it_value.tv_usec = 0;
12283cedbec3SEnji Cooper 			setitimer(ITIMER_REAL, &itv, NULL);
12293cedbec3SEnji Cooper 
12303cedbec3SEnji Cooper 			if (verbose) {
12313cedbec3SEnji Cooper 				snprintf(outbuf, sizeof(outbuf),
12323cedbec3SEnji Cooper 				    "%d[%d]: %s [%d .. %d] succeeded\n",
12333cedbec3SEnji Cooper 				    id, j,
12343cedbec3SEnji Cooper 				    set ? (wrlock ? "write lock" : "read lock")
12353cedbec3SEnji Cooper 				    : "unlock", start, end);
12363cedbec3SEnji Cooper 				write(1, outbuf, strlen(outbuf));
12373cedbec3SEnji Cooper 			}
12383cedbec3SEnji Cooper 
12393cedbec3SEnji Cooper 			if (set) {
12403cedbec3SEnji Cooper 				if (wrlock) {
12413cedbec3SEnji Cooper 					/*
12423cedbec3SEnji Cooper 					 * We got a write lock - write
12433cedbec3SEnji Cooper 					 * our ID to each byte that we
12443cedbec3SEnji Cooper 					 * managed to claim.
12453cedbec3SEnji Cooper 					 */
12463cedbec3SEnji Cooper 					for (i = start; i < end; i++)
12473cedbec3SEnji Cooper 						map[i] = F_WRLCK;
12483cedbec3SEnji Cooper 					memset(&buf[start], id, len);
12493cedbec3SEnji Cooper 					if (pwrite(fd, &buf[start], len,
12503cedbec3SEnji Cooper 						start) != len) {
12513cedbec3SEnji Cooper 						printf("%d: short write\n", id);
12523cedbec3SEnji Cooper 						exit(1);
12533cedbec3SEnji Cooper 					}
12543cedbec3SEnji Cooper 				} else {
12553cedbec3SEnji Cooper 					/*
12563cedbec3SEnji Cooper 					 * We got a read lock - read
12573cedbec3SEnji Cooper 					 * the bytes which we claimed
12583cedbec3SEnji Cooper 					 * so that we can check that
12593cedbec3SEnji Cooper 					 * they don't change
12603cedbec3SEnji Cooper 					 * unexpectedly.
12613cedbec3SEnji Cooper 					 */
12623cedbec3SEnji Cooper 					for (i = start; i < end; i++)
12633cedbec3SEnji Cooper 						map[i] = F_RDLCK;
12643cedbec3SEnji Cooper 					if (pread(fd, &buf[start], len,
12653cedbec3SEnji Cooper 						start) != len) {
12663cedbec3SEnji Cooper 						printf("%d: short read\n", id);
12673cedbec3SEnji Cooper 						exit(1);
12683cedbec3SEnji Cooper 					}
12693cedbec3SEnji Cooper 				}
12703cedbec3SEnji Cooper 			} else {
12713cedbec3SEnji Cooper 				for (i = start; i < end; i++)
12723cedbec3SEnji Cooper 					map[i] = F_UNLCK;
12733cedbec3SEnji Cooper 			}
12743cedbec3SEnji Cooper 
12753cedbec3SEnji Cooper 			usleep(1000);
12763cedbec3SEnji Cooper 
12773cedbec3SEnji Cooper 			/*
12783cedbec3SEnji Cooper 			 * Read back the whole region so that we can
12793cedbec3SEnji Cooper 			 * check that all the bytes we have some kind
12803cedbec3SEnji Cooper 			 * of claim to have the correct value.
12813cedbec3SEnji Cooper 			 */
12823cedbec3SEnji Cooper 			if (pread(fd, tbuf, sizeof(tbuf), 0) != sizeof(tbuf)) {
12833cedbec3SEnji Cooper 				printf("%d: short read\n", id);
12843cedbec3SEnji Cooper 				exit(1);
12853cedbec3SEnji Cooper 			}
12863cedbec3SEnji Cooper 
12873cedbec3SEnji Cooper 			for (i = 0; i < 128; i++) {
12883cedbec3SEnji Cooper 				if (map[i] != F_UNLCK && buf[i] != tbuf[i]) {
12893cedbec3SEnji Cooper 					snprintf(outbuf, sizeof(outbuf),
12903cedbec3SEnji Cooper 					    "%d: byte %d expected %d, "
12913cedbec3SEnji Cooper 					    "got %d\n", id, i, buf[i], tbuf[i]);
12923cedbec3SEnji Cooper 					write(1, outbuf, strlen(outbuf));
12933cedbec3SEnji Cooper 					exit(1);
12943cedbec3SEnji Cooper 				}
12953cedbec3SEnji Cooper 			}
12963cedbec3SEnji Cooper 		}
12973cedbec3SEnji Cooper 		if (verbose)
12983cedbec3SEnji Cooper 			printf("%d[%d]: done\n", id, j);
12993cedbec3SEnji Cooper 
13003cedbec3SEnji Cooper 		exit(0);
13013cedbec3SEnji Cooper 	}
13023cedbec3SEnji Cooper 
13033cedbec3SEnji Cooper 	status = 0;
13043cedbec3SEnji Cooper 	for (i = 0; i < CHILD_COUNT; i++) {
13053cedbec3SEnji Cooper 		status += safe_waitpid(pids[i]);
13063cedbec3SEnji Cooper 	}
13073cedbec3SEnji Cooper 	if (status)
13083cedbec3SEnji Cooper 		FAIL(status != 0);
13093cedbec3SEnji Cooper 
13103cedbec3SEnji Cooper 	SUCCEED;
13113cedbec3SEnji Cooper }
13123cedbec3SEnji Cooper 
13133cedbec3SEnji Cooper /*
13143cedbec3SEnji Cooper  * Test 15 - flock(2) semantcs
13153cedbec3SEnji Cooper  *
13163cedbec3SEnji Cooper  * When a lock holder has a shared lock and attempts to upgrade that
13173cedbec3SEnji Cooper  * shared lock to exclusive, it must drop the shared lock before
13183cedbec3SEnji Cooper  * blocking on the exclusive lock.
13193cedbec3SEnji Cooper  *
13203cedbec3SEnji Cooper  * To test this, we first arrange for two shared locks on the file,
13213cedbec3SEnji Cooper  * and then attempt to upgrade one of them to exclusive. This should
13223cedbec3SEnji Cooper  * drop one of the shared locks and block. We interrupt the blocking
13233cedbec3SEnji Cooper  * lock request and examine the lock state of the file after dropping
13243cedbec3SEnji Cooper  * the other shared lock - there should be no active locks at this
13253cedbec3SEnji Cooper  * point.
13263cedbec3SEnji Cooper  */
13273cedbec3SEnji Cooper static int
test15(int fd,__unused int argc,const __unused char ** argv)13283cedbec3SEnji Cooper test15(int fd, __unused int argc, const __unused char **argv)
13293cedbec3SEnji Cooper {
13303cedbec3SEnji Cooper #ifdef LOCK_EX
13313cedbec3SEnji Cooper 	/*
13323cedbec3SEnji Cooper 	 * We create a child process to hold the lock which we will
13333cedbec3SEnji Cooper 	 * test. We use a pipe to communicate with the child.
13343cedbec3SEnji Cooper 	 *
13353cedbec3SEnji Cooper 	 * Since we only have one file descriptors and lock ownership
13363cedbec3SEnji Cooper 	 * for flock(2) goes with the file descriptor, we use fcntl to
13373cedbec3SEnji Cooper 	 * set the child's shared lock.
13383cedbec3SEnji Cooper 	 */
13393cedbec3SEnji Cooper 	int pid;
13403cedbec3SEnji Cooper 	int pfd[2];
13413cedbec3SEnji Cooper 	struct flock fl;
13423cedbec3SEnji Cooper 	char ch;
13433cedbec3SEnji Cooper 	int res;
13443cedbec3SEnji Cooper 
13453cedbec3SEnji Cooper 	if (pipe(pfd) < 0)
13463cedbec3SEnji Cooper 		err(1, "pipe");
13473cedbec3SEnji Cooper 
13483cedbec3SEnji Cooper 	pid = fork();
13493cedbec3SEnji Cooper 	if (pid < 0)
13503cedbec3SEnji Cooper 		err(1, "fork");
13513cedbec3SEnji Cooper 
13523cedbec3SEnji Cooper 	if (pid == 0) {
13533cedbec3SEnji Cooper 		/*
13543cedbec3SEnji Cooper 		 * We are the child. We set a shared lock and then
13553cedbec3SEnji Cooper 		 * write one byte back to the parent to tell it. The
13563cedbec3SEnji Cooper 		 * parent will kill us when its done.
13573cedbec3SEnji Cooper 		 */
13583cedbec3SEnji Cooper 		fl.l_start = 0;
13593cedbec3SEnji Cooper 		fl.l_len = 0;
13603cedbec3SEnji Cooper 		fl.l_type = F_RDLCK;
13613cedbec3SEnji Cooper 		fl.l_whence = SEEK_SET;
13623cedbec3SEnji Cooper 		if (fcntl(fd, F_SETLK, &fl) < 0)
13633cedbec3SEnji Cooper 			err(1, "fcntl(F_SETLK) (child)");
13643cedbec3SEnji Cooper 		if (write(pfd[1], "a", 1) < 0)
13653cedbec3SEnji Cooper 			err(1, "writing to pipe (child)");
13663cedbec3SEnji Cooper 		pause();
13673cedbec3SEnji Cooper 		exit(0);
13683cedbec3SEnji Cooper 	}
13693cedbec3SEnji Cooper 
13703cedbec3SEnji Cooper 	/*
13713cedbec3SEnji Cooper 	 * Wait until the child has set its lock and then perform the
13723cedbec3SEnji Cooper 	 * test.
13733cedbec3SEnji Cooper 	 */
13743cedbec3SEnji Cooper 	if (read(pfd[0], &ch, 1) != 1)
13753cedbec3SEnji Cooper 		err(1, "reading from pipe (child)");
13763cedbec3SEnji Cooper 
13773cedbec3SEnji Cooper 	(void)dup(fd);
13783cedbec3SEnji Cooper 	if (flock(fd, LOCK_SH) < 0)
13793cedbec3SEnji Cooper 		err(1, "flock shared");
13803cedbec3SEnji Cooper 
13813cedbec3SEnji Cooper 	/*
13823cedbec3SEnji Cooper 	 * flock should wait until the alarm and then return -1 with
13833cedbec3SEnji Cooper 	 * errno set to EINTR.
13843cedbec3SEnji Cooper 	 */
13853cedbec3SEnji Cooper 	printf("15 - flock(2) semantics: ");
13863cedbec3SEnji Cooper 
13873cedbec3SEnji Cooper 	alarm(1);
13883cedbec3SEnji Cooper 	flock(fd, LOCK_EX);
13893cedbec3SEnji Cooper 
13903cedbec3SEnji Cooper 	/*
13913cedbec3SEnji Cooper 	 * Kill the child to force it to drop its locks.
13923cedbec3SEnji Cooper 	 */
13933cedbec3SEnji Cooper 	kill(pid, SIGTERM);
13943cedbec3SEnji Cooper 	safe_waitpid(pid);
13953cedbec3SEnji Cooper 
13963cedbec3SEnji Cooper 	fl.l_start = 0;
13973cedbec3SEnji Cooper 	fl.l_len = 0;
13983cedbec3SEnji Cooper 	fl.l_type = F_WRLCK;
13993cedbec3SEnji Cooper 	fl.l_whence = SEEK_SET;
14003cedbec3SEnji Cooper 	res = fcntl(fd, F_GETLK, &fl);
14013cedbec3SEnji Cooper 
14023cedbec3SEnji Cooper 	close(pfd[0]);
14033cedbec3SEnji Cooper 	close(pfd[1]);
14043cedbec3SEnji Cooper 	FAIL(res != 0);
14053cedbec3SEnji Cooper 	FAIL(fl.l_type != F_UNLCK);
14063cedbec3SEnji Cooper 
14073cedbec3SEnji Cooper 	SUCCEED;
14083cedbec3SEnji Cooper #else
14093cedbec3SEnji Cooper 	return 0;
14103cedbec3SEnji Cooper #endif
14113cedbec3SEnji Cooper }
14123cedbec3SEnji Cooper 
14133cedbec3SEnji Cooper struct test_ctx {
14143cedbec3SEnji Cooper 	struct flock tc_fl;
14153cedbec3SEnji Cooper 	int tc_fd;
14163cedbec3SEnji Cooper };
14173cedbec3SEnji Cooper 
14183cedbec3SEnji Cooper static void *
test16_func(void * tc_in)14193cedbec3SEnji Cooper test16_func(void *tc_in)
14203cedbec3SEnji Cooper {
14213cedbec3SEnji Cooper 	uintptr_t error;
14223cedbec3SEnji Cooper 	struct test_ctx *tc = tc_in;
14233cedbec3SEnji Cooper 
14243cedbec3SEnji Cooper 	error = fcntl(tc->tc_fd, F_SETLKW, &tc->tc_fl);
14253cedbec3SEnji Cooper 
14263cedbec3SEnji Cooper 	pthread_exit((void *)error);
14273cedbec3SEnji Cooper }
14283cedbec3SEnji Cooper 
14293cedbec3SEnji Cooper #define THREADS 10
14303cedbec3SEnji Cooper 
14313cedbec3SEnji Cooper /*
14323cedbec3SEnji Cooper  * Test 16 - F_SETLKW from two threads
14333cedbec3SEnji Cooper  *
14343cedbec3SEnji Cooper  * If two threads within a process are blocked on a lock and the lock
14353cedbec3SEnji Cooper  * is granted, make sure things are sane.
14363cedbec3SEnji Cooper  */
14373cedbec3SEnji Cooper static int
test16(int fd,__unused int argc,const __unused char ** argv)14383cedbec3SEnji Cooper test16(int fd, __unused int argc, const __unused char **argv)
14393cedbec3SEnji Cooper {
14403cedbec3SEnji Cooper 	/*
14413cedbec3SEnji Cooper 	 * We create a child process to hold the lock which we will
14423cedbec3SEnji Cooper 	 * test. We use a pipe to communicate with the child.
14433cedbec3SEnji Cooper 	 */
14443cedbec3SEnji Cooper 	int pid;
14453cedbec3SEnji Cooper 	int pfd[2];
14463cedbec3SEnji Cooper 	struct test_ctx tc = { .tc_fd = fd };
14473cedbec3SEnji Cooper 	char ch;
14483cedbec3SEnji Cooper 	int i;
14493cedbec3SEnji Cooper 	int error;
14503cedbec3SEnji Cooper 	pthread_t thr[THREADS];
14513cedbec3SEnji Cooper 
14523cedbec3SEnji Cooper 	if (pipe(pfd) < 0)
14533cedbec3SEnji Cooper 		err(1, "pipe");
14543cedbec3SEnji Cooper 
14553cedbec3SEnji Cooper 	tc.tc_fl.l_start = 0;
14563cedbec3SEnji Cooper 	tc.tc_fl.l_len = 0;
14573cedbec3SEnji Cooper 	tc.tc_fl.l_type = F_WRLCK;
14583cedbec3SEnji Cooper 	tc.tc_fl.l_whence = SEEK_SET;
14593cedbec3SEnji Cooper 
14603cedbec3SEnji Cooper 	pid = fork();
14613cedbec3SEnji Cooper 	if (pid < 0)
14623cedbec3SEnji Cooper 		err(1, "fork");
14633cedbec3SEnji Cooper 
14643cedbec3SEnji Cooper 	if (pid == 0) {
14653cedbec3SEnji Cooper 		/*
14663cedbec3SEnji Cooper 		 * We are the child. We set a write lock and then
14673cedbec3SEnji Cooper 		 * write one byte back to the parent to tell it. The
14683cedbec3SEnji Cooper 		 * parent will kill us when its done.
14693cedbec3SEnji Cooper 		 */
14703cedbec3SEnji Cooper 		if (fcntl(fd, F_SETLK, &tc.tc_fl) < 0)
14713cedbec3SEnji Cooper 			err(1, "F_SETLK (child)");
14723cedbec3SEnji Cooper 		if (write(pfd[1], "a", 1) < 0)
14733cedbec3SEnji Cooper 			err(1, "writing to pipe (child)");
14743cedbec3SEnji Cooper 		pause();
14753cedbec3SEnji Cooper 		exit(0);
14763cedbec3SEnji Cooper 	}
14773cedbec3SEnji Cooper 
14783cedbec3SEnji Cooper 	/*
14793cedbec3SEnji Cooper 	 * Wait until the child has set its lock and then perform the
14803cedbec3SEnji Cooper 	 * test.
14813cedbec3SEnji Cooper 	 */
14823cedbec3SEnji Cooper 	if (read(pfd[0], &ch, 1) != 1)
14833cedbec3SEnji Cooper 		err(1, "reading from pipe (child)");
14843cedbec3SEnji Cooper 
14853cedbec3SEnji Cooper 	/*
14863cedbec3SEnji Cooper 	 * fcntl should wait until the alarm and then return -1 with
14873cedbec3SEnji Cooper 	 * errno set to EINTR.
14883cedbec3SEnji Cooper 	 */
14893cedbec3SEnji Cooper 	printf("16 - F_SETLKW on locked region by two threads: ");
14903cedbec3SEnji Cooper 
14913cedbec3SEnji Cooper 	for (i = 0; i < THREADS; i++) {
14923cedbec3SEnji Cooper 		error = pthread_create(&thr[i], NULL, test16_func, &tc);
14933cedbec3SEnji Cooper 		if (error)
14943cedbec3SEnji Cooper 			err(1, "pthread_create");
14953cedbec3SEnji Cooper 	}
14963cedbec3SEnji Cooper 
14973cedbec3SEnji Cooper 	/*
14983cedbec3SEnji Cooper 	 * Sleep, then kill the child. This makes me a little sad, but it's
14993cedbec3SEnji Cooper 	 * tricky to tell whether the threads are all really blocked by this
15003cedbec3SEnji Cooper 	 * point.
15013cedbec3SEnji Cooper 	 */
15023cedbec3SEnji Cooper 	sleep(1);
15033cedbec3SEnji Cooper 	kill(pid, SIGTERM);
15043cedbec3SEnji Cooper 	safe_waitpid(pid);
15053cedbec3SEnji Cooper 	close(pfd[0]);
15063cedbec3SEnji Cooper 	close(pfd[1]);
15073cedbec3SEnji Cooper 
15083cedbec3SEnji Cooper 	for (i = 0; i < THREADS; i++) {
15093cedbec3SEnji Cooper 		void *res;
15103cedbec3SEnji Cooper 		error = pthread_join(thr[i], &res);
15113cedbec3SEnji Cooper 		if (error)
15123cedbec3SEnji Cooper 			err(1, "pthread_join");
15133cedbec3SEnji Cooper 		FAIL((uintptr_t)res != 0);
15143cedbec3SEnji Cooper 	}
15153cedbec3SEnji Cooper 
15163cedbec3SEnji Cooper 	SUCCEED;
15173cedbec3SEnji Cooper }
15183cedbec3SEnji Cooper 
15193cedbec3SEnji Cooper struct test {
15203cedbec3SEnji Cooper 	int (*testfn)(int, int, const char **);	/* function to perform the test */
15213cedbec3SEnji Cooper 	int num;		/* test number */
15223cedbec3SEnji Cooper 	int intr;		/* non-zero if the test interrupts a lock */
15233cedbec3SEnji Cooper };
15243cedbec3SEnji Cooper 
15253cedbec3SEnji Cooper static struct test tests[] = {
15263cedbec3SEnji Cooper 	{	test1,		1,	0	},
15273cedbec3SEnji Cooper 	{	test2,		2,	0	},
15283cedbec3SEnji Cooper 	{	test3,		3,	1	},
15293cedbec3SEnji Cooper 	{	test4,		4,	0	},
15303cedbec3SEnji Cooper 	{	test5,		5,	1	},
15313cedbec3SEnji Cooper 	{	test6,		6,	1	},
15323cedbec3SEnji Cooper 	{	test7,		7,	0	},
15333cedbec3SEnji Cooper 	{	test8,		8,	0	},
15343cedbec3SEnji Cooper 	{	test9,		9,	0	},
15353cedbec3SEnji Cooper 	{	test10,		10,	0	},
15363cedbec3SEnji Cooper 	{	test11,		11,	1	},
15373cedbec3SEnji Cooper 	{	test12,		12,	0	},
15383cedbec3SEnji Cooper 	{	test13,		13,	1	},
15393cedbec3SEnji Cooper 	{	test14,		14,	0	},
15403cedbec3SEnji Cooper 	{	test15,		15,	1	},
15413cedbec3SEnji Cooper 	{	test16,		16,	1	},
15423cedbec3SEnji Cooper };
15433cedbec3SEnji Cooper 
15443cedbec3SEnji Cooper int
main(int argc,const char * argv[])15453cedbec3SEnji Cooper main(int argc, const char *argv[])
15463cedbec3SEnji Cooper {
15473cedbec3SEnji Cooper 	int testnum;
15483cedbec3SEnji Cooper 	int fd;
15493cedbec3SEnji Cooper 	int nointr;
15503cedbec3SEnji Cooper 	unsigned i;
15513cedbec3SEnji Cooper 	struct sigaction sa;
15523cedbec3SEnji Cooper 	int test_argc;
15533cedbec3SEnji Cooper 	const char **test_argv;
15543cedbec3SEnji Cooper 
15553cedbec3SEnji Cooper 	if (argc < 2) {
15563cedbec3SEnji Cooper 		errx(1, "usage: flock <directory> [test number] ...");
15573cedbec3SEnji Cooper 	}
15583cedbec3SEnji Cooper 
15593cedbec3SEnji Cooper 	fd = make_file(argv[1], 1024);
15603cedbec3SEnji Cooper 	if (argc >= 3) {
15613cedbec3SEnji Cooper 		testnum = strtol(argv[2], NULL, 0);
15623cedbec3SEnji Cooper 		test_argc = argc - 2;
15633cedbec3SEnji Cooper 		test_argv = argv + 2;
15643cedbec3SEnji Cooper 	} else {
15653cedbec3SEnji Cooper 		testnum = 0;
15663cedbec3SEnji Cooper 		test_argc = 0;
1567*abea2d5aSEnji Cooper 		test_argv = NULL;
15683cedbec3SEnji Cooper 	}
15693cedbec3SEnji Cooper 
15703cedbec3SEnji Cooper 	sa.sa_handler = ignore_alarm;
15713cedbec3SEnji Cooper 	sigemptyset(&sa.sa_mask);
15723cedbec3SEnji Cooper 	sa.sa_flags = 0;
15733cedbec3SEnji Cooper 	sigaction(SIGALRM, &sa, 0);
15743cedbec3SEnji Cooper 
15753cedbec3SEnji Cooper 	nointr = 0;
15763cedbec3SEnji Cooper #if defined(__FreeBSD__) && __FreeBSD_version < 800040
15773cedbec3SEnji Cooper 	{
15783cedbec3SEnji Cooper 		/*
15793cedbec3SEnji Cooper 		 * FreeBSD with userland NLM can't interrupt a blocked
15803cedbec3SEnji Cooper 		 * lock request on an NFS mounted filesystem.
15813cedbec3SEnji Cooper 		 */
15823cedbec3SEnji Cooper 		struct statfs st;
15833cedbec3SEnji Cooper 		fstatfs(fd, &st);
15843cedbec3SEnji Cooper 		nointr = !strcmp(st.f_fstypename, "nfs");
15853cedbec3SEnji Cooper 	}
15863cedbec3SEnji Cooper #endif
15873cedbec3SEnji Cooper 
15883cedbec3SEnji Cooper 	for (i = 0; i < nitems(tests); i++) {
15893cedbec3SEnji Cooper 		if (tests[i].intr && nointr)
15903cedbec3SEnji Cooper 			continue;
15913cedbec3SEnji Cooper 		if (!testnum || tests[i].num == testnum)
15923cedbec3SEnji Cooper 			tests[i].testfn(fd, test_argc, test_argv);
15933cedbec3SEnji Cooper 	}
15943cedbec3SEnji Cooper 
15953cedbec3SEnji Cooper 	return 0;
15963cedbec3SEnji Cooper }
1597