1177636Sdfr/*-
2177636Sdfr * Copyright (c) 2008 Isilon Inc http://www.isilon.com/
3177636Sdfr * Authors: Doug Rabson <dfr@rabson.org>
4177636Sdfr * Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org>
5177636Sdfr *
6177636Sdfr * Redistribution and use in source and binary forms, with or without
7177636Sdfr * modification, are permitted provided that the following conditions
8177636Sdfr * are met:
9177636Sdfr * 1. Redistributions of source code must retain the above copyright
10177636Sdfr *    notice, this list of conditions and the following disclaimer.
11177636Sdfr * 2. Redistributions in binary form must reproduce the above copyright
12177636Sdfr *    notice, this list of conditions and the following disclaimer in the
13177636Sdfr *    documentation and/or other materials provided with the distribution.
14177636Sdfr *
15177636Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16177636Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17177636Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18177636Sdfr * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19177636Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20177636Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21177636Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22177636Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23177636Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24177636Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25177636Sdfr * SUCH DAMAGE.
26177636Sdfr *
27177636Sdfr * $FreeBSD$
28177636Sdfr */
29177636Sdfr
30277527Sngie#include <sys/param.h>
31268385Skib#include <sys/file.h>
32177636Sdfr#include <sys/time.h>
33177636Sdfr#ifdef __FreeBSD__
34177636Sdfr#include <sys/mount.h>
35177636Sdfr#endif
36180025Sdfr#include <sys/stat.h>
37177636Sdfr#include <sys/wait.h>
38177636Sdfr
39177636Sdfr#include <err.h>
40177636Sdfr#include <errno.h>
41177636Sdfr#include <fcntl.h>
42192949Szml#include <pthread.h>
43177636Sdfr#include <signal.h>
44268385Skib#include <stdint.h>
45177636Sdfr#include <stdio.h>
46177636Sdfr#include <stdlib.h>
47177636Sdfr#include <string.h>
48177636Sdfr#include <unistd.h>
49177636Sdfr
50177636Sdfr#ifdef __FreeBSD__
51177638Sdfr#if __FreeBSD_version >= 800028
52177636Sdfr#define HAVE_SYSID
53177636Sdfr#endif
54177636Sdfr#include <sys/cdefs.h>
55177636Sdfr#else
56277527Sngie#ifndef nitems
57277527Sngie#define	nitems(x)	(sizeof((x)) / sizeof((x)[0]))
58277527Sngie#endif
59277527Sngie
60177636Sdfr#ifndef __unused
61268385Skib#ifdef __GNUC__
62268385Skib#define	__unused	__attribute__((__unused__))
63268385Skib#else
64177636Sdfr#define __unused
65177636Sdfr#endif
66177636Sdfr#endif
67268385Skib#endif
68177636Sdfr
69277527Sngiestatic int verbose = 0;
70177636Sdfr
71177636Sdfrstatic int
72180025Sdfrmake_file(const char *pathname, off_t sz)
73177636Sdfr{
74180025Sdfr	struct stat st;
75177636Sdfr	const char *template = "/flocktempXXXXXX";
76177636Sdfr	size_t len;
77177636Sdfr	char *filename;
78177636Sdfr	int fd;
79177636Sdfr
80180025Sdfr	if (stat(pathname, &st) == 0) {
81180025Sdfr		if (S_ISREG(st.st_mode)) {
82180025Sdfr			fd = open(pathname, O_RDWR);
83180025Sdfr			if (fd < 0)
84180025Sdfr				err(1, "open(%s)", pathname);
85180025Sdfr			if (ftruncate(fd, sz) < 0)
86180025Sdfr				err(1, "ftruncate");
87180025Sdfr			return (fd);
88180025Sdfr		}
89180025Sdfr	}
90180025Sdfr
91180025Sdfr	len = strlen(pathname) + strlen(template) + 1;
92177636Sdfr	filename = malloc(len);
93180025Sdfr	strcpy(filename, pathname);
94177636Sdfr	strcat(filename, template);
95177636Sdfr	fd = mkstemp(filename);
96177636Sdfr	if (fd < 0)
97177636Sdfr		err(1, "mkstemp");
98177636Sdfr	if (ftruncate(fd, sz) < 0)
99177636Sdfr		err(1, "ftruncate");
100177636Sdfr	if (unlink(filename) < 0)
101177636Sdfr		err(1, "unlink");
102177636Sdfr	free(filename);
103177636Sdfr
104177636Sdfr	return (fd);
105177636Sdfr}
106177636Sdfr
107177636Sdfrstatic void
108177636Sdfrignore_alarm(int __unused sig)
109177636Sdfr{
110177636Sdfr}
111177636Sdfr
112180025Sdfrstatic int
113180025Sdfrsafe_waitpid(pid_t pid)
114180025Sdfr{
115180025Sdfr	int save_errno;
116180025Sdfr	int status;
117180025Sdfr
118180025Sdfr	save_errno = errno;
119180025Sdfr	errno = 0;
120180025Sdfr	while (waitpid(pid, &status, 0) != pid) {
121180025Sdfr		if (errno == EINTR)
122180025Sdfr			continue;
123180025Sdfr		err(1, "waitpid");
124180025Sdfr	}
125180025Sdfr	errno = save_errno;
126180025Sdfr
127180025Sdfr	return (status);
128180025Sdfr}
129180025Sdfr
130177636Sdfr#define FAIL(test)					\
131177636Sdfr	do {						\
132177636Sdfr		if (test) {				\
133177636Sdfr			printf("FAIL (%s)\n", #test);	\
134177636Sdfr			return -1;			\
135177636Sdfr		}					\
136177636Sdfr	} while (0)
137177636Sdfr
138177636Sdfr#define SUCCEED \
139177636Sdfr	do { printf("SUCCEED\n"); return 0; } while (0)
140177636Sdfr
141177636Sdfr/*
142177636Sdfr * Test 1 - F_GETLK on unlocked region
143177636Sdfr *
144177636Sdfr * If no lock is found that would prevent this lock from being
145177636Sdfr * created, the structure is left unchanged by this function call
146177636Sdfr * except for the lock type which is set to F_UNLCK.
147177636Sdfr */
148177636Sdfrstatic int
149180025Sdfrtest1(int fd, __unused int argc, const __unused char **argv)
150177636Sdfr{
151177636Sdfr	struct flock fl1, fl2;
152177636Sdfr
153177636Sdfr	memset(&fl1, 1, sizeof(fl1));
154177636Sdfr	fl1.l_type = F_WRLCK;
155177636Sdfr	fl1.l_whence = SEEK_SET;
156177636Sdfr	fl2 = fl1;
157177636Sdfr
158177636Sdfr	if (fcntl(fd, F_GETLK, &fl1) < 0)
159177636Sdfr		err(1, "F_GETLK");
160177636Sdfr
161177636Sdfr	printf("1 - F_GETLK on unlocked region: ");
162177636Sdfr	FAIL(fl1.l_start != fl2.l_start);
163177636Sdfr	FAIL(fl1.l_len != fl2.l_len);
164177636Sdfr	FAIL(fl1.l_pid != fl2.l_pid);
165177636Sdfr	FAIL(fl1.l_type != F_UNLCK);
166177636Sdfr	FAIL(fl1.l_whence != fl2.l_whence);
167177636Sdfr#ifdef HAVE_SYSID
168177636Sdfr	FAIL(fl1.l_sysid != fl2.l_sysid);
169177636Sdfr#endif
170177636Sdfr
171177636Sdfr	SUCCEED;
172177636Sdfr}
173177636Sdfr
174177636Sdfr/*
175177636Sdfr * Test 2 - F_SETLK on locked region
176177636Sdfr *
177177636Sdfr * If a shared or exclusive lock cannot be set, fcntl returns
178177636Sdfr * immediately with EACCES or EAGAIN.
179177636Sdfr */
180177636Sdfrstatic int
181180025Sdfrtest2(int fd, __unused int argc, const __unused char **argv)
182177636Sdfr{
183177636Sdfr	/*
184177636Sdfr	 * We create a child process to hold the lock which we will
185177636Sdfr	 * test. We use a pipe to communicate with the child.
186177636Sdfr	 */
187177636Sdfr	int pid;
188177636Sdfr	int pfd[2];
189177636Sdfr	struct flock fl;
190177636Sdfr	char ch;
191177636Sdfr	int res;
192177636Sdfr
193177636Sdfr	if (pipe(pfd) < 0)
194177636Sdfr		err(1, "pipe");
195177636Sdfr
196177636Sdfr	fl.l_start = 0;
197177636Sdfr	fl.l_len = 0;
198177636Sdfr	fl.l_type = F_WRLCK;
199177636Sdfr	fl.l_whence = SEEK_SET;
200177636Sdfr
201177636Sdfr	pid = fork();
202177636Sdfr	if (pid < 0)
203177636Sdfr		err(1, "fork");
204177636Sdfr
205177636Sdfr	if (pid == 0) {
206177636Sdfr		/*
207177636Sdfr		 * We are the child. We set a write lock and then
208177636Sdfr		 * write one byte back to the parent to tell it. The
209177636Sdfr		 * parent will kill us when its done.
210177636Sdfr		 */
211177636Sdfr		if (fcntl(fd, F_SETLK, &fl) < 0)
212177636Sdfr			err(1, "F_SETLK (child)");
213177636Sdfr		if (write(pfd[1], "a", 1) < 0)
214177636Sdfr			err(1, "writing to pipe (child)");
215177636Sdfr		pause();
216177636Sdfr		exit(0);
217177636Sdfr	}
218177636Sdfr
219177636Sdfr	/*
220177636Sdfr	 * Wait until the child has set its lock and then perform the
221177636Sdfr	 * test.
222177636Sdfr	 */
223177636Sdfr	if (read(pfd[0], &ch, 1) != 1)
224177636Sdfr		err(1, "reading from pipe (child)");
225177636Sdfr
226177636Sdfr	/*
227177636Sdfr	 * fcntl should return -1 with errno set to either EACCES or
228177636Sdfr	 * EAGAIN.
229177636Sdfr	 */
230177636Sdfr	printf("2 - F_SETLK on locked region: ");
231177636Sdfr	res = fcntl(fd, F_SETLK, &fl);
232177636Sdfr	kill(pid, SIGTERM);
233177636Sdfr	safe_waitpid(pid);
234177636Sdfr	close(pfd[0]);
235177636Sdfr	close(pfd[1]);
236177636Sdfr	FAIL(res == 0);
237177636Sdfr	FAIL(errno != EACCES && errno != EAGAIN);
238177636Sdfr
239177636Sdfr	SUCCEED;
240177636Sdfr}
241177636Sdfr
242177636Sdfr/*
243177636Sdfr * Test 3 - F_SETLKW on locked region
244177636Sdfr *
245177636Sdfr * If a shared or exclusive lock is blocked by other locks, the
246177636Sdfr * process waits until the request can be satisfied.
247177636Sdfr *
248177636Sdfr * XXX this test hangs on FreeBSD NFS filesystems due to limitations
249177636Sdfr * in FreeBSD's client (and server) lockd implementation.
250177636Sdfr */
251177636Sdfrstatic int
252180025Sdfrtest3(int fd, __unused int argc, const __unused char **argv)
253177636Sdfr{
254177636Sdfr	/*
255177636Sdfr	 * We create a child process to hold the lock which we will
256177636Sdfr	 * test. We use a pipe to communicate with the child.
257177636Sdfr	 */
258177636Sdfr	int pid;
259177636Sdfr	int pfd[2];
260177636Sdfr	struct flock fl;
261177636Sdfr	char ch;
262177636Sdfr	int res;
263177636Sdfr
264177636Sdfr	if (pipe(pfd) < 0)
265177636Sdfr		err(1, "pipe");
266177636Sdfr
267177636Sdfr	fl.l_start = 0;
268177636Sdfr	fl.l_len = 0;
269177636Sdfr	fl.l_type = F_WRLCK;
270177636Sdfr	fl.l_whence = SEEK_SET;
271177636Sdfr
272177636Sdfr	pid = fork();
273177636Sdfr	if (pid < 0)
274177636Sdfr		err(1, "fork");
275177636Sdfr
276177636Sdfr	if (pid == 0) {
277177636Sdfr		/*
278177636Sdfr		 * We are the child. We set a write lock and then
279177636Sdfr		 * write one byte back to the parent to tell it. The
280177636Sdfr		 * parent will kill us when its done.
281177636Sdfr		 */
282177636Sdfr		if (fcntl(fd, F_SETLK, &fl) < 0)
283177636Sdfr			err(1, "F_SETLK (child)");
284177636Sdfr		if (write(pfd[1], "a", 1) < 0)
285177636Sdfr			err(1, "writing to pipe (child)");
286177636Sdfr		pause();
287177636Sdfr		exit(0);
288177636Sdfr	}
289177636Sdfr
290177636Sdfr	/*
291177636Sdfr	 * Wait until the child has set its lock and then perform the
292177636Sdfr	 * test.
293177636Sdfr	 */
294177636Sdfr	if (read(pfd[0], &ch, 1) != 1)
295177636Sdfr		err(1, "reading from pipe (child)");
296177636Sdfr
297177636Sdfr	/*
298177636Sdfr	 * fcntl should wait until the alarm and then return -1 with
299177636Sdfr	 * errno set to EINTR.
300177636Sdfr	 */
301177636Sdfr	printf("3 - F_SETLKW on locked region: ");
302177636Sdfr
303177636Sdfr	alarm(1);
304177636Sdfr
305177636Sdfr	res = fcntl(fd, F_SETLKW, &fl);
306177636Sdfr	kill(pid, SIGTERM);
307177636Sdfr	safe_waitpid(pid);
308177636Sdfr	close(pfd[0]);
309177636Sdfr	close(pfd[1]);
310177636Sdfr	FAIL(res == 0);
311177636Sdfr	FAIL(errno != EINTR);
312177636Sdfr
313177636Sdfr	SUCCEED;
314177636Sdfr}
315177636Sdfr
316177636Sdfr/*
317177636Sdfr * Test 4 - F_GETLK on locked region
318177636Sdfr *
319177636Sdfr * Get the first lock that blocks the lock.
320177636Sdfr */
321177636Sdfrstatic int
322180025Sdfrtest4(int fd, __unused int argc, const __unused char **argv)
323177636Sdfr{
324177636Sdfr	/*
325177636Sdfr	 * We create a child process to hold the lock which we will
326177636Sdfr	 * test. We use a pipe to communicate with the child.
327177636Sdfr	 */
328177636Sdfr	int pid;
329177636Sdfr	int pfd[2];
330177636Sdfr	struct flock fl;
331177636Sdfr	char ch;
332177636Sdfr
333177636Sdfr	if (pipe(pfd) < 0)
334177636Sdfr		err(1, "pipe");
335177636Sdfr
336177636Sdfr	fl.l_start = 0;
337177636Sdfr	fl.l_len = 99;
338177636Sdfr	fl.l_type = F_WRLCK;
339177636Sdfr	fl.l_whence = SEEK_SET;
340177636Sdfr
341177636Sdfr	pid = fork();
342177636Sdfr	if (pid < 0)
343177636Sdfr		err(1, "fork");
344177636Sdfr
345177636Sdfr	if (pid == 0) {
346177636Sdfr		/*
347177636Sdfr		 * We are the child. We set a write lock and then
348177636Sdfr		 * write one byte back to the parent to tell it. The
349177636Sdfr		 * parent will kill us when its done.
350177636Sdfr		 */
351177636Sdfr		if (fcntl(fd, F_SETLK, &fl) < 0)
352177636Sdfr			err(1, "F_SETLK (child)");
353177636Sdfr		if (write(pfd[1], "a", 1) < 0)
354177636Sdfr			err(1, "writing to pipe (child)");
355177636Sdfr		pause();
356177636Sdfr		exit(0);
357177636Sdfr	}
358177636Sdfr
359177636Sdfr	/*
360177636Sdfr	 * Wait until the child has set its lock and then perform the
361177636Sdfr	 * test.
362177636Sdfr	 */
363177636Sdfr	if (read(pfd[0], &ch, 1) != 1)
364177636Sdfr		err(1, "reading from pipe (child)");
365177636Sdfr
366177636Sdfr	/*
367177636Sdfr	 * fcntl should return a lock structure reflecting the lock we
368177636Sdfr	 * made in the child process.
369177636Sdfr	 */
370177636Sdfr	if (fcntl(fd, F_GETLK, &fl) < 0)
371177636Sdfr		err(1, "F_GETLK");
372177636Sdfr
373177636Sdfr	printf("4 - F_GETLK on locked region: ");
374177636Sdfr	FAIL(fl.l_start != 0);
375177636Sdfr	FAIL(fl.l_len != 99);
376177636Sdfr	FAIL(fl.l_type != F_WRLCK);
377177636Sdfr	FAIL(fl.l_pid != pid);
378177636Sdfr#ifdef HAVE_SYSID
379177636Sdfr	FAIL(fl.l_sysid != 0);
380177636Sdfr#endif
381177636Sdfr
382177636Sdfr	kill(pid, SIGTERM);
383177636Sdfr	safe_waitpid(pid);
384177636Sdfr	close(pfd[0]);
385177636Sdfr	close(pfd[1]);
386177636Sdfr
387177636Sdfr	SUCCEED;
388177636Sdfr}
389177636Sdfr
390177636Sdfr/*
391177636Sdfr * Test 5 - F_SETLKW simple deadlock
392177636Sdfr *
393177636Sdfr * If a blocking shared lock request would cause a deadlock (i.e. the
394177636Sdfr * lock request is blocked by a process which is itself blocked on a
395177636Sdfr * lock currently owned by the process making the new request),
396177636Sdfr * EDEADLK is returned.
397177636Sdfr */
398177636Sdfrstatic int
399180025Sdfrtest5(int fd, __unused int argc, const __unused char **argv)
400177636Sdfr{
401177636Sdfr	/*
402177636Sdfr	 * We create a child process to hold the lock which we will
403177636Sdfr	 * test. Because our test relies on the child process being
404177636Sdfr	 * blocked on the parent's lock, we can't easily use a pipe to
405177636Sdfr	 * synchronize so we just sleep in the parent to given the
406177636Sdfr	 * child a chance to setup.
407177636Sdfr	 *
408177636Sdfr	 * To create the deadlock condition, we arrange for the parent
409177636Sdfr	 * to lock the first byte of the file and the child to lock
410177636Sdfr	 * the second byte.  After locking the second byte, the child
411177636Sdfr	 * will attempt to lock the first byte of the file, and
412177636Sdfr	 * block. The parent will then attempt to lock the second byte
413177636Sdfr	 * (owned by the child) which should cause deadlock.
414177636Sdfr	 */
415177636Sdfr	int pid;
416177636Sdfr	struct flock fl;
417177636Sdfr	int res;
418177636Sdfr
419177636Sdfr	/*
420177636Sdfr	 * Lock the first byte in the parent.
421177636Sdfr	 */
422177636Sdfr	fl.l_start = 0;
423177636Sdfr	fl.l_len = 1;
424177636Sdfr	fl.l_type = F_WRLCK;
425177636Sdfr	fl.l_whence = SEEK_SET;
426177636Sdfr	if (fcntl(fd, F_SETLK, &fl) < 0)
427177636Sdfr		err(1, "F_SETLK 1 (parent)");
428177636Sdfr
429177636Sdfr	pid = fork();
430177636Sdfr	if (pid < 0)
431177636Sdfr		err(1, "fork");
432177636Sdfr
433177636Sdfr	if (pid == 0) {
434177636Sdfr		/*
435177636Sdfr		 * Lock the second byte in the child and then block on
436177636Sdfr		 * the parent's lock.
437177636Sdfr		 */
438177636Sdfr		fl.l_start = 1;
439177636Sdfr		if (fcntl(fd, F_SETLK, &fl) < 0)
440177636Sdfr			err(1, "F_SETLK (child)");
441177636Sdfr		fl.l_start = 0;
442177636Sdfr		if (fcntl(fd, F_SETLKW, &fl) < 0)
443177636Sdfr			err(1, "F_SETLKW (child)");
444177636Sdfr		exit(0);
445177636Sdfr	}
446177636Sdfr
447177636Sdfr	/*
448177636Sdfr	 * Wait until the child has set its lock and then perform the
449177636Sdfr	 * test.
450177636Sdfr	 */
451177636Sdfr	sleep(1);
452177636Sdfr
453177636Sdfr	/*
454180025Sdfr	 * fcntl should immediately return -1 with errno set to
455180025Sdfr	 * EDEADLK. If the alarm fires, we failed to detect the
456180025Sdfr	 * deadlock.
457177636Sdfr	 */
458180025Sdfr	alarm(1);
459177636Sdfr	printf("5 - F_SETLKW simple deadlock: ");
460177636Sdfr
461177636Sdfr	fl.l_start = 1;
462177636Sdfr	res = fcntl(fd, F_SETLKW, &fl);
463177636Sdfr	kill(pid, SIGTERM);
464177636Sdfr	safe_waitpid(pid);
465177636Sdfr
466177636Sdfr	FAIL(res == 0);
467177636Sdfr	FAIL(errno != EDEADLK);
468177636Sdfr
469177636Sdfr	fl.l_start = 0;
470177636Sdfr	fl.l_len = 0;
471177636Sdfr	fl.l_type = F_UNLCK;
472177636Sdfr	if (fcntl(fd, F_SETLK, &fl) < 0)
473177636Sdfr		err(1, "F_UNLCK");
474177636Sdfr
475180025Sdfr	/*
476180025Sdfr	 * Cancel the alarm to avoid confusing later tests.
477180025Sdfr	 */
478180025Sdfr	alarm(0);
479180025Sdfr
480177636Sdfr	SUCCEED;
481177636Sdfr}
482177636Sdfr
483177636Sdfr/*
484177636Sdfr * Test 6 - F_SETLKW complex deadlock.
485177636Sdfr *
486177636Sdfr * This test involves three process, P, C1 and C2. We set things up so
487177636Sdfr * that P locks byte zero, C1 locks byte 1 and C2 locks byte 2. We
488177636Sdfr * also block C2 by attempting to lock byte zero. Lastly, P attempts
489177636Sdfr * to lock a range including byte 1 and 2. This represents a deadlock
490177636Sdfr * (due to C2's blocking attempt to lock byte zero).
491177636Sdfr */
492177636Sdfrstatic int
493180025Sdfrtest6(int fd, __unused int argc, const __unused char **argv)
494177636Sdfr{
495177636Sdfr	/*
496177636Sdfr	 * Because our test relies on the child process being blocked
497177636Sdfr	 * on the parent's lock, we can't easily use a pipe to
498177636Sdfr	 * synchronize so we just sleep in the parent to given the
499177636Sdfr	 * children a chance to setup.
500177636Sdfr	 */
501177636Sdfr	int pid1, pid2;
502177636Sdfr	struct flock fl;
503177636Sdfr	int res;
504177636Sdfr
505177636Sdfr	/*
506177636Sdfr	 * Lock the first byte in the parent.
507177636Sdfr	 */
508177636Sdfr	fl.l_start = 0;
509177636Sdfr	fl.l_len = 1;
510177636Sdfr	fl.l_type = F_WRLCK;
511177636Sdfr	fl.l_whence = SEEK_SET;
512177636Sdfr	if (fcntl(fd, F_SETLK, &fl) < 0)
513177636Sdfr		err(1, "F_SETLK 1 (parent)");
514177636Sdfr
515177636Sdfr	pid1 = fork();
516177636Sdfr	if (pid1 < 0)
517177636Sdfr		err(1, "fork");
518177636Sdfr
519177636Sdfr	if (pid1 == 0) {
520177636Sdfr		/*
521177636Sdfr		 * C1
522177636Sdfr		 * Lock the second byte in the child and then sleep
523177636Sdfr		 */
524177636Sdfr		fl.l_start = 1;
525177636Sdfr		if (fcntl(fd, F_SETLK, &fl) < 0)
526177636Sdfr			err(1, "F_SETLK (child1)");
527177636Sdfr		pause();
528177636Sdfr		exit(0);
529177636Sdfr	}
530177636Sdfr
531177636Sdfr	pid2 = fork();
532177636Sdfr	if (pid2 < 0)
533177636Sdfr		err(1, "fork");
534177636Sdfr
535177636Sdfr	if (pid2 == 0) {
536177636Sdfr		/*
537177636Sdfr		 * C2
538177636Sdfr		 * Lock the third byte in the child and then block on
539177636Sdfr		 * the parent's lock.
540177636Sdfr		 */
541177636Sdfr		fl.l_start = 2;
542177636Sdfr		if (fcntl(fd, F_SETLK, &fl) < 0)
543177636Sdfr			err(1, "F_SETLK (child2)");
544177636Sdfr		fl.l_start = 0;
545177636Sdfr		if (fcntl(fd, F_SETLKW, &fl) < 0)
546177636Sdfr			err(1, "F_SETLKW (child2)");
547177636Sdfr		exit(0);
548177636Sdfr	}
549177636Sdfr
550177636Sdfr	/*
551177636Sdfr	 * Wait until the children have set their locks and then
552177636Sdfr	 * perform the test.
553177636Sdfr	 */
554177636Sdfr	sleep(1);
555177636Sdfr
556177636Sdfr	/*
557177636Sdfr	 * fcntl should immediately return -1 with errno set to
558177636Sdfr	 * EDEADLK. If the alarm fires, we failed to detect the
559177636Sdfr	 * deadlock.
560177636Sdfr	 */
561177636Sdfr	alarm(1);
562177636Sdfr	printf("6 - F_SETLKW complex deadlock: ");
563177636Sdfr
564177636Sdfr	fl.l_start = 1;
565177636Sdfr	fl.l_len = 2;
566177636Sdfr	res = fcntl(fd, F_SETLKW, &fl);
567177636Sdfr	kill(pid1, SIGTERM);
568177636Sdfr	safe_waitpid(pid1);
569177636Sdfr	kill(pid2, SIGTERM);
570177636Sdfr	safe_waitpid(pid2);
571177636Sdfr
572177636Sdfr	fl.l_start = 0;
573177636Sdfr	fl.l_len = 0;
574177636Sdfr	fl.l_type = F_UNLCK;
575177636Sdfr	if (fcntl(fd, F_SETLK, &fl) < 0)
576177636Sdfr		err(1, "F_UNLCK");
577177636Sdfr
578177636Sdfr	FAIL(res == 0);
579177636Sdfr	FAIL(errno != EDEADLK);
580177636Sdfr
581177636Sdfr	/*
582177636Sdfr	 * Cancel the alarm to avoid confusing later tests.
583177636Sdfr	 */
584177636Sdfr	alarm(0);
585177636Sdfr
586177636Sdfr	SUCCEED;
587177636Sdfr}
588177636Sdfr
589177636Sdfr/*
590177636Sdfr * Test 7 - F_SETLK shared lock on exclusive locked region
591177636Sdfr *
592177636Sdfr * If a shared or exclusive lock cannot be set, fcntl returns
593177636Sdfr * immediately with EACCES or EAGAIN.
594177636Sdfr */
595177636Sdfrstatic int
596180025Sdfrtest7(int fd, __unused int argc, const __unused char **argv)
597177636Sdfr{
598177636Sdfr	/*
599177636Sdfr	 * We create a child process to hold the lock which we will
600177636Sdfr	 * test. We use a pipe to communicate with the child.
601177636Sdfr	 */
602177636Sdfr	int pid;
603177636Sdfr	int pfd[2];
604177636Sdfr	struct flock fl;
605177636Sdfr	char ch;
606177636Sdfr	int res;
607177636Sdfr
608177636Sdfr	if (pipe(pfd) < 0)
609177636Sdfr		err(1, "pipe");
610177636Sdfr
611177636Sdfr	fl.l_start = 0;
612177636Sdfr	fl.l_len = 0;
613177636Sdfr	fl.l_type = F_WRLCK;
614177636Sdfr	fl.l_whence = SEEK_SET;
615177636Sdfr
616177636Sdfr	pid = fork();
617177636Sdfr	if (pid < 0)
618177636Sdfr		err(1, "fork");
619177636Sdfr
620177636Sdfr	if (pid == 0) {
621177636Sdfr		/*
622177636Sdfr		 * We are the child. We set a write lock and then
623177636Sdfr		 * write one byte back to the parent to tell it. The
624177636Sdfr		 * parent will kill us when its done.
625177636Sdfr		 */
626177636Sdfr		if (fcntl(fd, F_SETLK, &fl) < 0)
627177636Sdfr			err(1, "F_SETLK (child)");
628177636Sdfr		if (write(pfd[1], "a", 1) < 0)
629177636Sdfr			err(1, "writing to pipe (child)");
630177636Sdfr		pause();
631177636Sdfr		exit(0);
632177636Sdfr	}
633177636Sdfr
634177636Sdfr	/*
635177636Sdfr	 * Wait until the child has set its lock and then perform the
636177636Sdfr	 * test.
637177636Sdfr	 */
638177636Sdfr	if (read(pfd[0], &ch, 1) != 1)
639177636Sdfr		err(1, "reading from pipe (child)");
640177636Sdfr
641177636Sdfr	/*
642177636Sdfr	 * fcntl should wait until the alarm and then return -1 with
643177636Sdfr	 * errno set to EINTR.
644177636Sdfr	 */
645177636Sdfr	printf("7 - F_SETLK shared lock on exclusive locked region: ");
646177636Sdfr
647177636Sdfr	fl.l_type = F_RDLCK;
648177636Sdfr	res = fcntl(fd, F_SETLK, &fl);
649177636Sdfr	kill(pid, SIGTERM);
650177636Sdfr	safe_waitpid(pid);
651177636Sdfr	close(pfd[0]);
652177636Sdfr	close(pfd[1]);
653177636Sdfr
654177636Sdfr	FAIL(res == 0);
655177636Sdfr	FAIL(errno != EACCES && errno != EAGAIN);
656177636Sdfr
657177636Sdfr	SUCCEED;
658177636Sdfr}
659177636Sdfr
660177636Sdfr/*
661177636Sdfr * Test 8 - F_SETLK shared lock on share locked region
662177636Sdfr *
663177636Sdfr * When a shared lock is set on a segment of a file, other processes
664177636Sdfr * shall be able to set shared locks on that segment or a portion of
665177636Sdfr * it.
666177636Sdfr */
667177636Sdfrstatic int
668180025Sdfrtest8(int fd, __unused int argc, const __unused char **argv)
669177636Sdfr{
670177636Sdfr	/*
671177636Sdfr	 * We create a child process to hold the lock which we will
672177636Sdfr	 * test. We use a pipe to communicate with the child.
673177636Sdfr	 */
674177636Sdfr	int pid;
675177636Sdfr	int pfd[2];
676177636Sdfr	struct flock fl;
677177636Sdfr	char ch;
678177636Sdfr	int res;
679177636Sdfr
680177636Sdfr	if (pipe(pfd) < 0)
681177636Sdfr		err(1, "pipe");
682177636Sdfr
683177636Sdfr	fl.l_start = 0;
684177636Sdfr	fl.l_len = 0;
685177636Sdfr	fl.l_type = F_RDLCK;
686177636Sdfr	fl.l_whence = SEEK_SET;
687177636Sdfr
688177636Sdfr	pid = fork();
689177636Sdfr	if (pid < 0)
690177636Sdfr		err(1, "fork");
691177636Sdfr
692177636Sdfr	if (pid == 0) {
693177636Sdfr		/*
694177636Sdfr		 * We are the child. We set a write lock and then
695177636Sdfr		 * write one byte back to the parent to tell it. The
696177636Sdfr		 * parent will kill us when its done.
697177636Sdfr		 */
698177636Sdfr		if (fcntl(fd, F_SETLK, &fl) < 0)
699177636Sdfr			err(1, "F_SETLK (child)");
700177636Sdfr		if (write(pfd[1], "a", 1) < 0)
701177636Sdfr			err(1, "writing to pipe (child)");
702177636Sdfr		pause();
703177636Sdfr		exit(0);
704177636Sdfr	}
705177636Sdfr
706177636Sdfr	/*
707177636Sdfr	 * Wait until the child has set its lock and then perform the
708177636Sdfr	 * test.
709177636Sdfr	 */
710177636Sdfr	if (read(pfd[0], &ch, 1) != 1)
711177636Sdfr		err(1, "reading from pipe (child)");
712177636Sdfr
713177636Sdfr	/*
714177636Sdfr	 * fcntl should wait until the alarm and then return -1 with
715177636Sdfr	 * errno set to EINTR.
716177636Sdfr	 */
717177636Sdfr	printf("8 - F_SETLK shared lock on share locked region: ");
718177636Sdfr
719177636Sdfr	fl.l_type = F_RDLCK;
720177636Sdfr	res = fcntl(fd, F_SETLK, &fl);
721177636Sdfr
722177636Sdfr	kill(pid, SIGTERM);
723177636Sdfr	safe_waitpid(pid);
724177636Sdfr	close(pfd[0]);
725177636Sdfr	close(pfd[1]);
726177636Sdfr
727177636Sdfr	fl.l_start = 0;
728177636Sdfr	fl.l_len = 0;
729177636Sdfr	fl.l_type = F_UNLCK;
730177636Sdfr	if (fcntl(fd, F_SETLK, &fl) < 0)
731177636Sdfr		err(1, "F_UNLCK");
732177636Sdfr
733177636Sdfr	FAIL(res != 0);
734177636Sdfr
735177636Sdfr	SUCCEED;
736177636Sdfr}
737177636Sdfr
738177636Sdfr/*
739177636Sdfr * Test 9 - F_SETLK exclusive lock on share locked region
740177636Sdfr *
741177636Sdfr * If a shared or exclusive lock cannot be set, fcntl returns
742177636Sdfr * immediately with EACCES or EAGAIN.
743177636Sdfr */
744177636Sdfrstatic int
745180025Sdfrtest9(int fd, __unused int argc, const __unused char **argv)
746177636Sdfr{
747177636Sdfr	/*
748177636Sdfr	 * We create a child process to hold the lock which we will
749177636Sdfr	 * test. We use a pipe to communicate with the child.
750177636Sdfr	 */
751177636Sdfr	int pid;
752177636Sdfr	int pfd[2];
753177636Sdfr	struct flock fl;
754177636Sdfr	char ch;
755177636Sdfr	int res;
756177636Sdfr
757177636Sdfr	if (pipe(pfd) < 0)
758177636Sdfr		err(1, "pipe");
759177636Sdfr
760177636Sdfr	fl.l_start = 0;
761177636Sdfr	fl.l_len = 0;
762177636Sdfr	fl.l_type = F_RDLCK;
763177636Sdfr	fl.l_whence = SEEK_SET;
764177636Sdfr
765177636Sdfr	pid = fork();
766177636Sdfr	if (pid < 0)
767177636Sdfr		err(1, "fork");
768177636Sdfr
769177636Sdfr	if (pid == 0) {
770177636Sdfr		/*
771177636Sdfr		 * We are the child. We set a write lock and then
772177636Sdfr		 * write one byte back to the parent to tell it. The
773177636Sdfr		 * parent will kill us when its done.
774177636Sdfr		 */
775177636Sdfr		if (fcntl(fd, F_SETLK, &fl) < 0)
776177636Sdfr			err(1, "F_SETLK (child)");
777177636Sdfr		if (write(pfd[1], "a", 1) < 0)
778177636Sdfr			err(1, "writing to pipe (child)");
779177636Sdfr		pause();
780177636Sdfr		exit(0);
781177636Sdfr	}
782177636Sdfr
783177636Sdfr	/*
784177636Sdfr	 * Wait until the child has set its lock and then perform the
785177636Sdfr	 * test.
786177636Sdfr	 */
787177636Sdfr	if (read(pfd[0], &ch, 1) != 1)
788177636Sdfr		err(1, "reading from pipe (child)");
789177636Sdfr
790177636Sdfr	/*
791177636Sdfr	 * fcntl should wait until the alarm and then return -1 with
792177636Sdfr	 * errno set to EINTR.
793177636Sdfr	 */
794177636Sdfr	printf("9 - F_SETLK exclusive lock on share locked region: ");
795177636Sdfr
796177636Sdfr	fl.l_type = F_WRLCK;
797177636Sdfr	res = fcntl(fd, F_SETLK, &fl);
798177636Sdfr	kill(pid, SIGTERM);
799177636Sdfr	safe_waitpid(pid);
800177636Sdfr	close(pfd[0]);
801177636Sdfr	close(pfd[1]);
802177636Sdfr
803177636Sdfr	FAIL(res == 0);
804177636Sdfr	FAIL(errno != EACCES && errno != EAGAIN);
805177636Sdfr
806177636Sdfr	SUCCEED;
807177636Sdfr}
808177636Sdfr
809177636Sdfr/*
810177636Sdfr * Test 10 - trying to set bogus pid or sysid values
811177636Sdfr *
812177636Sdfr * The l_pid and l_sysid fields are only used with F_GETLK to return
813177636Sdfr * the process ID of the process holding a blocking lock and the
814177636Sdfr * system ID of the system that owns that process
815177636Sdfr */
816177636Sdfrstatic int
817180025Sdfrtest10(int fd, __unused int argc, const __unused char **argv)
818177636Sdfr{
819177636Sdfr	/*
820177636Sdfr	 * We create a child process to hold the lock which we will
821177636Sdfr	 * test. We use a pipe to communicate with the child.
822177636Sdfr	 */
823177636Sdfr	int pid;
824177636Sdfr	int pfd[2];
825177636Sdfr	struct flock fl;
826177636Sdfr	char ch;
827177636Sdfr
828177636Sdfr	if (pipe(pfd) < 0)
829177636Sdfr		err(1, "pipe");
830177636Sdfr
831177636Sdfr	fl.l_start = 0;
832177636Sdfr	fl.l_len = 0;
833177636Sdfr	fl.l_type = F_WRLCK;
834177636Sdfr	fl.l_whence = SEEK_SET;
835177636Sdfr	fl.l_pid = 9999;
836177636Sdfr#ifdef HAVE_SYSID
837177636Sdfr	fl.l_sysid = 9999;
838177636Sdfr#endif
839177636Sdfr
840177636Sdfr	pid = fork();
841177636Sdfr	if (pid < 0)
842177636Sdfr		err(1, "fork");
843177636Sdfr
844177636Sdfr	if (pid == 0) {
845177636Sdfr		/*
846177636Sdfr		 * We are the child. We set a write lock and then
847177636Sdfr		 * write one byte back to the parent to tell it. The
848177636Sdfr		 * parent will kill us when its done.
849177636Sdfr		 */
850177636Sdfr		if (fcntl(fd, F_SETLK, &fl) < 0)
851177636Sdfr			err(1, "F_SETLK (child)");
852177636Sdfr		if (write(pfd[1], "a", 1) < 0)
853177636Sdfr			err(1, "writing to pipe (child)");
854177636Sdfr		pause();
855177636Sdfr		exit(0);
856177636Sdfr	}
857177636Sdfr
858177636Sdfr	/*
859177636Sdfr	 * Wait until the child has set its lock and then perform the
860177636Sdfr	 * test.
861177636Sdfr	 */
862177636Sdfr	if (read(pfd[0], &ch, 1) != 1)
863177636Sdfr		err(1, "reading from pipe (child)");
864177636Sdfr
865177636Sdfr	printf("10 - trying to set bogus pid or sysid values: ");
866177636Sdfr
867177636Sdfr	if (fcntl(fd, F_GETLK, &fl) < 0)
868177636Sdfr		err(1, "F_GETLK");
869177636Sdfr
870177636Sdfr	kill(pid, SIGTERM);
871177636Sdfr	safe_waitpid(pid);
872177636Sdfr	close(pfd[0]);
873177636Sdfr	close(pfd[1]);
874177636Sdfr
875177636Sdfr	FAIL(fl.l_pid != pid);
876177636Sdfr#ifdef HAVE_SYSID
877177636Sdfr	FAIL(fl.l_sysid != 0);
878177636Sdfr#endif
879177636Sdfr
880177636Sdfr	SUCCEED;
881177636Sdfr}
882177636Sdfr
883177636Sdfr/*
884177636Sdfr * Test 11 - remote locks
885177636Sdfr *
886177636Sdfr * XXX temporary interface which will be removed when the kernel lockd
887177636Sdfr * is added.
888177636Sdfr */
889177636Sdfrstatic int
890180025Sdfrtest11(int fd, __unused int argc, const __unused char **argv)
891177636Sdfr{
892177636Sdfr#ifdef F_SETLK_REMOTE
893177636Sdfr	struct flock fl;
894177636Sdfr	int res;
895177636Sdfr
896177636Sdfr	if (geteuid() != 0)
897177636Sdfr		return 0;
898177636Sdfr
899177636Sdfr	fl.l_start = 0;
900177636Sdfr	fl.l_len = 0;
901177636Sdfr	fl.l_type = F_WRLCK;
902177636Sdfr	fl.l_whence = SEEK_SET;
903177636Sdfr	fl.l_pid = 9999;
904177636Sdfr	fl.l_sysid = 1001;
905177636Sdfr
906177636Sdfr	printf("11 - remote locks: ");
907177636Sdfr
908177636Sdfr	res = fcntl(fd, F_SETLK_REMOTE, &fl);
909177636Sdfr	FAIL(res != 0);
910177636Sdfr
911177636Sdfr	fl.l_sysid = 1002;
912177636Sdfr	res = fcntl(fd, F_SETLK_REMOTE, &fl);
913177636Sdfr	FAIL(res == 0);
914177636Sdfr	FAIL(errno != EACCES && errno != EAGAIN);
915177636Sdfr
916177636Sdfr	res = fcntl(fd, F_GETLK, &fl);
917177636Sdfr	FAIL(res != 0);
918177636Sdfr	FAIL(fl.l_pid != 9999);
919177636Sdfr	FAIL(fl.l_sysid != 1001);
920177636Sdfr
921177636Sdfr	fl.l_type = F_UNLCK;
922177636Sdfr	fl.l_sysid = 1001;
923177636Sdfr	fl.l_start = 0;
924177636Sdfr	fl.l_len = 0;
925177636Sdfr	res = fcntl(fd, F_SETLK_REMOTE, &fl);
926177636Sdfr	FAIL(res != 0);
927177636Sdfr
928177636Sdfr	fl.l_pid = 1234;
929177636Sdfr	fl.l_sysid = 1001;
930177636Sdfr	fl.l_start = 0;
931177636Sdfr	fl.l_len = 1;
932177636Sdfr	fl.l_whence = SEEK_SET;
933177636Sdfr	fl.l_type = F_RDLCK;
934177636Sdfr	res = fcntl(fd, F_SETLK_REMOTE, &fl);
935177636Sdfr	FAIL(res != 0);
936177636Sdfr
937177636Sdfr	fl.l_sysid = 1002;
938177636Sdfr	res = fcntl(fd, F_SETLK_REMOTE, &fl);
939177636Sdfr	FAIL(res != 0);
940177636Sdfr
941177636Sdfr	fl.l_type = F_UNLCKSYS;
942177636Sdfr	fl.l_sysid = 1001;
943177636Sdfr	res = fcntl(fd, F_SETLK_REMOTE, &fl);
944177636Sdfr	FAIL(res != 0);
945177636Sdfr
946177636Sdfr	fl.l_type = F_WRLCK;
947177636Sdfr	res = fcntl(fd, F_GETLK, &fl);
948177636Sdfr	FAIL(res != 0);
949177636Sdfr	FAIL(fl.l_pid != 1234);
950177636Sdfr	FAIL(fl.l_sysid != 1002);
951177636Sdfr
952177636Sdfr	fl.l_type = F_UNLCKSYS;
953177636Sdfr	fl.l_sysid = 1002;
954177636Sdfr	res = fcntl(fd, F_SETLK_REMOTE, &fl);
955177636Sdfr	FAIL(res != 0);
956177636Sdfr
957177636Sdfr	SUCCEED;
958177636Sdfr#else
959177636Sdfr	return 0;
960177636Sdfr#endif
961177636Sdfr}
962177636Sdfr
963177636Sdfr/*
964177636Sdfr * Test 12 - F_SETLKW on locked region which is then unlocked
965177636Sdfr *
966177636Sdfr * If a shared or exclusive lock is blocked by other locks, the
967177636Sdfr * process waits until the request can be satisfied.
968177636Sdfr */
969177636Sdfrstatic int
970180025Sdfrtest12(int fd, __unused int argc, const __unused char **argv)
971177636Sdfr{
972177636Sdfr	/*
973177636Sdfr	 * We create a child process to hold the lock which we will
974177636Sdfr	 * test. We use a pipe to communicate with the child.
975177636Sdfr	 */
976177636Sdfr	int pid;
977177636Sdfr	int pfd[2];
978177636Sdfr	struct flock fl;
979177636Sdfr	char ch;
980177636Sdfr	int res;
981177636Sdfr
982177636Sdfr	if (pipe(pfd) < 0)
983177636Sdfr		err(1, "pipe");
984177636Sdfr
985177636Sdfr	fl.l_start = 0;
986177636Sdfr	fl.l_len = 0;
987177636Sdfr	fl.l_type = F_WRLCK;
988177636Sdfr	fl.l_whence = SEEK_SET;
989177636Sdfr
990177636Sdfr	pid = fork();
991177636Sdfr	if (pid < 0)
992177636Sdfr		err(1, "fork");
993177636Sdfr
994177636Sdfr	if (pid == 0) {
995177636Sdfr		/*
996177636Sdfr		 * We are the child. We set a write lock and then
997177636Sdfr		 * write one byte back to the parent to tell it. The
998177636Sdfr		 * parent will kill us when its done.
999177636Sdfr		 */
1000177636Sdfr		if (fcntl(fd, F_SETLK, &fl) < 0)
1001177636Sdfr			err(1, "F_SETLK (child)");
1002177636Sdfr		if (write(pfd[1], "a", 1) < 0)
1003177636Sdfr			err(1, "writing to pipe (child)");
1004177636Sdfr
1005177636Sdfr		sleep(1);
1006177636Sdfr		exit(0);
1007177636Sdfr	}
1008177636Sdfr
1009177636Sdfr	/*
1010177636Sdfr	 * Wait until the child has set its lock and then perform the
1011177636Sdfr	 * test.
1012177636Sdfr	 */
1013177636Sdfr	if (read(pfd[0], &ch, 1) != 1)
1014177636Sdfr		err(1, "reading from pipe (child)");
1015177636Sdfr
1016177636Sdfr	/*
1017177636Sdfr	 * fcntl should wait until the alarm and then return -1 with
1018177636Sdfr	 * errno set to EINTR.
1019177636Sdfr	 */
1020177636Sdfr	printf("12 - F_SETLKW on locked region which is then unlocked: ");
1021177636Sdfr
1022177636Sdfr	//alarm(1);
1023177636Sdfr
1024177636Sdfr	res = fcntl(fd, F_SETLKW, &fl);
1025177636Sdfr	kill(pid, SIGTERM);
1026177636Sdfr	safe_waitpid(pid);
1027177636Sdfr	close(pfd[0]);
1028177636Sdfr	close(pfd[1]);
1029177636Sdfr	FAIL(res != 0);
1030177636Sdfr
1031177636Sdfr	fl.l_start = 0;
1032177636Sdfr	fl.l_len = 0;
1033177636Sdfr	fl.l_type = F_UNLCK;
1034177636Sdfr	if (fcntl(fd, F_SETLK, &fl) < 0)
1035177636Sdfr		err(1, "F_UNLCK");
1036177636Sdfr
1037177636Sdfr	SUCCEED;
1038177636Sdfr}
1039177636Sdfr
1040177636Sdfr/*
1041177636Sdfr * Test 13 - F_SETLKW on locked region, race with owner
1042177636Sdfr *
1043177636Sdfr * If a shared or exclusive lock is blocked by other locks, the
1044177636Sdfr * process waits until the request can be satisfied.
1045177636Sdfr */
1046177636Sdfrstatic int
1047180025Sdfrtest13(int fd, __unused int argc, const __unused char **argv)
1048177636Sdfr{
1049177636Sdfr	/*
1050177636Sdfr	 * We create a child process to hold the lock which we will
1051177636Sdfr	 * test. We use a pipe to communicate with the child.
1052177636Sdfr	 */
1053177636Sdfr	int i;
1054177636Sdfr	int pid;
1055177636Sdfr	int pfd[2];
1056177636Sdfr	struct flock fl;
1057177636Sdfr	char ch;
1058177636Sdfr	int res;
1059177636Sdfr	struct itimerval itv;
1060177636Sdfr
1061177636Sdfr	printf("13 - F_SETLKW on locked region, race with owner: ");
1062177636Sdfr	fflush(stdout);
1063177636Sdfr
1064177636Sdfr	for (i = 0; i < 100; i++) {
1065177636Sdfr		if (pipe(pfd) < 0)
1066177636Sdfr			err(1, "pipe");
1067177636Sdfr
1068177636Sdfr		fl.l_start = 0;
1069177636Sdfr		fl.l_len = 0;
1070177636Sdfr		fl.l_type = F_WRLCK;
1071177636Sdfr		fl.l_whence = SEEK_SET;
1072177636Sdfr
1073177636Sdfr		pid = fork();
1074177636Sdfr		if (pid < 0)
1075177636Sdfr			err(1, "fork");
1076177636Sdfr
1077177636Sdfr		if (pid == 0) {
1078177636Sdfr			/*
1079177636Sdfr			 * We are the child. We set a write lock and then
1080177636Sdfr			 * write one byte back to the parent to tell it. The
1081177636Sdfr			 * parent will kill us when its done.
1082177636Sdfr			 */
1083177636Sdfr			if (fcntl(fd, F_SETLK, &fl) < 0)
1084177636Sdfr				err(1, "F_SETLK (child)");
1085177636Sdfr			if (write(pfd[1], "a", 1) < 0)
1086177636Sdfr				err(1, "writing to pipe (child)");
1087177636Sdfr
1088177636Sdfr			usleep(1);
1089177636Sdfr			exit(0);
1090177636Sdfr		}
1091177636Sdfr
1092177636Sdfr		/*
1093177636Sdfr		 * Wait until the child has set its lock and then perform the
1094177636Sdfr		 * test.
1095177636Sdfr		 */
1096177636Sdfr		while (read(pfd[0], &ch, 1) != 1) {
1097177636Sdfr			if (errno == EINTR)
1098177636Sdfr				continue;
1099177636Sdfr			err(1, "reading from pipe (child)");
1100177636Sdfr		}
1101177636Sdfr
1102177636Sdfr		/*
1103177636Sdfr		 * fcntl should wait until the alarm and then return -1 with
1104177636Sdfr		 * errno set to EINTR.
1105177636Sdfr		 */
1106177636Sdfr		itv.it_interval.tv_sec = 0;
1107177636Sdfr		itv.it_interval.tv_usec = 0;
1108177636Sdfr		itv.it_value.tv_sec = 0;
1109177636Sdfr		itv.it_value.tv_usec = 2;
1110177636Sdfr		setitimer(ITIMER_REAL, &itv, NULL);
1111177636Sdfr
1112177636Sdfr		res = fcntl(fd, F_SETLKW, &fl);
1113177636Sdfr		kill(pid, SIGTERM);
1114177636Sdfr		safe_waitpid(pid);
1115177636Sdfr		close(pfd[0]);
1116177636Sdfr		close(pfd[1]);
1117177636Sdfr		FAIL(!(res == 0 || (res == -1 && errno == EINTR)));
1118177636Sdfr
1119177636Sdfr		fl.l_start = 0;
1120177636Sdfr		fl.l_len = 0;
1121177636Sdfr		fl.l_type = F_UNLCK;
1122177636Sdfr		if (fcntl(fd, F_SETLK, &fl) < 0)
1123177636Sdfr			err(1, "F_UNLCK");
1124177636Sdfr	}
1125177636Sdfr	SUCCEED;
1126177636Sdfr}
1127177636Sdfr
1128177636Sdfr/*
1129177636Sdfr * Test 14 - soak test
1130177636Sdfr */
1131177636Sdfrstatic int
1132180025Sdfrtest14(int fd, int argc, const char **argv)
1133177636Sdfr{
1134177636Sdfr#define CHILD_COUNT 20
1135177636Sdfr	/*
1136177636Sdfr	 * We create a set of child processes and let each one run
1137177636Sdfr	 * through a random sequence of locks and unlocks.
1138177636Sdfr	 */
1139180025Sdfr	int i, j, id, id_base;
1140177636Sdfr	int pids[CHILD_COUNT], pid;
1141177636Sdfr	char buf[128];
1142177636Sdfr	char tbuf[128];
1143177636Sdfr	int map[128];
1144177636Sdfr	char outbuf[512];
1145177636Sdfr	struct flock fl;
1146177636Sdfr	struct itimerval itv;
1147177636Sdfr	int status;
1148177636Sdfr
1149180025Sdfr	id_base = 0;
1150180025Sdfr	if (argc >= 2)
1151180025Sdfr		id_base = strtol(argv[1], NULL, 0);
1152180025Sdfr
1153177636Sdfr	printf("14 - soak test: ");
1154177636Sdfr	fflush(stdout);
1155177636Sdfr
1156177636Sdfr	for (i = 0; i < 128; i++)
1157177636Sdfr		map[i] = F_UNLCK;
1158177636Sdfr
1159177636Sdfr	for (i = 0; i < CHILD_COUNT; i++) {
1160177636Sdfr
1161177636Sdfr		pid = fork();
1162177636Sdfr		if (pid < 0)
1163177636Sdfr			err(1, "fork");
1164177636Sdfr		if (pid) {
1165177636Sdfr			/*
1166177636Sdfr			 * Parent - record the pid and continue.
1167177636Sdfr			 */
1168177636Sdfr			pids[i] = pid;
1169177636Sdfr			continue;
1170177636Sdfr		}
1171177636Sdfr
1172177636Sdfr		/*
1173177636Sdfr		 * Child - do some work and exit.
1174177636Sdfr		 */
1175180025Sdfr		id = id_base + i;
1176180025Sdfr		srandom(getpid());
1177177636Sdfr
1178177636Sdfr		for (j = 0; j < 50; j++) {
1179177636Sdfr			int start, end, len;
1180177636Sdfr			int set, wrlock;
1181177636Sdfr
1182177636Sdfr			do {
1183177636Sdfr				start = random() & 127;
1184177636Sdfr				end = random() & 127;
1185177636Sdfr			} while (end <= start);
1186177636Sdfr
1187177636Sdfr			set = random() & 1;
1188177636Sdfr			wrlock = random() & 1;
1189177636Sdfr
1190177636Sdfr			len = end - start;
1191177636Sdfr			fl.l_start = start;
1192177636Sdfr			fl.l_len = len;
1193177636Sdfr			fl.l_whence = SEEK_SET;
1194177636Sdfr			if (set)
1195177636Sdfr				fl.l_type = wrlock ? F_WRLCK : F_RDLCK;
1196177636Sdfr			else
1197177636Sdfr				fl.l_type = F_UNLCK;
1198177636Sdfr
1199177636Sdfr			itv.it_interval.tv_sec = 0;
1200177636Sdfr			itv.it_interval.tv_usec = 0;
1201177636Sdfr			itv.it_value.tv_sec = 0;
1202177636Sdfr			itv.it_value.tv_usec = 3000;
1203177636Sdfr			setitimer(ITIMER_REAL, &itv, NULL);
1204177636Sdfr
1205177636Sdfr			if (fcntl(fd, F_SETLKW, &fl) < 0) {
1206177636Sdfr				if (errno == EDEADLK || errno == EINTR) {
1207177636Sdfr					if (verbose) {
1208177636Sdfr						snprintf(outbuf, sizeof(outbuf),
1209177636Sdfr						    "%d[%d]: %s [%d .. %d] %s\n",
1210177636Sdfr						    id, j,
1211177636Sdfr						    set ? (wrlock ? "write lock"
1212177636Sdfr							: "read lock")
1213177636Sdfr						    : "unlock", start, end,
1214177636Sdfr						    errno == EDEADLK
1215177636Sdfr						    ? "deadlock"
1216177636Sdfr						    : "interrupted");
1217177636Sdfr						write(1, outbuf,
1218177636Sdfr						    strlen(outbuf));
1219177636Sdfr					}
1220177636Sdfr					continue;
1221177636Sdfr				} else {
1222177636Sdfr					perror("fcntl");
1223177636Sdfr				}
1224177636Sdfr			}
1225177636Sdfr
1226177636Sdfr			itv.it_interval.tv_sec = 0;
1227177636Sdfr			itv.it_interval.tv_usec = 0;
1228177636Sdfr			itv.it_value.tv_sec = 0;
1229177636Sdfr			itv.it_value.tv_usec = 0;
1230177636Sdfr			setitimer(ITIMER_REAL, &itv, NULL);
1231177636Sdfr
1232177636Sdfr			if (verbose) {
1233177636Sdfr				snprintf(outbuf, sizeof(outbuf),
1234177636Sdfr				    "%d[%d]: %s [%d .. %d] succeeded\n",
1235177636Sdfr				    id, j,
1236177636Sdfr				    set ? (wrlock ? "write lock" : "read lock")
1237177636Sdfr				    : "unlock", start, end);
1238177636Sdfr				write(1, outbuf, strlen(outbuf));
1239177636Sdfr			}
1240177636Sdfr
1241177636Sdfr			if (set) {
1242177636Sdfr				if (wrlock) {
1243177636Sdfr					/*
1244177636Sdfr					 * We got a write lock - write
1245177636Sdfr					 * our ID to each byte that we
1246177636Sdfr					 * managed to claim.
1247177636Sdfr					 */
1248177636Sdfr					for (i = start; i < end; i++)
1249177636Sdfr						map[i] = F_WRLCK;
1250177636Sdfr					memset(&buf[start], id, len);
1251177636Sdfr					if (pwrite(fd, &buf[start], len,
1252177636Sdfr						start) != len) {
1253177636Sdfr						printf("%d: short write\n", id);
1254177636Sdfr						exit(1);
1255177636Sdfr					}
1256177636Sdfr				} else {
1257177636Sdfr					/*
1258177636Sdfr					 * We got a read lock - read
1259177636Sdfr					 * the bytes which we claimed
1260177636Sdfr					 * so that we can check that
1261177636Sdfr					 * they don't change
1262177636Sdfr					 * unexpectedly.
1263177636Sdfr					 */
1264177636Sdfr					for (i = start; i < end; i++)
1265177636Sdfr						map[i] = F_RDLCK;
1266177636Sdfr					if (pread(fd, &buf[start], len,
1267177636Sdfr						start) != len) {
1268177636Sdfr						printf("%d: short read\n", id);
1269177636Sdfr						exit(1);
1270177636Sdfr					}
1271177636Sdfr				}
1272177636Sdfr			} else {
1273177636Sdfr				for (i = start; i < end; i++)
1274177636Sdfr					map[i] = F_UNLCK;
1275177636Sdfr			}
1276177636Sdfr
1277177636Sdfr			usleep(1000);
1278177636Sdfr
1279177636Sdfr			/*
1280177636Sdfr			 * Read back the whole region so that we can
1281177636Sdfr			 * check that all the bytes we have some kind
1282177636Sdfr			 * of claim to have the correct value.
1283177636Sdfr			 */
1284177636Sdfr			if (pread(fd, tbuf, sizeof(tbuf), 0) != sizeof(tbuf)) {
1285177636Sdfr				printf("%d: short read\n", id);
1286177636Sdfr				exit(1);
1287177636Sdfr			}
1288177636Sdfr
1289177636Sdfr			for (i = 0; i < 128; i++) {
1290177636Sdfr				if (map[i] != F_UNLCK && buf[i] != tbuf[i]) {
1291177636Sdfr					snprintf(outbuf, sizeof(outbuf),
1292177636Sdfr					    "%d: byte %d expected %d, "
1293177636Sdfr					    "got %d\n", id, i, buf[i], tbuf[i]);
1294177636Sdfr					write(1, outbuf, strlen(outbuf));
1295177636Sdfr					exit(1);
1296177636Sdfr				}
1297177636Sdfr			}
1298177636Sdfr		}
1299177636Sdfr		if (verbose)
1300177636Sdfr			printf("%d[%d]: done\n", id, j);
1301177636Sdfr
1302177636Sdfr		exit(0);
1303177636Sdfr	}
1304177636Sdfr
1305177636Sdfr	status = 0;
1306177636Sdfr	for (i = 0; i < CHILD_COUNT; i++) {
1307177636Sdfr		status += safe_waitpid(pids[i]);
1308177636Sdfr	}
1309177636Sdfr	if (status)
1310177636Sdfr		FAIL(status != 0);
1311177636Sdfr
1312177636Sdfr	SUCCEED;
1313177636Sdfr}
1314177636Sdfr
1315180025Sdfr/*
1316180025Sdfr * Test 15 - flock(2) semantcs
1317180025Sdfr *
1318180025Sdfr * When a lock holder has a shared lock and attempts to upgrade that
1319180025Sdfr * shared lock to exclusive, it must drop the shared lock before
1320180025Sdfr * blocking on the exclusive lock.
1321180025Sdfr *
1322180025Sdfr * To test this, we first arrange for two shared locks on the file,
1323180025Sdfr * and then attempt to upgrade one of them to exclusive. This should
1324180025Sdfr * drop one of the shared locks and block. We interrupt the blocking
1325180025Sdfr * lock request and examine the lock state of the file after dropping
1326180025Sdfr * the other shared lock - there should be no active locks at this
1327180025Sdfr * point.
1328180025Sdfr */
1329180025Sdfrstatic int
1330180025Sdfrtest15(int fd, __unused int argc, const __unused char **argv)
1331180025Sdfr{
1332180025Sdfr#ifdef LOCK_EX
1333180025Sdfr	/*
1334180025Sdfr	 * We create a child process to hold the lock which we will
1335180025Sdfr	 * test. We use a pipe to communicate with the child.
1336180025Sdfr	 *
1337180025Sdfr	 * Since we only have one file descriptors and lock ownership
1338180025Sdfr	 * for flock(2) goes with the file descriptor, we use fcntl to
1339180025Sdfr	 * set the child's shared lock.
1340180025Sdfr	 */
1341180025Sdfr	int pid;
1342180025Sdfr	int pfd[2];
1343180025Sdfr	struct flock fl;
1344180025Sdfr	char ch;
1345180025Sdfr	int res;
1346180025Sdfr
1347180025Sdfr	if (pipe(pfd) < 0)
1348180025Sdfr		err(1, "pipe");
1349180025Sdfr
1350180025Sdfr	pid = fork();
1351180025Sdfr	if (pid < 0)
1352180025Sdfr		err(1, "fork");
1353180025Sdfr
1354180025Sdfr	if (pid == 0) {
1355180025Sdfr		/*
1356180025Sdfr		 * We are the child. We set a shared lock and then
1357180025Sdfr		 * write one byte back to the parent to tell it. The
1358180025Sdfr		 * parent will kill us when its done.
1359180025Sdfr		 */
1360180025Sdfr		fl.l_start = 0;
1361180025Sdfr		fl.l_len = 0;
1362180025Sdfr		fl.l_type = F_RDLCK;
1363180025Sdfr		fl.l_whence = SEEK_SET;
1364180025Sdfr		if (fcntl(fd, F_SETLK, &fl) < 0)
1365180025Sdfr			err(1, "fcntl(F_SETLK) (child)");
1366180025Sdfr		if (write(pfd[1], "a", 1) < 0)
1367180025Sdfr			err(1, "writing to pipe (child)");
1368180025Sdfr		pause();
1369180025Sdfr		exit(0);
1370180025Sdfr	}
1371180025Sdfr
1372180025Sdfr	/*
1373180025Sdfr	 * Wait until the child has set its lock and then perform the
1374180025Sdfr	 * test.
1375180025Sdfr	 */
1376180025Sdfr	if (read(pfd[0], &ch, 1) != 1)
1377180025Sdfr		err(1, "reading from pipe (child)");
1378180025Sdfr
1379268385Skib	(void)dup(fd);
1380180025Sdfr	if (flock(fd, LOCK_SH) < 0)
1381180025Sdfr		err(1, "flock shared");
1382180025Sdfr
1383180025Sdfr	/*
1384180025Sdfr	 * flock should wait until the alarm and then return -1 with
1385180025Sdfr	 * errno set to EINTR.
1386180025Sdfr	 */
1387180025Sdfr	printf("15 - flock(2) semantics: ");
1388180025Sdfr
1389180025Sdfr	alarm(1);
1390180025Sdfr	flock(fd, LOCK_EX);
1391180025Sdfr
1392180025Sdfr	/*
1393180025Sdfr	 * Kill the child to force it to drop its locks.
1394180025Sdfr	 */
1395180025Sdfr	kill(pid, SIGTERM);
1396180025Sdfr	safe_waitpid(pid);
1397180025Sdfr
1398180025Sdfr	fl.l_start = 0;
1399180025Sdfr	fl.l_len = 0;
1400180025Sdfr	fl.l_type = F_WRLCK;
1401180025Sdfr	fl.l_whence = SEEK_SET;
1402180025Sdfr	res = fcntl(fd, F_GETLK, &fl);
1403180025Sdfr
1404180025Sdfr	close(pfd[0]);
1405180025Sdfr	close(pfd[1]);
1406180025Sdfr	FAIL(res != 0);
1407180025Sdfr	FAIL(fl.l_type != F_UNLCK);
1408180025Sdfr
1409180025Sdfr	SUCCEED;
1410180025Sdfr#else
1411180025Sdfr	return 0;
1412180025Sdfr#endif
1413180025Sdfr}
1414180025Sdfr
1415192949Szmlstruct test_ctx {
1416192949Szml	struct flock tc_fl;
1417192949Szml	int tc_fd;
1418192949Szml};
1419192949Szml
1420192949Szmlstatic void *
1421192949Szmltest16_func(void *tc_in)
1422192949Szml{
1423192949Szml	uintptr_t error;
1424192949Szml	struct test_ctx *tc = tc_in;
1425192949Szml
1426192949Szml	error = fcntl(tc->tc_fd, F_SETLKW, &tc->tc_fl);
1427192949Szml
1428192949Szml	pthread_exit((void *)error);
1429192949Szml}
1430192949Szml
1431192949Szml#define THREADS 10
1432192949Szml
1433192949Szml/*
1434192949Szml * Test 16 - F_SETLKW from two threads
1435192949Szml *
1436192949Szml * If two threads within a process are blocked on a lock and the lock
1437192949Szml * is granted, make sure things are sane.
1438192949Szml */
1439192949Szmlstatic int
1440192949Szmltest16(int fd, __unused int argc, const __unused char **argv)
1441192949Szml{
1442192949Szml	/*
1443192949Szml	 * We create a child process to hold the lock which we will
1444192949Szml	 * test. We use a pipe to communicate with the child.
1445192949Szml	 */
1446192949Szml	int pid;
1447192949Szml	int pfd[2];
1448192949Szml	struct test_ctx tc = { .tc_fd = fd };
1449192949Szml	char ch;
1450192949Szml	int i;
1451192949Szml	int error;
1452192949Szml	pthread_t thr[THREADS];
1453192949Szml
1454192949Szml	if (pipe(pfd) < 0)
1455192949Szml		err(1, "pipe");
1456192949Szml
1457192949Szml	tc.tc_fl.l_start = 0;
1458192949Szml	tc.tc_fl.l_len = 0;
1459192949Szml	tc.tc_fl.l_type = F_WRLCK;
1460192949Szml	tc.tc_fl.l_whence = SEEK_SET;
1461192949Szml
1462192949Szml	pid = fork();
1463192949Szml	if (pid < 0)
1464192949Szml		err(1, "fork");
1465192949Szml
1466192949Szml	if (pid == 0) {
1467192949Szml		/*
1468192949Szml		 * We are the child. We set a write lock and then
1469192949Szml		 * write one byte back to the parent to tell it. The
1470192949Szml		 * parent will kill us when its done.
1471192949Szml		 */
1472192949Szml		if (fcntl(fd, F_SETLK, &tc.tc_fl) < 0)
1473192949Szml			err(1, "F_SETLK (child)");
1474192949Szml		if (write(pfd[1], "a", 1) < 0)
1475192949Szml			err(1, "writing to pipe (child)");
1476192949Szml		pause();
1477192949Szml		exit(0);
1478192949Szml	}
1479192949Szml
1480192949Szml	/*
1481192949Szml	 * Wait until the child has set its lock and then perform the
1482192949Szml	 * test.
1483192949Szml	 */
1484192949Szml	if (read(pfd[0], &ch, 1) != 1)
1485192949Szml		err(1, "reading from pipe (child)");
1486192949Szml
1487192949Szml	/*
1488192949Szml	 * fcntl should wait until the alarm and then return -1 with
1489192949Szml	 * errno set to EINTR.
1490192949Szml	 */
1491192949Szml	printf("16 - F_SETLKW on locked region by two threads: ");
1492192949Szml
1493192949Szml	for (i = 0; i < THREADS; i++) {
1494192949Szml		error = pthread_create(&thr[i], NULL, test16_func, &tc);
1495192949Szml		if (error)
1496192949Szml			err(1, "pthread_create");
1497192949Szml	}
1498192949Szml
1499192949Szml	/*
1500192949Szml	 * Sleep, then kill the child. This makes me a little sad, but it's
1501192949Szml	 * tricky to tell whether the threads are all really blocked by this
1502192949Szml	 * point.
1503192949Szml	 */
1504192949Szml	sleep(1);
1505192949Szml	kill(pid, SIGTERM);
1506192949Szml	safe_waitpid(pid);
1507192949Szml	close(pfd[0]);
1508192949Szml	close(pfd[1]);
1509192949Szml
1510192949Szml	for (i = 0; i < THREADS; i++) {
1511192949Szml		void *res;
1512192949Szml		error = pthread_join(thr[i], &res);
1513192949Szml		if (error)
1514192949Szml			err(1, "pthread_join");
1515192949Szml		FAIL((uintptr_t)res != 0);
1516192949Szml	}
1517192949Szml
1518192949Szml	SUCCEED;
1519192949Szml}
1520192949Szml
1521177636Sdfrstruct test {
1522180025Sdfr	int (*testfn)(int, int, const char **);	/* function to perform the test */
1523177636Sdfr	int num;		/* test number */
1524177636Sdfr	int intr;		/* non-zero if the test interrupts a lock */
1525177636Sdfr};
1526177636Sdfr
1527277527Sngiestatic struct test tests[] = {
1528177636Sdfr	{	test1,		1,	0	},
1529177636Sdfr	{	test2,		2,	0	},
1530177636Sdfr	{	test3,		3,	1	},
1531177636Sdfr	{	test4,		4,	0	},
1532177636Sdfr	{	test5,		5,	1	},
1533177636Sdfr	{	test6,		6,	1	},
1534177636Sdfr	{	test7,		7,	0	},
1535177636Sdfr	{	test8,		8,	0	},
1536177636Sdfr	{	test9,		9,	0	},
1537177636Sdfr	{	test10,		10,	0	},
1538177636Sdfr	{	test11,		11,	1	},
1539177636Sdfr	{	test12,		12,	0	},
1540177636Sdfr	{	test13,		13,	1	},
1541177636Sdfr	{	test14,		14,	0	},
1542180025Sdfr	{	test15,		15,	1	},
1543192949Szml	{	test16,		16,	1	},
1544177636Sdfr};
1545177636Sdfr
1546177636Sdfrint
1547177636Sdfrmain(int argc, const char *argv[])
1548177636Sdfr{
1549177636Sdfr	int testnum;
1550177636Sdfr	int fd;
1551177636Sdfr	int nointr;
1552277527Sngie	unsigned i;
1553177636Sdfr	struct sigaction sa;
1554180025Sdfr	int test_argc;
1555180025Sdfr	const char **test_argv;
1556177636Sdfr
1557180025Sdfr	if (argc < 2) {
1558180025Sdfr		errx(1, "usage: flock <directory> [test number] ...");
1559177636Sdfr	}
1560177636Sdfr
1561177636Sdfr	fd = make_file(argv[1], 1024);
1562180025Sdfr	if (argc >= 3) {
1563177636Sdfr		testnum = strtol(argv[2], NULL, 0);
1564180025Sdfr		test_argc = argc - 2;
1565180025Sdfr		test_argv = argv + 2;
1566180025Sdfr	} else {
1567177636Sdfr		testnum = 0;
1568180025Sdfr		test_argc = 0;
1569298490Sngie		test_argv = NULL;
1570180025Sdfr	}
1571177636Sdfr
1572177636Sdfr	sa.sa_handler = ignore_alarm;
1573177636Sdfr	sigemptyset(&sa.sa_mask);
1574177636Sdfr	sa.sa_flags = 0;
1575177636Sdfr	sigaction(SIGALRM, &sa, 0);
1576177636Sdfr
1577177636Sdfr	nointr = 0;
1578180025Sdfr#if defined(__FreeBSD__) && __FreeBSD_version < 800040
1579177636Sdfr	{
1580177636Sdfr		/*
1581180025Sdfr		 * FreeBSD with userland NLM can't interrupt a blocked
1582180025Sdfr		 * lock request on an NFS mounted filesystem.
1583177636Sdfr		 */
1584177636Sdfr		struct statfs st;
1585177636Sdfr		fstatfs(fd, &st);
1586177636Sdfr		nointr = !strcmp(st.f_fstypename, "nfs");
1587177636Sdfr	}
1588177636Sdfr#endif
1589177636Sdfr
1590277527Sngie	for (i = 0; i < nitems(tests); i++) {
1591177636Sdfr		if (tests[i].intr && nointr)
1592177636Sdfr			continue;
1593177636Sdfr		if (!testnum || tests[i].num == testnum)
1594180025Sdfr			tests[i].testfn(fd, test_argc, test_argv);
1595177636Sdfr	}
1596177636Sdfr
1597177636Sdfr	return 0;
1598177636Sdfr}
1599