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
30177636Sdfr#include <sys/time.h>
31177636Sdfr#ifdef __FreeBSD__
32177636Sdfr#include <sys/mount.h>
33177636Sdfr#endif
34180025Sdfr#include <sys/stat.h>
35177636Sdfr#include <sys/wait.h>
36177636Sdfr
37177636Sdfr#include <err.h>
38177636Sdfr#include <errno.h>
39177636Sdfr#include <fcntl.h>
40192949Szml#include <pthread.h>
41177636Sdfr#include <signal.h>
42177636Sdfr#include <stdio.h>
43177636Sdfr#include <stdlib.h>
44177636Sdfr#include <string.h>
45177636Sdfr#include <unistd.h>
46177636Sdfr
47177636Sdfr#ifdef __FreeBSD__
48177638Sdfr#if __FreeBSD_version >= 800028
49177636Sdfr#define HAVE_SYSID
50177636Sdfr#endif
51177636Sdfr#include <sys/cdefs.h>
52177636Sdfr#else
53177636Sdfr#ifndef __unused
54177636Sdfr#define __unused
55177636Sdfr#endif
56177636Sdfr#endif
57177636Sdfr
58177636Sdfrint verbose = 0;
59177636Sdfr
60177636Sdfrstatic int
61180025Sdfrmake_file(const char *pathname, off_t sz)
62177636Sdfr{
63180025Sdfr	struct stat st;
64177636Sdfr	const char *template = "/flocktempXXXXXX";
65177636Sdfr	size_t len;
66177636Sdfr	char *filename;
67177636Sdfr	int fd;
68177636Sdfr
69180025Sdfr	if (stat(pathname, &st) == 0) {
70180025Sdfr		if (S_ISREG(st.st_mode)) {
71180025Sdfr			fd = open(pathname, O_RDWR);
72180025Sdfr			if (fd < 0)
73180025Sdfr				err(1, "open(%s)", pathname);
74180025Sdfr			if (ftruncate(fd, sz) < 0)
75180025Sdfr				err(1, "ftruncate");
76180025Sdfr			return (fd);
77180025Sdfr		}
78180025Sdfr	}
79180025Sdfr
80180025Sdfr	len = strlen(pathname) + strlen(template) + 1;
81177636Sdfr	filename = malloc(len);
82180025Sdfr	strcpy(filename, pathname);
83177636Sdfr	strcat(filename, template);
84177636Sdfr	fd = mkstemp(filename);
85177636Sdfr	if (fd < 0)
86177636Sdfr		err(1, "mkstemp");
87177636Sdfr	if (ftruncate(fd, sz) < 0)
88177636Sdfr		err(1, "ftruncate");
89177636Sdfr	if (unlink(filename) < 0)
90177636Sdfr		err(1, "unlink");
91177636Sdfr	free(filename);
92177636Sdfr
93177636Sdfr	return (fd);
94177636Sdfr}
95177636Sdfr
96177636Sdfrstatic void
97177636Sdfrignore_alarm(int __unused sig)
98177636Sdfr{
99177636Sdfr}
100177636Sdfr
101180025Sdfrstatic int
102180025Sdfrsafe_waitpid(pid_t pid)
103180025Sdfr{
104180025Sdfr	int save_errno;
105180025Sdfr	int status;
106180025Sdfr
107180025Sdfr	save_errno = errno;
108180025Sdfr	errno = 0;
109180025Sdfr	while (waitpid(pid, &status, 0) != pid) {
110180025Sdfr		if (errno == EINTR)
111180025Sdfr			continue;
112180025Sdfr		err(1, "waitpid");
113180025Sdfr	}
114180025Sdfr	errno = save_errno;
115180025Sdfr
116180025Sdfr	return (status);
117180025Sdfr}
118180025Sdfr
119177636Sdfr#define FAIL(test)					\
120177636Sdfr	do {						\
121177636Sdfr		if (test) {				\
122177636Sdfr			printf("FAIL (%s)\n", #test);	\
123177636Sdfr			return -1;			\
124177636Sdfr		}					\
125177636Sdfr	} while (0)
126177636Sdfr
127177636Sdfr#define SUCCEED \
128177636Sdfr	do { printf("SUCCEED\n"); return 0; } while (0)
129177636Sdfr
130177636Sdfr/*
131177636Sdfr * Test 1 - F_GETLK on unlocked region
132177636Sdfr *
133177636Sdfr * If no lock is found that would prevent this lock from being
134177636Sdfr * created, the structure is left unchanged by this function call
135177636Sdfr * except for the lock type which is set to F_UNLCK.
136177636Sdfr */
137177636Sdfrstatic int
138180025Sdfrtest1(int fd, __unused int argc, const __unused char **argv)
139177636Sdfr{
140177636Sdfr	struct flock fl1, fl2;
141177636Sdfr
142177636Sdfr	memset(&fl1, 1, sizeof(fl1));
143177636Sdfr	fl1.l_type = F_WRLCK;
144177636Sdfr	fl1.l_whence = SEEK_SET;
145177636Sdfr	fl2 = fl1;
146177636Sdfr
147177636Sdfr	if (fcntl(fd, F_GETLK, &fl1) < 0)
148177636Sdfr		err(1, "F_GETLK");
149177636Sdfr
150177636Sdfr	printf("1 - F_GETLK on unlocked region: ");
151177636Sdfr	FAIL(fl1.l_start != fl2.l_start);
152177636Sdfr	FAIL(fl1.l_len != fl2.l_len);
153177636Sdfr	FAIL(fl1.l_pid != fl2.l_pid);
154177636Sdfr	FAIL(fl1.l_type != F_UNLCK);
155177636Sdfr	FAIL(fl1.l_whence != fl2.l_whence);
156177636Sdfr#ifdef HAVE_SYSID
157177636Sdfr	FAIL(fl1.l_sysid != fl2.l_sysid);
158177636Sdfr#endif
159177636Sdfr
160177636Sdfr	SUCCEED;
161177636Sdfr}
162177636Sdfr
163177636Sdfr/*
164177636Sdfr * Test 2 - F_SETLK on locked region
165177636Sdfr *
166177636Sdfr * If a shared or exclusive lock cannot be set, fcntl returns
167177636Sdfr * immediately with EACCES or EAGAIN.
168177636Sdfr */
169177636Sdfrstatic int
170180025Sdfrtest2(int fd, __unused int argc, const __unused char **argv)
171177636Sdfr{
172177636Sdfr	/*
173177636Sdfr	 * We create a child process to hold the lock which we will
174177636Sdfr	 * test. We use a pipe to communicate with the child.
175177636Sdfr	 */
176177636Sdfr	int pid;
177177636Sdfr	int pfd[2];
178177636Sdfr	struct flock fl;
179177636Sdfr	char ch;
180177636Sdfr	int res;
181177636Sdfr
182177636Sdfr	if (pipe(pfd) < 0)
183177636Sdfr		err(1, "pipe");
184177636Sdfr
185177636Sdfr	fl.l_start = 0;
186177636Sdfr	fl.l_len = 0;
187177636Sdfr	fl.l_type = F_WRLCK;
188177636Sdfr	fl.l_whence = SEEK_SET;
189177636Sdfr
190177636Sdfr	pid = fork();
191177636Sdfr	if (pid < 0)
192177636Sdfr		err(1, "fork");
193177636Sdfr
194177636Sdfr	if (pid == 0) {
195177636Sdfr		/*
196177636Sdfr		 * We are the child. We set a write lock and then
197177636Sdfr		 * write one byte back to the parent to tell it. The
198177636Sdfr		 * parent will kill us when its done.
199177636Sdfr		 */
200177636Sdfr		if (fcntl(fd, F_SETLK, &fl) < 0)
201177636Sdfr			err(1, "F_SETLK (child)");
202177636Sdfr		if (write(pfd[1], "a", 1) < 0)
203177636Sdfr			err(1, "writing to pipe (child)");
204177636Sdfr		pause();
205177636Sdfr		exit(0);
206177636Sdfr	}
207177636Sdfr
208177636Sdfr	/*
209177636Sdfr	 * Wait until the child has set its lock and then perform the
210177636Sdfr	 * test.
211177636Sdfr	 */
212177636Sdfr	if (read(pfd[0], &ch, 1) != 1)
213177636Sdfr		err(1, "reading from pipe (child)");
214177636Sdfr
215177636Sdfr	/*
216177636Sdfr	 * fcntl should return -1 with errno set to either EACCES or
217177636Sdfr	 * EAGAIN.
218177636Sdfr	 */
219177636Sdfr	printf("2 - F_SETLK on locked region: ");
220177636Sdfr	res = fcntl(fd, F_SETLK, &fl);
221177636Sdfr	kill(pid, SIGTERM);
222177636Sdfr	safe_waitpid(pid);
223177636Sdfr	close(pfd[0]);
224177636Sdfr	close(pfd[1]);
225177636Sdfr	FAIL(res == 0);
226177636Sdfr	FAIL(errno != EACCES && errno != EAGAIN);
227177636Sdfr
228177636Sdfr	SUCCEED;
229177636Sdfr}
230177636Sdfr
231177636Sdfr/*
232177636Sdfr * Test 3 - F_SETLKW on locked region
233177636Sdfr *
234177636Sdfr * If a shared or exclusive lock is blocked by other locks, the
235177636Sdfr * process waits until the request can be satisfied.
236177636Sdfr *
237177636Sdfr * XXX this test hangs on FreeBSD NFS filesystems due to limitations
238177636Sdfr * in FreeBSD's client (and server) lockd implementation.
239177636Sdfr */
240177636Sdfrstatic int
241180025Sdfrtest3(int fd, __unused int argc, const __unused char **argv)
242177636Sdfr{
243177636Sdfr	/*
244177636Sdfr	 * We create a child process to hold the lock which we will
245177636Sdfr	 * test. We use a pipe to communicate with the child.
246177636Sdfr	 */
247177636Sdfr	int pid;
248177636Sdfr	int pfd[2];
249177636Sdfr	struct flock fl;
250177636Sdfr	char ch;
251177636Sdfr	int res;
252177636Sdfr
253177636Sdfr	if (pipe(pfd) < 0)
254177636Sdfr		err(1, "pipe");
255177636Sdfr
256177636Sdfr	fl.l_start = 0;
257177636Sdfr	fl.l_len = 0;
258177636Sdfr	fl.l_type = F_WRLCK;
259177636Sdfr	fl.l_whence = SEEK_SET;
260177636Sdfr
261177636Sdfr	pid = fork();
262177636Sdfr	if (pid < 0)
263177636Sdfr		err(1, "fork");
264177636Sdfr
265177636Sdfr	if (pid == 0) {
266177636Sdfr		/*
267177636Sdfr		 * We are the child. We set a write lock and then
268177636Sdfr		 * write one byte back to the parent to tell it. The
269177636Sdfr		 * parent will kill us when its done.
270177636Sdfr		 */
271177636Sdfr		if (fcntl(fd, F_SETLK, &fl) < 0)
272177636Sdfr			err(1, "F_SETLK (child)");
273177636Sdfr		if (write(pfd[1], "a", 1) < 0)
274177636Sdfr			err(1, "writing to pipe (child)");
275177636Sdfr		pause();
276177636Sdfr		exit(0);
277177636Sdfr	}
278177636Sdfr
279177636Sdfr	/*
280177636Sdfr	 * Wait until the child has set its lock and then perform the
281177636Sdfr	 * test.
282177636Sdfr	 */
283177636Sdfr	if (read(pfd[0], &ch, 1) != 1)
284177636Sdfr		err(1, "reading from pipe (child)");
285177636Sdfr
286177636Sdfr	/*
287177636Sdfr	 * fcntl should wait until the alarm and then return -1 with
288177636Sdfr	 * errno set to EINTR.
289177636Sdfr	 */
290177636Sdfr	printf("3 - F_SETLKW on locked region: ");
291177636Sdfr
292177636Sdfr	alarm(1);
293177636Sdfr
294177636Sdfr	res = fcntl(fd, F_SETLKW, &fl);
295177636Sdfr	kill(pid, SIGTERM);
296177636Sdfr	safe_waitpid(pid);
297177636Sdfr	close(pfd[0]);
298177636Sdfr	close(pfd[1]);
299177636Sdfr	FAIL(res == 0);
300177636Sdfr	FAIL(errno != EINTR);
301177636Sdfr
302177636Sdfr	SUCCEED;
303177636Sdfr}
304177636Sdfr
305177636Sdfr/*
306177636Sdfr * Test 4 - F_GETLK on locked region
307177636Sdfr *
308177636Sdfr * Get the first lock that blocks the lock.
309177636Sdfr */
310177636Sdfrstatic int
311180025Sdfrtest4(int fd, __unused int argc, const __unused char **argv)
312177636Sdfr{
313177636Sdfr	/*
314177636Sdfr	 * We create a child process to hold the lock which we will
315177636Sdfr	 * test. We use a pipe to communicate with the child.
316177636Sdfr	 */
317177636Sdfr	int pid;
318177636Sdfr	int pfd[2];
319177636Sdfr	struct flock fl;
320177636Sdfr	char ch;
321177636Sdfr
322177636Sdfr	if (pipe(pfd) < 0)
323177636Sdfr		err(1, "pipe");
324177636Sdfr
325177636Sdfr	fl.l_start = 0;
326177636Sdfr	fl.l_len = 99;
327177636Sdfr	fl.l_type = F_WRLCK;
328177636Sdfr	fl.l_whence = SEEK_SET;
329177636Sdfr
330177636Sdfr	pid = fork();
331177636Sdfr	if (pid < 0)
332177636Sdfr		err(1, "fork");
333177636Sdfr
334177636Sdfr	if (pid == 0) {
335177636Sdfr		/*
336177636Sdfr		 * We are the child. We set a write lock and then
337177636Sdfr		 * write one byte back to the parent to tell it. The
338177636Sdfr		 * parent will kill us when its done.
339177636Sdfr		 */
340177636Sdfr		if (fcntl(fd, F_SETLK, &fl) < 0)
341177636Sdfr			err(1, "F_SETLK (child)");
342177636Sdfr		if (write(pfd[1], "a", 1) < 0)
343177636Sdfr			err(1, "writing to pipe (child)");
344177636Sdfr		pause();
345177636Sdfr		exit(0);
346177636Sdfr	}
347177636Sdfr
348177636Sdfr	/*
349177636Sdfr	 * Wait until the child has set its lock and then perform the
350177636Sdfr	 * test.
351177636Sdfr	 */
352177636Sdfr	if (read(pfd[0], &ch, 1) != 1)
353177636Sdfr		err(1, "reading from pipe (child)");
354177636Sdfr
355177636Sdfr	/*
356177636Sdfr	 * fcntl should return a lock structure reflecting the lock we
357177636Sdfr	 * made in the child process.
358177636Sdfr	 */
359177636Sdfr	if (fcntl(fd, F_GETLK, &fl) < 0)
360177636Sdfr		err(1, "F_GETLK");
361177636Sdfr
362177636Sdfr	printf("4 - F_GETLK on locked region: ");
363177636Sdfr	FAIL(fl.l_start != 0);
364177636Sdfr	FAIL(fl.l_len != 99);
365177636Sdfr	FAIL(fl.l_type != F_WRLCK);
366177636Sdfr	FAIL(fl.l_pid != pid);
367177636Sdfr#ifdef HAVE_SYSID
368177636Sdfr	FAIL(fl.l_sysid != 0);
369177636Sdfr#endif
370177636Sdfr
371177636Sdfr	kill(pid, SIGTERM);
372177636Sdfr	safe_waitpid(pid);
373177636Sdfr	close(pfd[0]);
374177636Sdfr	close(pfd[1]);
375177636Sdfr
376177636Sdfr	SUCCEED;
377177636Sdfr}
378177636Sdfr
379177636Sdfr/*
380177636Sdfr * Test 5 - F_SETLKW simple deadlock
381177636Sdfr *
382177636Sdfr * If a blocking shared lock request would cause a deadlock (i.e. the
383177636Sdfr * lock request is blocked by a process which is itself blocked on a
384177636Sdfr * lock currently owned by the process making the new request),
385177636Sdfr * EDEADLK is returned.
386177636Sdfr */
387177636Sdfrstatic int
388180025Sdfrtest5(int fd, __unused int argc, const __unused char **argv)
389177636Sdfr{
390177636Sdfr	/*
391177636Sdfr	 * We create a child process to hold the lock which we will
392177636Sdfr	 * test. Because our test relies on the child process being
393177636Sdfr	 * blocked on the parent's lock, we can't easily use a pipe to
394177636Sdfr	 * synchronize so we just sleep in the parent to given the
395177636Sdfr	 * child a chance to setup.
396177636Sdfr	 *
397177636Sdfr	 * To create the deadlock condition, we arrange for the parent
398177636Sdfr	 * to lock the first byte of the file and the child to lock
399177636Sdfr	 * the second byte.  After locking the second byte, the child
400177636Sdfr	 * will attempt to lock the first byte of the file, and
401177636Sdfr	 * block. The parent will then attempt to lock the second byte
402177636Sdfr	 * (owned by the child) which should cause deadlock.
403177636Sdfr	 */
404177636Sdfr	int pid;
405177636Sdfr	struct flock fl;
406177636Sdfr	int res;
407177636Sdfr
408177636Sdfr	/*
409177636Sdfr	 * Lock the first byte in the parent.
410177636Sdfr	 */
411177636Sdfr	fl.l_start = 0;
412177636Sdfr	fl.l_len = 1;
413177636Sdfr	fl.l_type = F_WRLCK;
414177636Sdfr	fl.l_whence = SEEK_SET;
415177636Sdfr	if (fcntl(fd, F_SETLK, &fl) < 0)
416177636Sdfr		err(1, "F_SETLK 1 (parent)");
417177636Sdfr
418177636Sdfr	pid = fork();
419177636Sdfr	if (pid < 0)
420177636Sdfr		err(1, "fork");
421177636Sdfr
422177636Sdfr	if (pid == 0) {
423177636Sdfr		/*
424177636Sdfr		 * Lock the second byte in the child and then block on
425177636Sdfr		 * the parent's lock.
426177636Sdfr		 */
427177636Sdfr		fl.l_start = 1;
428177636Sdfr		if (fcntl(fd, F_SETLK, &fl) < 0)
429177636Sdfr			err(1, "F_SETLK (child)");
430177636Sdfr		fl.l_start = 0;
431177636Sdfr		if (fcntl(fd, F_SETLKW, &fl) < 0)
432177636Sdfr			err(1, "F_SETLKW (child)");
433177636Sdfr		exit(0);
434177636Sdfr	}
435177636Sdfr
436177636Sdfr	/*
437177636Sdfr	 * Wait until the child has set its lock and then perform the
438177636Sdfr	 * test.
439177636Sdfr	 */
440177636Sdfr	sleep(1);
441177636Sdfr
442177636Sdfr	/*
443180025Sdfr	 * fcntl should immediately return -1 with errno set to
444180025Sdfr	 * EDEADLK. If the alarm fires, we failed to detect the
445180025Sdfr	 * deadlock.
446177636Sdfr	 */
447180025Sdfr	alarm(1);
448177636Sdfr	printf("5 - F_SETLKW simple deadlock: ");
449177636Sdfr
450177636Sdfr	fl.l_start = 1;
451177636Sdfr	res = fcntl(fd, F_SETLKW, &fl);
452177636Sdfr	kill(pid, SIGTERM);
453177636Sdfr	safe_waitpid(pid);
454177636Sdfr
455177636Sdfr	FAIL(res == 0);
456177636Sdfr	FAIL(errno != EDEADLK);
457177636Sdfr
458177636Sdfr	fl.l_start = 0;
459177636Sdfr	fl.l_len = 0;
460177636Sdfr	fl.l_type = F_UNLCK;
461177636Sdfr	if (fcntl(fd, F_SETLK, &fl) < 0)
462177636Sdfr		err(1, "F_UNLCK");
463177636Sdfr
464180025Sdfr	/*
465180025Sdfr	 * Cancel the alarm to avoid confusing later tests.
466180025Sdfr	 */
467180025Sdfr	alarm(0);
468180025Sdfr
469177636Sdfr	SUCCEED;
470177636Sdfr}
471177636Sdfr
472177636Sdfr/*
473177636Sdfr * Test 6 - F_SETLKW complex deadlock.
474177636Sdfr *
475177636Sdfr * This test involves three process, P, C1 and C2. We set things up so
476177636Sdfr * that P locks byte zero, C1 locks byte 1 and C2 locks byte 2. We
477177636Sdfr * also block C2 by attempting to lock byte zero. Lastly, P attempts
478177636Sdfr * to lock a range including byte 1 and 2. This represents a deadlock
479177636Sdfr * (due to C2's blocking attempt to lock byte zero).
480177636Sdfr */
481177636Sdfrstatic int
482180025Sdfrtest6(int fd, __unused int argc, const __unused char **argv)
483177636Sdfr{
484177636Sdfr	/*
485177636Sdfr	 * Because our test relies on the child process being blocked
486177636Sdfr	 * on the parent's lock, we can't easily use a pipe to
487177636Sdfr	 * synchronize so we just sleep in the parent to given the
488177636Sdfr	 * children a chance to setup.
489177636Sdfr	 */
490177636Sdfr	int pid1, pid2;
491177636Sdfr	struct flock fl;
492177636Sdfr	int res;
493177636Sdfr
494177636Sdfr	/*
495177636Sdfr	 * Lock the first byte in the parent.
496177636Sdfr	 */
497177636Sdfr	fl.l_start = 0;
498177636Sdfr	fl.l_len = 1;
499177636Sdfr	fl.l_type = F_WRLCK;
500177636Sdfr	fl.l_whence = SEEK_SET;
501177636Sdfr	if (fcntl(fd, F_SETLK, &fl) < 0)
502177636Sdfr		err(1, "F_SETLK 1 (parent)");
503177636Sdfr
504177636Sdfr	pid1 = fork();
505177636Sdfr	if (pid1 < 0)
506177636Sdfr		err(1, "fork");
507177636Sdfr
508177636Sdfr	if (pid1 == 0) {
509177636Sdfr		/*
510177636Sdfr		 * C1
511177636Sdfr		 * Lock the second byte in the child and then sleep
512177636Sdfr		 */
513177636Sdfr		fl.l_start = 1;
514177636Sdfr		if (fcntl(fd, F_SETLK, &fl) < 0)
515177636Sdfr			err(1, "F_SETLK (child1)");
516177636Sdfr		pause();
517177636Sdfr		exit(0);
518177636Sdfr	}
519177636Sdfr
520177636Sdfr	pid2 = fork();
521177636Sdfr	if (pid2 < 0)
522177636Sdfr		err(1, "fork");
523177636Sdfr
524177636Sdfr	if (pid2 == 0) {
525177636Sdfr		/*
526177636Sdfr		 * C2
527177636Sdfr		 * Lock the third byte in the child and then block on
528177636Sdfr		 * the parent's lock.
529177636Sdfr		 */
530177636Sdfr		fl.l_start = 2;
531177636Sdfr		if (fcntl(fd, F_SETLK, &fl) < 0)
532177636Sdfr			err(1, "F_SETLK (child2)");
533177636Sdfr		fl.l_start = 0;
534177636Sdfr		if (fcntl(fd, F_SETLKW, &fl) < 0)
535177636Sdfr			err(1, "F_SETLKW (child2)");
536177636Sdfr		exit(0);
537177636Sdfr	}
538177636Sdfr
539177636Sdfr	/*
540177636Sdfr	 * Wait until the children have set their locks and then
541177636Sdfr	 * perform the test.
542177636Sdfr	 */
543177636Sdfr	sleep(1);
544177636Sdfr
545177636Sdfr	/*
546177636Sdfr	 * fcntl should immediately return -1 with errno set to
547177636Sdfr	 * EDEADLK. If the alarm fires, we failed to detect the
548177636Sdfr	 * deadlock.
549177636Sdfr	 */
550177636Sdfr	alarm(1);
551177636Sdfr	printf("6 - F_SETLKW complex deadlock: ");
552177636Sdfr
553177636Sdfr	fl.l_start = 1;
554177636Sdfr	fl.l_len = 2;
555177636Sdfr	res = fcntl(fd, F_SETLKW, &fl);
556177636Sdfr	kill(pid1, SIGTERM);
557177636Sdfr	safe_waitpid(pid1);
558177636Sdfr	kill(pid2, SIGTERM);
559177636Sdfr	safe_waitpid(pid2);
560177636Sdfr
561177636Sdfr	fl.l_start = 0;
562177636Sdfr	fl.l_len = 0;
563177636Sdfr	fl.l_type = F_UNLCK;
564177636Sdfr	if (fcntl(fd, F_SETLK, &fl) < 0)
565177636Sdfr		err(1, "F_UNLCK");
566177636Sdfr
567177636Sdfr	FAIL(res == 0);
568177636Sdfr	FAIL(errno != EDEADLK);
569177636Sdfr
570177636Sdfr	/*
571177636Sdfr	 * Cancel the alarm to avoid confusing later tests.
572177636Sdfr	 */
573177636Sdfr	alarm(0);
574177636Sdfr
575177636Sdfr	SUCCEED;
576177636Sdfr}
577177636Sdfr
578177636Sdfr/*
579177636Sdfr * Test 7 - F_SETLK shared lock on exclusive locked region
580177636Sdfr *
581177636Sdfr * If a shared or exclusive lock cannot be set, fcntl returns
582177636Sdfr * immediately with EACCES or EAGAIN.
583177636Sdfr */
584177636Sdfrstatic int
585180025Sdfrtest7(int fd, __unused int argc, const __unused char **argv)
586177636Sdfr{
587177636Sdfr	/*
588177636Sdfr	 * We create a child process to hold the lock which we will
589177636Sdfr	 * test. We use a pipe to communicate with the child.
590177636Sdfr	 */
591177636Sdfr	int pid;
592177636Sdfr	int pfd[2];
593177636Sdfr	struct flock fl;
594177636Sdfr	char ch;
595177636Sdfr	int res;
596177636Sdfr
597177636Sdfr	if (pipe(pfd) < 0)
598177636Sdfr		err(1, "pipe");
599177636Sdfr
600177636Sdfr	fl.l_start = 0;
601177636Sdfr	fl.l_len = 0;
602177636Sdfr	fl.l_type = F_WRLCK;
603177636Sdfr	fl.l_whence = SEEK_SET;
604177636Sdfr
605177636Sdfr	pid = fork();
606177636Sdfr	if (pid < 0)
607177636Sdfr		err(1, "fork");
608177636Sdfr
609177636Sdfr	if (pid == 0) {
610177636Sdfr		/*
611177636Sdfr		 * We are the child. We set a write lock and then
612177636Sdfr		 * write one byte back to the parent to tell it. The
613177636Sdfr		 * parent will kill us when its done.
614177636Sdfr		 */
615177636Sdfr		if (fcntl(fd, F_SETLK, &fl) < 0)
616177636Sdfr			err(1, "F_SETLK (child)");
617177636Sdfr		if (write(pfd[1], "a", 1) < 0)
618177636Sdfr			err(1, "writing to pipe (child)");
619177636Sdfr		pause();
620177636Sdfr		exit(0);
621177636Sdfr	}
622177636Sdfr
623177636Sdfr	/*
624177636Sdfr	 * Wait until the child has set its lock and then perform the
625177636Sdfr	 * test.
626177636Sdfr	 */
627177636Sdfr	if (read(pfd[0], &ch, 1) != 1)
628177636Sdfr		err(1, "reading from pipe (child)");
629177636Sdfr
630177636Sdfr	/*
631177636Sdfr	 * fcntl should wait until the alarm and then return -1 with
632177636Sdfr	 * errno set to EINTR.
633177636Sdfr	 */
634177636Sdfr	printf("7 - F_SETLK shared lock on exclusive locked region: ");
635177636Sdfr
636177636Sdfr	fl.l_type = F_RDLCK;
637177636Sdfr	res = fcntl(fd, F_SETLK, &fl);
638177636Sdfr	kill(pid, SIGTERM);
639177636Sdfr	safe_waitpid(pid);
640177636Sdfr	close(pfd[0]);
641177636Sdfr	close(pfd[1]);
642177636Sdfr
643177636Sdfr	FAIL(res == 0);
644177636Sdfr	FAIL(errno != EACCES && errno != EAGAIN);
645177636Sdfr
646177636Sdfr	SUCCEED;
647177636Sdfr}
648177636Sdfr
649177636Sdfr/*
650177636Sdfr * Test 8 - F_SETLK shared lock on share locked region
651177636Sdfr *
652177636Sdfr * When a shared lock is set on a segment of a file, other processes
653177636Sdfr * shall be able to set shared locks on that segment or a portion of
654177636Sdfr * it.
655177636Sdfr */
656177636Sdfrstatic int
657180025Sdfrtest8(int fd, __unused int argc, const __unused char **argv)
658177636Sdfr{
659177636Sdfr	/*
660177636Sdfr	 * We create a child process to hold the lock which we will
661177636Sdfr	 * test. We use a pipe to communicate with the child.
662177636Sdfr	 */
663177636Sdfr	int pid;
664177636Sdfr	int pfd[2];
665177636Sdfr	struct flock fl;
666177636Sdfr	char ch;
667177636Sdfr	int res;
668177636Sdfr
669177636Sdfr	if (pipe(pfd) < 0)
670177636Sdfr		err(1, "pipe");
671177636Sdfr
672177636Sdfr	fl.l_start = 0;
673177636Sdfr	fl.l_len = 0;
674177636Sdfr	fl.l_type = F_RDLCK;
675177636Sdfr	fl.l_whence = SEEK_SET;
676177636Sdfr
677177636Sdfr	pid = fork();
678177636Sdfr	if (pid < 0)
679177636Sdfr		err(1, "fork");
680177636Sdfr
681177636Sdfr	if (pid == 0) {
682177636Sdfr		/*
683177636Sdfr		 * We are the child. We set a write lock and then
684177636Sdfr		 * write one byte back to the parent to tell it. The
685177636Sdfr		 * parent will kill us when its done.
686177636Sdfr		 */
687177636Sdfr		if (fcntl(fd, F_SETLK, &fl) < 0)
688177636Sdfr			err(1, "F_SETLK (child)");
689177636Sdfr		if (write(pfd[1], "a", 1) < 0)
690177636Sdfr			err(1, "writing to pipe (child)");
691177636Sdfr		pause();
692177636Sdfr		exit(0);
693177636Sdfr	}
694177636Sdfr
695177636Sdfr	/*
696177636Sdfr	 * Wait until the child has set its lock and then perform the
697177636Sdfr	 * test.
698177636Sdfr	 */
699177636Sdfr	if (read(pfd[0], &ch, 1) != 1)
700177636Sdfr		err(1, "reading from pipe (child)");
701177636Sdfr
702177636Sdfr	/*
703177636Sdfr	 * fcntl should wait until the alarm and then return -1 with
704177636Sdfr	 * errno set to EINTR.
705177636Sdfr	 */
706177636Sdfr	printf("8 - F_SETLK shared lock on share locked region: ");
707177636Sdfr
708177636Sdfr	fl.l_type = F_RDLCK;
709177636Sdfr	res = fcntl(fd, F_SETLK, &fl);
710177636Sdfr
711177636Sdfr	kill(pid, SIGTERM);
712177636Sdfr	safe_waitpid(pid);
713177636Sdfr	close(pfd[0]);
714177636Sdfr	close(pfd[1]);
715177636Sdfr
716177636Sdfr	fl.l_start = 0;
717177636Sdfr	fl.l_len = 0;
718177636Sdfr	fl.l_type = F_UNLCK;
719177636Sdfr	if (fcntl(fd, F_SETLK, &fl) < 0)
720177636Sdfr		err(1, "F_UNLCK");
721177636Sdfr
722177636Sdfr	FAIL(res != 0);
723177636Sdfr
724177636Sdfr	SUCCEED;
725177636Sdfr}
726177636Sdfr
727177636Sdfr/*
728177636Sdfr * Test 9 - F_SETLK exclusive lock on share locked region
729177636Sdfr *
730177636Sdfr * If a shared or exclusive lock cannot be set, fcntl returns
731177636Sdfr * immediately with EACCES or EAGAIN.
732177636Sdfr */
733177636Sdfrstatic int
734180025Sdfrtest9(int fd, __unused int argc, const __unused char **argv)
735177636Sdfr{
736177636Sdfr	/*
737177636Sdfr	 * We create a child process to hold the lock which we will
738177636Sdfr	 * test. We use a pipe to communicate with the child.
739177636Sdfr	 */
740177636Sdfr	int pid;
741177636Sdfr	int pfd[2];
742177636Sdfr	struct flock fl;
743177636Sdfr	char ch;
744177636Sdfr	int res;
745177636Sdfr
746177636Sdfr	if (pipe(pfd) < 0)
747177636Sdfr		err(1, "pipe");
748177636Sdfr
749177636Sdfr	fl.l_start = 0;
750177636Sdfr	fl.l_len = 0;
751177636Sdfr	fl.l_type = F_RDLCK;
752177636Sdfr	fl.l_whence = SEEK_SET;
753177636Sdfr
754177636Sdfr	pid = fork();
755177636Sdfr	if (pid < 0)
756177636Sdfr		err(1, "fork");
757177636Sdfr
758177636Sdfr	if (pid == 0) {
759177636Sdfr		/*
760177636Sdfr		 * We are the child. We set a write lock and then
761177636Sdfr		 * write one byte back to the parent to tell it. The
762177636Sdfr		 * parent will kill us when its done.
763177636Sdfr		 */
764177636Sdfr		if (fcntl(fd, F_SETLK, &fl) < 0)
765177636Sdfr			err(1, "F_SETLK (child)");
766177636Sdfr		if (write(pfd[1], "a", 1) < 0)
767177636Sdfr			err(1, "writing to pipe (child)");
768177636Sdfr		pause();
769177636Sdfr		exit(0);
770177636Sdfr	}
771177636Sdfr
772177636Sdfr	/*
773177636Sdfr	 * Wait until the child has set its lock and then perform the
774177636Sdfr	 * test.
775177636Sdfr	 */
776177636Sdfr	if (read(pfd[0], &ch, 1) != 1)
777177636Sdfr		err(1, "reading from pipe (child)");
778177636Sdfr
779177636Sdfr	/*
780177636Sdfr	 * fcntl should wait until the alarm and then return -1 with
781177636Sdfr	 * errno set to EINTR.
782177636Sdfr	 */
783177636Sdfr	printf("9 - F_SETLK exclusive lock on share locked region: ");
784177636Sdfr
785177636Sdfr	fl.l_type = F_WRLCK;
786177636Sdfr	res = fcntl(fd, F_SETLK, &fl);
787177636Sdfr	kill(pid, SIGTERM);
788177636Sdfr	safe_waitpid(pid);
789177636Sdfr	close(pfd[0]);
790177636Sdfr	close(pfd[1]);
791177636Sdfr
792177636Sdfr	FAIL(res == 0);
793177636Sdfr	FAIL(errno != EACCES && errno != EAGAIN);
794177636Sdfr
795177636Sdfr	SUCCEED;
796177636Sdfr}
797177636Sdfr
798177636Sdfr/*
799177636Sdfr * Test 10 - trying to set bogus pid or sysid values
800177636Sdfr *
801177636Sdfr * The l_pid and l_sysid fields are only used with F_GETLK to return
802177636Sdfr * the process ID of the process holding a blocking lock and the
803177636Sdfr * system ID of the system that owns that process
804177636Sdfr */
805177636Sdfrstatic int
806180025Sdfrtest10(int fd, __unused int argc, const __unused char **argv)
807177636Sdfr{
808177636Sdfr	/*
809177636Sdfr	 * We create a child process to hold the lock which we will
810177636Sdfr	 * test. We use a pipe to communicate with the child.
811177636Sdfr	 */
812177636Sdfr	int pid;
813177636Sdfr	int pfd[2];
814177636Sdfr	struct flock fl;
815177636Sdfr	char ch;
816177636Sdfr
817177636Sdfr	if (pipe(pfd) < 0)
818177636Sdfr		err(1, "pipe");
819177636Sdfr
820177636Sdfr	fl.l_start = 0;
821177636Sdfr	fl.l_len = 0;
822177636Sdfr	fl.l_type = F_WRLCK;
823177636Sdfr	fl.l_whence = SEEK_SET;
824177636Sdfr	fl.l_pid = 9999;
825177636Sdfr#ifdef HAVE_SYSID
826177636Sdfr	fl.l_sysid = 9999;
827177636Sdfr#endif
828177636Sdfr
829177636Sdfr	pid = fork();
830177636Sdfr	if (pid < 0)
831177636Sdfr		err(1, "fork");
832177636Sdfr
833177636Sdfr	if (pid == 0) {
834177636Sdfr		/*
835177636Sdfr		 * We are the child. We set a write lock and then
836177636Sdfr		 * write one byte back to the parent to tell it. The
837177636Sdfr		 * parent will kill us when its done.
838177636Sdfr		 */
839177636Sdfr		if (fcntl(fd, F_SETLK, &fl) < 0)
840177636Sdfr			err(1, "F_SETLK (child)");
841177636Sdfr		if (write(pfd[1], "a", 1) < 0)
842177636Sdfr			err(1, "writing to pipe (child)");
843177636Sdfr		pause();
844177636Sdfr		exit(0);
845177636Sdfr	}
846177636Sdfr
847177636Sdfr	/*
848177636Sdfr	 * Wait until the child has set its lock and then perform the
849177636Sdfr	 * test.
850177636Sdfr	 */
851177636Sdfr	if (read(pfd[0], &ch, 1) != 1)
852177636Sdfr		err(1, "reading from pipe (child)");
853177636Sdfr
854177636Sdfr	printf("10 - trying to set bogus pid or sysid values: ");
855177636Sdfr
856177636Sdfr	if (fcntl(fd, F_GETLK, &fl) < 0)
857177636Sdfr		err(1, "F_GETLK");
858177636Sdfr
859177636Sdfr	kill(pid, SIGTERM);
860177636Sdfr	safe_waitpid(pid);
861177636Sdfr	close(pfd[0]);
862177636Sdfr	close(pfd[1]);
863177636Sdfr
864177636Sdfr	FAIL(fl.l_pid != pid);
865177636Sdfr#ifdef HAVE_SYSID
866177636Sdfr	FAIL(fl.l_sysid != 0);
867177636Sdfr#endif
868177636Sdfr
869177636Sdfr	SUCCEED;
870177636Sdfr}
871177636Sdfr
872177636Sdfr/*
873177636Sdfr * Test 11 - remote locks
874177636Sdfr *
875177636Sdfr * XXX temporary interface which will be removed when the kernel lockd
876177636Sdfr * is added.
877177636Sdfr */
878177636Sdfrstatic int
879180025Sdfrtest11(int fd, __unused int argc, const __unused char **argv)
880177636Sdfr{
881177636Sdfr#ifdef F_SETLK_REMOTE
882177636Sdfr	struct flock fl;
883177636Sdfr	int res;
884177636Sdfr
885177636Sdfr	if (geteuid() != 0)
886177636Sdfr		return 0;
887177636Sdfr
888177636Sdfr	fl.l_start = 0;
889177636Sdfr	fl.l_len = 0;
890177636Sdfr	fl.l_type = F_WRLCK;
891177636Sdfr	fl.l_whence = SEEK_SET;
892177636Sdfr	fl.l_pid = 9999;
893177636Sdfr	fl.l_sysid = 1001;
894177636Sdfr
895177636Sdfr	printf("11 - remote locks: ");
896177636Sdfr
897177636Sdfr	res = fcntl(fd, F_SETLK_REMOTE, &fl);
898177636Sdfr	FAIL(res != 0);
899177636Sdfr
900177636Sdfr	fl.l_sysid = 1002;
901177636Sdfr	res = fcntl(fd, F_SETLK_REMOTE, &fl);
902177636Sdfr	FAIL(res == 0);
903177636Sdfr	FAIL(errno != EACCES && errno != EAGAIN);
904177636Sdfr
905177636Sdfr	res = fcntl(fd, F_GETLK, &fl);
906177636Sdfr	FAIL(res != 0);
907177636Sdfr	FAIL(fl.l_pid != 9999);
908177636Sdfr	FAIL(fl.l_sysid != 1001);
909177636Sdfr
910177636Sdfr	fl.l_type = F_UNLCK;
911177636Sdfr	fl.l_sysid = 1001;
912177636Sdfr	fl.l_start = 0;
913177636Sdfr	fl.l_len = 0;
914177636Sdfr	res = fcntl(fd, F_SETLK_REMOTE, &fl);
915177636Sdfr	FAIL(res != 0);
916177636Sdfr
917177636Sdfr	fl.l_pid = 1234;
918177636Sdfr	fl.l_sysid = 1001;
919177636Sdfr	fl.l_start = 0;
920177636Sdfr	fl.l_len = 1;
921177636Sdfr	fl.l_whence = SEEK_SET;
922177636Sdfr	fl.l_type = F_RDLCK;
923177636Sdfr	res = fcntl(fd, F_SETLK_REMOTE, &fl);
924177636Sdfr	FAIL(res != 0);
925177636Sdfr
926177636Sdfr	fl.l_sysid = 1002;
927177636Sdfr	res = fcntl(fd, F_SETLK_REMOTE, &fl);
928177636Sdfr	FAIL(res != 0);
929177636Sdfr
930177636Sdfr	fl.l_type = F_UNLCKSYS;
931177636Sdfr	fl.l_sysid = 1001;
932177636Sdfr	res = fcntl(fd, F_SETLK_REMOTE, &fl);
933177636Sdfr	FAIL(res != 0);
934177636Sdfr
935177636Sdfr	fl.l_type = F_WRLCK;
936177636Sdfr	res = fcntl(fd, F_GETLK, &fl);
937177636Sdfr	FAIL(res != 0);
938177636Sdfr	FAIL(fl.l_pid != 1234);
939177636Sdfr	FAIL(fl.l_sysid != 1002);
940177636Sdfr
941177636Sdfr	fl.l_type = F_UNLCKSYS;
942177636Sdfr	fl.l_sysid = 1002;
943177636Sdfr	res = fcntl(fd, F_SETLK_REMOTE, &fl);
944177636Sdfr	FAIL(res != 0);
945177636Sdfr
946177636Sdfr	SUCCEED;
947177636Sdfr#else
948177636Sdfr	return 0;
949177636Sdfr#endif
950177636Sdfr}
951177636Sdfr
952177636Sdfr/*
953177636Sdfr * Test 12 - F_SETLKW on locked region which is then unlocked
954177636Sdfr *
955177636Sdfr * If a shared or exclusive lock is blocked by other locks, the
956177636Sdfr * process waits until the request can be satisfied.
957177636Sdfr */
958177636Sdfrstatic int
959180025Sdfrtest12(int fd, __unused int argc, const __unused char **argv)
960177636Sdfr{
961177636Sdfr	/*
962177636Sdfr	 * We create a child process to hold the lock which we will
963177636Sdfr	 * test. We use a pipe to communicate with the child.
964177636Sdfr	 */
965177636Sdfr	int pid;
966177636Sdfr	int pfd[2];
967177636Sdfr	struct flock fl;
968177636Sdfr	char ch;
969177636Sdfr	int res;
970177636Sdfr
971177636Sdfr	if (pipe(pfd) < 0)
972177636Sdfr		err(1, "pipe");
973177636Sdfr
974177636Sdfr	fl.l_start = 0;
975177636Sdfr	fl.l_len = 0;
976177636Sdfr	fl.l_type = F_WRLCK;
977177636Sdfr	fl.l_whence = SEEK_SET;
978177636Sdfr
979177636Sdfr	pid = fork();
980177636Sdfr	if (pid < 0)
981177636Sdfr		err(1, "fork");
982177636Sdfr
983177636Sdfr	if (pid == 0) {
984177636Sdfr		/*
985177636Sdfr		 * We are the child. We set a write lock and then
986177636Sdfr		 * write one byte back to the parent to tell it. The
987177636Sdfr		 * parent will kill us when its done.
988177636Sdfr		 */
989177636Sdfr		if (fcntl(fd, F_SETLK, &fl) < 0)
990177636Sdfr			err(1, "F_SETLK (child)");
991177636Sdfr		if (write(pfd[1], "a", 1) < 0)
992177636Sdfr			err(1, "writing to pipe (child)");
993177636Sdfr
994177636Sdfr		sleep(1);
995177636Sdfr		exit(0);
996177636Sdfr	}
997177636Sdfr
998177636Sdfr	/*
999177636Sdfr	 * Wait until the child has set its lock and then perform the
1000177636Sdfr	 * test.
1001177636Sdfr	 */
1002177636Sdfr	if (read(pfd[0], &ch, 1) != 1)
1003177636Sdfr		err(1, "reading from pipe (child)");
1004177636Sdfr
1005177636Sdfr	/*
1006177636Sdfr	 * fcntl should wait until the alarm and then return -1 with
1007177636Sdfr	 * errno set to EINTR.
1008177636Sdfr	 */
1009177636Sdfr	printf("12 - F_SETLKW on locked region which is then unlocked: ");
1010177636Sdfr
1011177636Sdfr	//alarm(1);
1012177636Sdfr
1013177636Sdfr	res = fcntl(fd, F_SETLKW, &fl);
1014177636Sdfr	kill(pid, SIGTERM);
1015177636Sdfr	safe_waitpid(pid);
1016177636Sdfr	close(pfd[0]);
1017177636Sdfr	close(pfd[1]);
1018177636Sdfr	FAIL(res != 0);
1019177636Sdfr
1020177636Sdfr	fl.l_start = 0;
1021177636Sdfr	fl.l_len = 0;
1022177636Sdfr	fl.l_type = F_UNLCK;
1023177636Sdfr	if (fcntl(fd, F_SETLK, &fl) < 0)
1024177636Sdfr		err(1, "F_UNLCK");
1025177636Sdfr
1026177636Sdfr	SUCCEED;
1027177636Sdfr}
1028177636Sdfr
1029177636Sdfr/*
1030177636Sdfr * Test 13 - F_SETLKW on locked region, race with owner
1031177636Sdfr *
1032177636Sdfr * If a shared or exclusive lock is blocked by other locks, the
1033177636Sdfr * process waits until the request can be satisfied.
1034177636Sdfr */
1035177636Sdfrstatic int
1036180025Sdfrtest13(int fd, __unused int argc, const __unused char **argv)
1037177636Sdfr{
1038177636Sdfr	/*
1039177636Sdfr	 * We create a child process to hold the lock which we will
1040177636Sdfr	 * test. We use a pipe to communicate with the child.
1041177636Sdfr	 */
1042177636Sdfr	int i;
1043177636Sdfr	int pid;
1044177636Sdfr	int pfd[2];
1045177636Sdfr	struct flock fl;
1046177636Sdfr	char ch;
1047177636Sdfr	int res;
1048177636Sdfr	struct itimerval itv;
1049177636Sdfr
1050177636Sdfr	printf("13 - F_SETLKW on locked region, race with owner: ");
1051177636Sdfr	fflush(stdout);
1052177636Sdfr
1053177636Sdfr	for (i = 0; i < 100; i++) {
1054177636Sdfr		if (pipe(pfd) < 0)
1055177636Sdfr			err(1, "pipe");
1056177636Sdfr
1057177636Sdfr		fl.l_start = 0;
1058177636Sdfr		fl.l_len = 0;
1059177636Sdfr		fl.l_type = F_WRLCK;
1060177636Sdfr		fl.l_whence = SEEK_SET;
1061177636Sdfr
1062177636Sdfr		pid = fork();
1063177636Sdfr		if (pid < 0)
1064177636Sdfr			err(1, "fork");
1065177636Sdfr
1066177636Sdfr		if (pid == 0) {
1067177636Sdfr			/*
1068177636Sdfr			 * We are the child. We set a write lock and then
1069177636Sdfr			 * write one byte back to the parent to tell it. The
1070177636Sdfr			 * parent will kill us when its done.
1071177636Sdfr			 */
1072177636Sdfr			if (fcntl(fd, F_SETLK, &fl) < 0)
1073177636Sdfr				err(1, "F_SETLK (child)");
1074177636Sdfr			if (write(pfd[1], "a", 1) < 0)
1075177636Sdfr				err(1, "writing to pipe (child)");
1076177636Sdfr
1077177636Sdfr			usleep(1);
1078177636Sdfr			exit(0);
1079177636Sdfr		}
1080177636Sdfr
1081177636Sdfr		/*
1082177636Sdfr		 * Wait until the child has set its lock and then perform the
1083177636Sdfr		 * test.
1084177636Sdfr		 */
1085177636Sdfr		while (read(pfd[0], &ch, 1) != 1) {
1086177636Sdfr			if (errno == EINTR)
1087177636Sdfr				continue;
1088177636Sdfr			err(1, "reading from pipe (child)");
1089177636Sdfr		}
1090177636Sdfr
1091177636Sdfr		/*
1092177636Sdfr		 * fcntl should wait until the alarm and then return -1 with
1093177636Sdfr		 * errno set to EINTR.
1094177636Sdfr		 */
1095177636Sdfr		itv.it_interval.tv_sec = 0;
1096177636Sdfr		itv.it_interval.tv_usec = 0;
1097177636Sdfr		itv.it_value.tv_sec = 0;
1098177636Sdfr		itv.it_value.tv_usec = 2;
1099177636Sdfr		setitimer(ITIMER_REAL, &itv, NULL);
1100177636Sdfr
1101177636Sdfr		res = fcntl(fd, F_SETLKW, &fl);
1102177636Sdfr		kill(pid, SIGTERM);
1103177636Sdfr		safe_waitpid(pid);
1104177636Sdfr		close(pfd[0]);
1105177636Sdfr		close(pfd[1]);
1106177636Sdfr		FAIL(!(res == 0 || (res == -1 && errno == EINTR)));
1107177636Sdfr
1108177636Sdfr		fl.l_start = 0;
1109177636Sdfr		fl.l_len = 0;
1110177636Sdfr		fl.l_type = F_UNLCK;
1111177636Sdfr		if (fcntl(fd, F_SETLK, &fl) < 0)
1112177636Sdfr			err(1, "F_UNLCK");
1113177636Sdfr	}
1114177636Sdfr	SUCCEED;
1115177636Sdfr}
1116177636Sdfr
1117177636Sdfr/*
1118177636Sdfr * Test 14 - soak test
1119177636Sdfr */
1120177636Sdfrstatic int
1121180025Sdfrtest14(int fd, int argc, const char **argv)
1122177636Sdfr{
1123177636Sdfr#define CHILD_COUNT 20
1124177636Sdfr	/*
1125177636Sdfr	 * We create a set of child processes and let each one run
1126177636Sdfr	 * through a random sequence of locks and unlocks.
1127177636Sdfr	 */
1128180025Sdfr	int i, j, id, id_base;
1129177636Sdfr	int pids[CHILD_COUNT], pid;
1130177636Sdfr	char buf[128];
1131177636Sdfr	char tbuf[128];
1132177636Sdfr	int map[128];
1133177636Sdfr	char outbuf[512];
1134177636Sdfr	struct flock fl;
1135177636Sdfr	struct itimerval itv;
1136177636Sdfr	int status;
1137177636Sdfr
1138180025Sdfr	id_base = 0;
1139180025Sdfr	if (argc >= 2)
1140180025Sdfr		id_base = strtol(argv[1], NULL, 0);
1141180025Sdfr
1142177636Sdfr	printf("14 - soak test: ");
1143177636Sdfr	fflush(stdout);
1144177636Sdfr
1145177636Sdfr	for (i = 0; i < 128; i++)
1146177636Sdfr		map[i] = F_UNLCK;
1147177636Sdfr
1148177636Sdfr	for (i = 0; i < CHILD_COUNT; i++) {
1149177636Sdfr
1150177636Sdfr		pid = fork();
1151177636Sdfr		if (pid < 0)
1152177636Sdfr			err(1, "fork");
1153177636Sdfr		if (pid) {
1154177636Sdfr			/*
1155177636Sdfr			 * Parent - record the pid and continue.
1156177636Sdfr			 */
1157177636Sdfr			pids[i] = pid;
1158177636Sdfr			continue;
1159177636Sdfr		}
1160177636Sdfr
1161177636Sdfr		/*
1162177636Sdfr		 * Child - do some work and exit.
1163177636Sdfr		 */
1164180025Sdfr		id = id_base + i;
1165180025Sdfr		srandom(getpid());
1166177636Sdfr
1167177636Sdfr		for (j = 0; j < 50; j++) {
1168177636Sdfr			int start, end, len;
1169177636Sdfr			int set, wrlock;
1170177636Sdfr
1171177636Sdfr			do {
1172177636Sdfr				start = random() & 127;
1173177636Sdfr				end = random() & 127;
1174177636Sdfr			} while (end <= start);
1175177636Sdfr
1176177636Sdfr			set = random() & 1;
1177177636Sdfr			wrlock = random() & 1;
1178177636Sdfr
1179177636Sdfr			len = end - start;
1180177636Sdfr			fl.l_start = start;
1181177636Sdfr			fl.l_len = len;
1182177636Sdfr			fl.l_whence = SEEK_SET;
1183177636Sdfr			if (set)
1184177636Sdfr				fl.l_type = wrlock ? F_WRLCK : F_RDLCK;
1185177636Sdfr			else
1186177636Sdfr				fl.l_type = F_UNLCK;
1187177636Sdfr
1188177636Sdfr			itv.it_interval.tv_sec = 0;
1189177636Sdfr			itv.it_interval.tv_usec = 0;
1190177636Sdfr			itv.it_value.tv_sec = 0;
1191177636Sdfr			itv.it_value.tv_usec = 3000;
1192177636Sdfr			setitimer(ITIMER_REAL, &itv, NULL);
1193177636Sdfr
1194177636Sdfr			if (fcntl(fd, F_SETLKW, &fl) < 0) {
1195177636Sdfr				if (errno == EDEADLK || errno == EINTR) {
1196177636Sdfr					if (verbose) {
1197177636Sdfr						snprintf(outbuf, sizeof(outbuf),
1198177636Sdfr						    "%d[%d]: %s [%d .. %d] %s\n",
1199177636Sdfr						    id, j,
1200177636Sdfr						    set ? (wrlock ? "write lock"
1201177636Sdfr							: "read lock")
1202177636Sdfr						    : "unlock", start, end,
1203177636Sdfr						    errno == EDEADLK
1204177636Sdfr						    ? "deadlock"
1205177636Sdfr						    : "interrupted");
1206177636Sdfr						write(1, outbuf,
1207177636Sdfr						    strlen(outbuf));
1208177636Sdfr					}
1209177636Sdfr					continue;
1210177636Sdfr				} else {
1211177636Sdfr					perror("fcntl");
1212177636Sdfr				}
1213177636Sdfr			}
1214177636Sdfr
1215177636Sdfr			itv.it_interval.tv_sec = 0;
1216177636Sdfr			itv.it_interval.tv_usec = 0;
1217177636Sdfr			itv.it_value.tv_sec = 0;
1218177636Sdfr			itv.it_value.tv_usec = 0;
1219177636Sdfr			setitimer(ITIMER_REAL, &itv, NULL);
1220177636Sdfr
1221177636Sdfr			if (verbose) {
1222177636Sdfr				snprintf(outbuf, sizeof(outbuf),
1223177636Sdfr				    "%d[%d]: %s [%d .. %d] succeeded\n",
1224177636Sdfr				    id, j,
1225177636Sdfr				    set ? (wrlock ? "write lock" : "read lock")
1226177636Sdfr				    : "unlock", start, end);
1227177636Sdfr				write(1, outbuf, strlen(outbuf));
1228177636Sdfr			}
1229177636Sdfr
1230177636Sdfr			if (set) {
1231177636Sdfr				if (wrlock) {
1232177636Sdfr					/*
1233177636Sdfr					 * We got a write lock - write
1234177636Sdfr					 * our ID to each byte that we
1235177636Sdfr					 * managed to claim.
1236177636Sdfr					 */
1237177636Sdfr					for (i = start; i < end; i++)
1238177636Sdfr						map[i] = F_WRLCK;
1239177636Sdfr					memset(&buf[start], id, len);
1240177636Sdfr					if (pwrite(fd, &buf[start], len,
1241177636Sdfr						start) != len) {
1242177636Sdfr						printf("%d: short write\n", id);
1243177636Sdfr						exit(1);
1244177636Sdfr					}
1245177636Sdfr				} else {
1246177636Sdfr					/*
1247177636Sdfr					 * We got a read lock - read
1248177636Sdfr					 * the bytes which we claimed
1249177636Sdfr					 * so that we can check that
1250177636Sdfr					 * they don't change
1251177636Sdfr					 * unexpectedly.
1252177636Sdfr					 */
1253177636Sdfr					for (i = start; i < end; i++)
1254177636Sdfr						map[i] = F_RDLCK;
1255177636Sdfr					if (pread(fd, &buf[start], len,
1256177636Sdfr						start) != len) {
1257177636Sdfr						printf("%d: short read\n", id);
1258177636Sdfr						exit(1);
1259177636Sdfr					}
1260177636Sdfr				}
1261177636Sdfr			} else {
1262177636Sdfr				for (i = start; i < end; i++)
1263177636Sdfr					map[i] = F_UNLCK;
1264177636Sdfr			}
1265177636Sdfr
1266177636Sdfr			usleep(1000);
1267177636Sdfr
1268177636Sdfr			/*
1269177636Sdfr			 * Read back the whole region so that we can
1270177636Sdfr			 * check that all the bytes we have some kind
1271177636Sdfr			 * of claim to have the correct value.
1272177636Sdfr			 */
1273177636Sdfr			if (pread(fd, tbuf, sizeof(tbuf), 0) != sizeof(tbuf)) {
1274177636Sdfr				printf("%d: short read\n", id);
1275177636Sdfr				exit(1);
1276177636Sdfr			}
1277177636Sdfr
1278177636Sdfr			for (i = 0; i < 128; i++) {
1279177636Sdfr				if (map[i] != F_UNLCK && buf[i] != tbuf[i]) {
1280177636Sdfr					snprintf(outbuf, sizeof(outbuf),
1281177636Sdfr					    "%d: byte %d expected %d, "
1282177636Sdfr					    "got %d\n", id, i, buf[i], tbuf[i]);
1283177636Sdfr					write(1, outbuf, strlen(outbuf));
1284177636Sdfr					exit(1);
1285177636Sdfr				}
1286177636Sdfr			}
1287177636Sdfr		}
1288177636Sdfr		if (verbose)
1289177636Sdfr			printf("%d[%d]: done\n", id, j);
1290177636Sdfr
1291177636Sdfr		exit(0);
1292177636Sdfr	}
1293177636Sdfr
1294177636Sdfr	status = 0;
1295177636Sdfr	for (i = 0; i < CHILD_COUNT; i++) {
1296177636Sdfr		status += safe_waitpid(pids[i]);
1297177636Sdfr	}
1298177636Sdfr	if (status)
1299177636Sdfr		FAIL(status != 0);
1300177636Sdfr
1301177636Sdfr	SUCCEED;
1302177636Sdfr}
1303177636Sdfr
1304180025Sdfr/*
1305180025Sdfr * Test 15 - flock(2) semantcs
1306180025Sdfr *
1307180025Sdfr * When a lock holder has a shared lock and attempts to upgrade that
1308180025Sdfr * shared lock to exclusive, it must drop the shared lock before
1309180025Sdfr * blocking on the exclusive lock.
1310180025Sdfr *
1311180025Sdfr * To test this, we first arrange for two shared locks on the file,
1312180025Sdfr * and then attempt to upgrade one of them to exclusive. This should
1313180025Sdfr * drop one of the shared locks and block. We interrupt the blocking
1314180025Sdfr * lock request and examine the lock state of the file after dropping
1315180025Sdfr * the other shared lock - there should be no active locks at this
1316180025Sdfr * point.
1317180025Sdfr */
1318180025Sdfrstatic int
1319180025Sdfrtest15(int fd, __unused int argc, const __unused char **argv)
1320180025Sdfr{
1321180025Sdfr#ifdef LOCK_EX
1322180025Sdfr	/*
1323180025Sdfr	 * We create a child process to hold the lock which we will
1324180025Sdfr	 * test. We use a pipe to communicate with the child.
1325180025Sdfr	 *
1326180025Sdfr	 * Since we only have one file descriptors and lock ownership
1327180025Sdfr	 * for flock(2) goes with the file descriptor, we use fcntl to
1328180025Sdfr	 * set the child's shared lock.
1329180025Sdfr	 */
1330180025Sdfr	int pid;
1331180025Sdfr	int pfd[2];
1332180025Sdfr	int fd2;
1333180025Sdfr	struct flock fl;
1334180025Sdfr	char ch;
1335180025Sdfr	int res;
1336180025Sdfr
1337180025Sdfr	if (pipe(pfd) < 0)
1338180025Sdfr		err(1, "pipe");
1339180025Sdfr
1340180025Sdfr	pid = fork();
1341180025Sdfr	if (pid < 0)
1342180025Sdfr		err(1, "fork");
1343180025Sdfr
1344180025Sdfr	if (pid == 0) {
1345180025Sdfr		/*
1346180025Sdfr		 * We are the child. We set a shared lock and then
1347180025Sdfr		 * write one byte back to the parent to tell it. The
1348180025Sdfr		 * parent will kill us when its done.
1349180025Sdfr		 */
1350180025Sdfr		fl.l_start = 0;
1351180025Sdfr		fl.l_len = 0;
1352180025Sdfr		fl.l_type = F_RDLCK;
1353180025Sdfr		fl.l_whence = SEEK_SET;
1354180025Sdfr		if (fcntl(fd, F_SETLK, &fl) < 0)
1355180025Sdfr			err(1, "fcntl(F_SETLK) (child)");
1356180025Sdfr		if (write(pfd[1], "a", 1) < 0)
1357180025Sdfr			err(1, "writing to pipe (child)");
1358180025Sdfr		pause();
1359180025Sdfr		exit(0);
1360180025Sdfr	}
1361180025Sdfr
1362180025Sdfr	/*
1363180025Sdfr	 * Wait until the child has set its lock and then perform the
1364180025Sdfr	 * test.
1365180025Sdfr	 */
1366180025Sdfr	if (read(pfd[0], &ch, 1) != 1)
1367180025Sdfr		err(1, "reading from pipe (child)");
1368180025Sdfr
1369180025Sdfr	fd2 = dup(fd);
1370180025Sdfr	if (flock(fd, LOCK_SH) < 0)
1371180025Sdfr		err(1, "flock shared");
1372180025Sdfr
1373180025Sdfr	/*
1374180025Sdfr	 * flock should wait until the alarm and then return -1 with
1375180025Sdfr	 * errno set to EINTR.
1376180025Sdfr	 */
1377180025Sdfr	printf("15 - flock(2) semantics: ");
1378180025Sdfr
1379180025Sdfr	alarm(1);
1380180025Sdfr	flock(fd, LOCK_EX);
1381180025Sdfr
1382180025Sdfr	/*
1383180025Sdfr	 * Kill the child to force it to drop its locks.
1384180025Sdfr	 */
1385180025Sdfr	kill(pid, SIGTERM);
1386180025Sdfr	safe_waitpid(pid);
1387180025Sdfr
1388180025Sdfr	fl.l_start = 0;
1389180025Sdfr	fl.l_len = 0;
1390180025Sdfr	fl.l_type = F_WRLCK;
1391180025Sdfr	fl.l_whence = SEEK_SET;
1392180025Sdfr	res = fcntl(fd, F_GETLK, &fl);
1393180025Sdfr
1394180025Sdfr	close(pfd[0]);
1395180025Sdfr	close(pfd[1]);
1396180025Sdfr	FAIL(res != 0);
1397180025Sdfr	FAIL(fl.l_type != F_UNLCK);
1398180025Sdfr
1399180025Sdfr	SUCCEED;
1400180025Sdfr#else
1401180025Sdfr	return 0;
1402180025Sdfr#endif
1403180025Sdfr}
1404180025Sdfr
1405192949Szmlstruct test_ctx {
1406192949Szml	struct flock tc_fl;
1407192949Szml	int tc_fd;
1408192949Szml};
1409192949Szml
1410192949Szmlstatic void *
1411192949Szmltest16_func(void *tc_in)
1412192949Szml{
1413192949Szml	uintptr_t error;
1414192949Szml	struct test_ctx *tc = tc_in;
1415192949Szml
1416192949Szml	error = fcntl(tc->tc_fd, F_SETLKW, &tc->tc_fl);
1417192949Szml
1418192949Szml	pthread_exit((void *)error);
1419192949Szml}
1420192949Szml
1421192949Szml#define THREADS 10
1422192949Szml
1423192949Szml/*
1424192949Szml * Test 16 - F_SETLKW from two threads
1425192949Szml *
1426192949Szml * If two threads within a process are blocked on a lock and the lock
1427192949Szml * is granted, make sure things are sane.
1428192949Szml */
1429192949Szmlstatic int
1430192949Szmltest16(int fd, __unused int argc, const __unused char **argv)
1431192949Szml{
1432192949Szml	/*
1433192949Szml	 * We create a child process to hold the lock which we will
1434192949Szml	 * test. We use a pipe to communicate with the child.
1435192949Szml	 */
1436192949Szml	int pid;
1437192949Szml	int pfd[2];
1438192949Szml	struct test_ctx tc = { .tc_fd = fd };
1439192949Szml	char ch;
1440192949Szml	int i;
1441192949Szml	int error;
1442192949Szml	pthread_t thr[THREADS];
1443192949Szml
1444192949Szml	if (pipe(pfd) < 0)
1445192949Szml		err(1, "pipe");
1446192949Szml
1447192949Szml	tc.tc_fl.l_start = 0;
1448192949Szml	tc.tc_fl.l_len = 0;
1449192949Szml	tc.tc_fl.l_type = F_WRLCK;
1450192949Szml	tc.tc_fl.l_whence = SEEK_SET;
1451192949Szml
1452192949Szml	pid = fork();
1453192949Szml	if (pid < 0)
1454192949Szml		err(1, "fork");
1455192949Szml
1456192949Szml	if (pid == 0) {
1457192949Szml		/*
1458192949Szml		 * We are the child. We set a write lock and then
1459192949Szml		 * write one byte back to the parent to tell it. The
1460192949Szml		 * parent will kill us when its done.
1461192949Szml		 */
1462192949Szml		if (fcntl(fd, F_SETLK, &tc.tc_fl) < 0)
1463192949Szml			err(1, "F_SETLK (child)");
1464192949Szml		if (write(pfd[1], "a", 1) < 0)
1465192949Szml			err(1, "writing to pipe (child)");
1466192949Szml		pause();
1467192949Szml		exit(0);
1468192949Szml	}
1469192949Szml
1470192949Szml	/*
1471192949Szml	 * Wait until the child has set its lock and then perform the
1472192949Szml	 * test.
1473192949Szml	 */
1474192949Szml	if (read(pfd[0], &ch, 1) != 1)
1475192949Szml		err(1, "reading from pipe (child)");
1476192949Szml
1477192949Szml	/*
1478192949Szml	 * fcntl should wait until the alarm and then return -1 with
1479192949Szml	 * errno set to EINTR.
1480192949Szml	 */
1481192949Szml	printf("16 - F_SETLKW on locked region by two threads: ");
1482192949Szml
1483192949Szml	for (i = 0; i < THREADS; i++) {
1484192949Szml		error = pthread_create(&thr[i], NULL, test16_func, &tc);
1485192949Szml		if (error)
1486192949Szml			err(1, "pthread_create");
1487192949Szml	}
1488192949Szml
1489192949Szml	/*
1490192949Szml	 * Sleep, then kill the child. This makes me a little sad, but it's
1491192949Szml	 * tricky to tell whether the threads are all really blocked by this
1492192949Szml	 * point.
1493192949Szml	 */
1494192949Szml	sleep(1);
1495192949Szml	kill(pid, SIGTERM);
1496192949Szml	safe_waitpid(pid);
1497192949Szml	close(pfd[0]);
1498192949Szml	close(pfd[1]);
1499192949Szml
1500192949Szml	for (i = 0; i < THREADS; i++) {
1501192949Szml		void *res;
1502192949Szml		error = pthread_join(thr[i], &res);
1503192949Szml		if (error)
1504192949Szml			err(1, "pthread_join");
1505192949Szml		FAIL((uintptr_t)res != 0);
1506192949Szml	}
1507192949Szml
1508192949Szml	SUCCEED;
1509192949Szml}
1510192949Szml
1511177636Sdfrstruct test {
1512180025Sdfr	int (*testfn)(int, int, const char **);	/* function to perform the test */
1513177636Sdfr	int num;		/* test number */
1514177636Sdfr	int intr;		/* non-zero if the test interrupts a lock */
1515177636Sdfr};
1516177636Sdfr
1517177636Sdfrstruct test tests[] = {
1518177636Sdfr	{	test1,		1,	0	},
1519177636Sdfr	{	test2,		2,	0	},
1520177636Sdfr	{	test3,		3,	1	},
1521177636Sdfr	{	test4,		4,	0	},
1522177636Sdfr	{	test5,		5,	1	},
1523177636Sdfr	{	test6,		6,	1	},
1524177636Sdfr	{	test7,		7,	0	},
1525177636Sdfr	{	test8,		8,	0	},
1526177636Sdfr	{	test9,		9,	0	},
1527177636Sdfr	{	test10,		10,	0	},
1528177636Sdfr	{	test11,		11,	1	},
1529177636Sdfr	{	test12,		12,	0	},
1530177636Sdfr	{	test13,		13,	1	},
1531177636Sdfr	{	test14,		14,	0	},
1532180025Sdfr	{	test15,		15,	1	},
1533192949Szml	{	test16,		16,	1	},
1534177636Sdfr};
1535177636Sdfrint test_count = sizeof(tests) / sizeof(tests[0]);
1536177636Sdfr
1537177636Sdfrint
1538177636Sdfrmain(int argc, const char *argv[])
1539177636Sdfr{
1540177636Sdfr	int testnum;
1541177636Sdfr	int fd;
1542177636Sdfr	int nointr;
1543177636Sdfr	int i;
1544177636Sdfr	struct sigaction sa;
1545180025Sdfr	int test_argc;
1546180025Sdfr	const char **test_argv;
1547177636Sdfr
1548180025Sdfr	if (argc < 2) {
1549180025Sdfr		errx(1, "usage: flock <directory> [test number] ...");
1550177636Sdfr	}
1551177636Sdfr
1552177636Sdfr	fd = make_file(argv[1], 1024);
1553180025Sdfr	if (argc >= 3) {
1554177636Sdfr		testnum = strtol(argv[2], NULL, 0);
1555180025Sdfr		test_argc = argc - 2;
1556180025Sdfr		test_argv = argv + 2;
1557180025Sdfr	} else {
1558177636Sdfr		testnum = 0;
1559180025Sdfr		test_argc = 0;
1560180025Sdfr		test_argv = 0;
1561180025Sdfr	}
1562177636Sdfr
1563177636Sdfr	sa.sa_handler = ignore_alarm;
1564177636Sdfr	sigemptyset(&sa.sa_mask);
1565177636Sdfr	sa.sa_flags = 0;
1566177636Sdfr	sigaction(SIGALRM, &sa, 0);
1567177636Sdfr
1568177636Sdfr	nointr = 0;
1569180025Sdfr#if defined(__FreeBSD__) && __FreeBSD_version < 800040
1570177636Sdfr	{
1571177636Sdfr		/*
1572180025Sdfr		 * FreeBSD with userland NLM can't interrupt a blocked
1573180025Sdfr		 * lock request on an NFS mounted filesystem.
1574177636Sdfr		 */
1575177636Sdfr		struct statfs st;
1576177636Sdfr		fstatfs(fd, &st);
1577177636Sdfr		nointr = !strcmp(st.f_fstypename, "nfs");
1578177636Sdfr	}
1579177636Sdfr#endif
1580177636Sdfr
1581177636Sdfr	for (i = 0; i < test_count; i++) {
1582177636Sdfr		if (tests[i].intr && nointr)
1583177636Sdfr			continue;
1584177636Sdfr		if (!testnum || tests[i].num == testnum)
1585180025Sdfr			tests[i].testfn(fd, test_argc, test_argv);
1586177636Sdfr	}
1587177636Sdfr
1588177636Sdfr	return 0;
1589177636Sdfr}
1590