]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - tests/sys/file/flock_helper.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / tests / sys / file / flock_helper.c
1 /*-
2  * Copyright (c) 2008 Isilon Inc http://www.isilon.com/
3  * Authors: Doug Rabson <dfr@rabson.org>
4  * Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org>
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  * $FreeBSD$
28  */
29
30 #include <sys/param.h>
31 #include <sys/file.h>
32 #include <sys/time.h>
33 #ifdef __FreeBSD__
34 #include <sys/mount.h>
35 #endif
36 #include <sys/stat.h>
37 #include <sys/wait.h>
38
39 #include <err.h>
40 #include <errno.h>
41 #include <fcntl.h>
42 #include <pthread.h>
43 #include <signal.h>
44 #include <stdint.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <unistd.h>
49
50 #ifdef __FreeBSD__
51 #if __FreeBSD_version >= 800028
52 #define HAVE_SYSID
53 #endif
54 #include <sys/cdefs.h>
55 #else
56 #ifndef nitems
57 #define nitems(x)       (sizeof((x)) / sizeof((x)[0]))
58 #endif
59
60 #ifndef __unused
61 #ifdef __GNUC__
62 #define __unused        __attribute__((__unused__))
63 #else
64 #define __unused
65 #endif
66 #endif
67 #endif
68
69 static int verbose = 0;
70
71 static int
72 make_file(const char *pathname, off_t sz)
73 {
74         struct stat st;
75         const char *template = "/flocktempXXXXXX";
76         size_t len;
77         char *filename;
78         int fd;
79
80         if (stat(pathname, &st) == 0) {
81                 if (S_ISREG(st.st_mode)) {
82                         fd = open(pathname, O_RDWR);
83                         if (fd < 0)
84                                 err(1, "open(%s)", pathname);
85                         if (ftruncate(fd, sz) < 0)
86                                 err(1, "ftruncate");
87                         return (fd);
88                 }
89         }
90
91         len = strlen(pathname) + strlen(template) + 1;
92         filename = malloc(len);
93         strcpy(filename, pathname);
94         strcat(filename, template);
95         fd = mkstemp(filename);
96         if (fd < 0)
97                 err(1, "mkstemp");
98         if (ftruncate(fd, sz) < 0)
99                 err(1, "ftruncate");
100         if (unlink(filename) < 0)
101                 err(1, "unlink");
102         free(filename);
103
104         return (fd);
105 }
106
107 static void
108 ignore_alarm(int __unused sig)
109 {
110 }
111
112 static int
113 safe_waitpid(pid_t pid)
114 {
115         int save_errno;
116         int status;
117
118         save_errno = errno;
119         errno = 0;
120         while (waitpid(pid, &status, 0) != pid) {
121                 if (errno == EINTR)
122                         continue;
123                 err(1, "waitpid");
124         }
125         errno = save_errno;
126
127         return (status);
128 }
129
130 #define FAIL(test)                                      \
131         do {                                            \
132                 if (test) {                             \
133                         printf("FAIL (%s)\n", #test);   \
134                         return -1;                      \
135                 }                                       \
136         } while (0)
137
138 #define SUCCEED \
139         do { printf("SUCCEED\n"); return 0; } while (0)
140
141 /*
142  * Test 1 - F_GETLK on unlocked region
143  *
144  * If no lock is found that would prevent this lock from being
145  * created, the structure is left unchanged by this function call
146  * except for the lock type which is set to F_UNLCK.
147  */
148 static int
149 test1(int fd, __unused int argc, const __unused char **argv)
150 {
151         struct flock fl1, fl2;
152
153         memset(&fl1, 1, sizeof(fl1));
154         fl1.l_type = F_WRLCK;
155         fl1.l_whence = SEEK_SET;
156         fl2 = fl1;
157
158         if (fcntl(fd, F_GETLK, &fl1) < 0)
159                 err(1, "F_GETLK");
160
161         printf("1 - F_GETLK on unlocked region: ");
162         FAIL(fl1.l_start != fl2.l_start);
163         FAIL(fl1.l_len != fl2.l_len);
164         FAIL(fl1.l_pid != fl2.l_pid);
165         FAIL(fl1.l_type != F_UNLCK);
166         FAIL(fl1.l_whence != fl2.l_whence);
167 #ifdef HAVE_SYSID
168         FAIL(fl1.l_sysid != fl2.l_sysid);
169 #endif
170
171         SUCCEED;
172 }
173
174 /*
175  * Test 2 - F_SETLK on locked region
176  *
177  * If a shared or exclusive lock cannot be set, fcntl returns
178  * immediately with EACCES or EAGAIN.
179  */
180 static int
181 test2(int fd, __unused int argc, const __unused char **argv)
182 {
183         /*
184          * We create a child process to hold the lock which we will
185          * test. We use a pipe to communicate with the child.
186          */
187         int pid;
188         int pfd[2];
189         struct flock fl;
190         char ch;
191         int res;
192
193         if (pipe(pfd) < 0)
194                 err(1, "pipe");
195
196         fl.l_start = 0;
197         fl.l_len = 0;
198         fl.l_type = F_WRLCK;
199         fl.l_whence = SEEK_SET;
200
201         pid = fork();
202         if (pid < 0)
203                 err(1, "fork");
204
205         if (pid == 0) {
206                 /*
207                  * We are the child. We set a write lock and then
208                  * write one byte back to the parent to tell it. The
209                  * parent will kill us when its done.
210                  */
211                 if (fcntl(fd, F_SETLK, &fl) < 0)
212                         err(1, "F_SETLK (child)");
213                 if (write(pfd[1], "a", 1) < 0)
214                         err(1, "writing to pipe (child)");
215                 pause();
216                 exit(0);
217         }
218
219         /*
220          * Wait until the child has set its lock and then perform the
221          * test.
222          */
223         if (read(pfd[0], &ch, 1) != 1)
224                 err(1, "reading from pipe (child)");
225
226         /*
227          * fcntl should return -1 with errno set to either EACCES or
228          * EAGAIN.
229          */
230         printf("2 - F_SETLK on locked region: ");
231         res = fcntl(fd, F_SETLK, &fl);
232         kill(pid, SIGTERM);
233         safe_waitpid(pid);
234         close(pfd[0]);
235         close(pfd[1]);
236         FAIL(res == 0);
237         FAIL(errno != EACCES && errno != EAGAIN);
238
239         SUCCEED;
240 }
241
242 /*
243  * Test 3 - F_SETLKW on locked region
244  *
245  * If a shared or exclusive lock is blocked by other locks, the
246  * process waits until the request can be satisfied.
247  *
248  * XXX this test hangs on FreeBSD NFS filesystems due to limitations
249  * in FreeBSD's client (and server) lockd implementation.
250  */
251 static int
252 test3(int fd, __unused int argc, const __unused char **argv)
253 {
254         /*
255          * We create a child process to hold the lock which we will
256          * test. We use a pipe to communicate with the child.
257          */
258         int pid;
259         int pfd[2];
260         struct flock fl;
261         char ch;
262         int res;
263
264         if (pipe(pfd) < 0)
265                 err(1, "pipe");
266
267         fl.l_start = 0;
268         fl.l_len = 0;
269         fl.l_type = F_WRLCK;
270         fl.l_whence = SEEK_SET;
271
272         pid = fork();
273         if (pid < 0)
274                 err(1, "fork");
275
276         if (pid == 0) {
277                 /*
278                  * We are the child. We set a write lock and then
279                  * write one byte back to the parent to tell it. The
280                  * parent will kill us when its done.
281                  */
282                 if (fcntl(fd, F_SETLK, &fl) < 0)
283                         err(1, "F_SETLK (child)");
284                 if (write(pfd[1], "a", 1) < 0)
285                         err(1, "writing to pipe (child)");
286                 pause();
287                 exit(0);
288         }
289
290         /*
291          * Wait until the child has set its lock and then perform the
292          * test.
293          */
294         if (read(pfd[0], &ch, 1) != 1)
295                 err(1, "reading from pipe (child)");
296
297         /*
298          * fcntl should wait until the alarm and then return -1 with
299          * errno set to EINTR.
300          */
301         printf("3 - F_SETLKW on locked region: ");
302
303         alarm(1);
304
305         res = fcntl(fd, F_SETLKW, &fl);
306         kill(pid, SIGTERM);
307         safe_waitpid(pid);
308         close(pfd[0]);
309         close(pfd[1]);
310         FAIL(res == 0);
311         FAIL(errno != EINTR);
312
313         SUCCEED;
314 }
315
316 /*
317  * Test 4 - F_GETLK on locked region
318  *
319  * Get the first lock that blocks the lock.
320  */
321 static int
322 test4(int fd, __unused int argc, const __unused char **argv)
323 {
324         /*
325          * We create a child process to hold the lock which we will
326          * test. We use a pipe to communicate with the child.
327          */
328         int pid;
329         int pfd[2];
330         struct flock fl;
331         char ch;
332
333         if (pipe(pfd) < 0)
334                 err(1, "pipe");
335
336         fl.l_start = 0;
337         fl.l_len = 99;
338         fl.l_type = F_WRLCK;
339         fl.l_whence = SEEK_SET;
340
341         pid = fork();
342         if (pid < 0)
343                 err(1, "fork");
344
345         if (pid == 0) {
346                 /*
347                  * We are the child. We set a write lock and then
348                  * write one byte back to the parent to tell it. The
349                  * parent will kill us when its done.
350                  */
351                 if (fcntl(fd, F_SETLK, &fl) < 0)
352                         err(1, "F_SETLK (child)");
353                 if (write(pfd[1], "a", 1) < 0)
354                         err(1, "writing to pipe (child)");
355                 pause();
356                 exit(0);
357         }
358
359         /*
360          * Wait until the child has set its lock and then perform the
361          * test.
362          */
363         if (read(pfd[0], &ch, 1) != 1)
364                 err(1, "reading from pipe (child)");
365
366         /*
367          * fcntl should return a lock structure reflecting the lock we
368          * made in the child process.
369          */
370         if (fcntl(fd, F_GETLK, &fl) < 0)
371                 err(1, "F_GETLK");
372
373         printf("4 - F_GETLK on locked region: ");
374         FAIL(fl.l_start != 0);
375         FAIL(fl.l_len != 99);
376         FAIL(fl.l_type != F_WRLCK);
377         FAIL(fl.l_pid != pid);
378 #ifdef HAVE_SYSID
379         FAIL(fl.l_sysid != 0);
380 #endif
381
382         kill(pid, SIGTERM);
383         safe_waitpid(pid);
384         close(pfd[0]);
385         close(pfd[1]);
386
387         SUCCEED;
388 }
389
390 /*
391  * Test 5 - F_SETLKW simple deadlock
392  *
393  * If a blocking shared lock request would cause a deadlock (i.e. the
394  * lock request is blocked by a process which is itself blocked on a
395  * lock currently owned by the process making the new request),
396  * EDEADLK is returned.
397  */
398 static int
399 test5(int fd, __unused int argc, const __unused char **argv)
400 {
401         /*
402          * We create a child process to hold the lock which we will
403          * test. Because our test relies on the child process being
404          * blocked on the parent's lock, we can't easily use a pipe to
405          * synchronize so we just sleep in the parent to given the
406          * child a chance to setup.
407          *
408          * To create the deadlock condition, we arrange for the parent
409          * to lock the first byte of the file and the child to lock
410          * the second byte.  After locking the second byte, the child
411          * will attempt to lock the first byte of the file, and
412          * block. The parent will then attempt to lock the second byte
413          * (owned by the child) which should cause deadlock.
414          */
415         int pid;
416         struct flock fl;
417         int res;
418
419         /*
420          * Lock the first byte in the parent.
421          */
422         fl.l_start = 0;
423         fl.l_len = 1;
424         fl.l_type = F_WRLCK;
425         fl.l_whence = SEEK_SET;
426         if (fcntl(fd, F_SETLK, &fl) < 0)
427                 err(1, "F_SETLK 1 (parent)");
428
429         pid = fork();
430         if (pid < 0)
431                 err(1, "fork");
432
433         if (pid == 0) {
434                 /*
435                  * Lock the second byte in the child and then block on
436                  * the parent's lock.
437                  */
438                 fl.l_start = 1;
439                 if (fcntl(fd, F_SETLK, &fl) < 0)
440                         err(1, "F_SETLK (child)");
441                 fl.l_start = 0;
442                 if (fcntl(fd, F_SETLKW, &fl) < 0)
443                         err(1, "F_SETLKW (child)");
444                 exit(0);
445         }
446
447         /*
448          * Wait until the child has set its lock and then perform the
449          * test.
450          */
451         sleep(1);
452
453         /*
454          * fcntl should immediately return -1 with errno set to
455          * EDEADLK. If the alarm fires, we failed to detect the
456          * deadlock.
457          */
458         alarm(1);
459         printf("5 - F_SETLKW simple deadlock: ");
460
461         fl.l_start = 1;
462         res = fcntl(fd, F_SETLKW, &fl);
463         kill(pid, SIGTERM);
464         safe_waitpid(pid);
465         
466         FAIL(res == 0);
467         FAIL(errno != EDEADLK);
468
469         fl.l_start = 0;
470         fl.l_len = 0;
471         fl.l_type = F_UNLCK;
472         if (fcntl(fd, F_SETLK, &fl) < 0)
473                 err(1, "F_UNLCK");
474
475         /*
476          * Cancel the alarm to avoid confusing later tests.
477          */
478         alarm(0);
479
480         SUCCEED;
481 }
482
483 /*
484  * Test 6 - F_SETLKW complex deadlock.
485  *
486  * This test involves three process, P, C1 and C2. We set things up so
487  * that P locks byte zero, C1 locks byte 1 and C2 locks byte 2. We
488  * also block C2 by attempting to lock byte zero. Lastly, P attempts
489  * to lock a range including byte 1 and 2. This represents a deadlock
490  * (due to C2's blocking attempt to lock byte zero).
491  */
492 static int
493 test6(int fd, __unused int argc, const __unused char **argv)
494 {
495         /*
496          * Because our test relies on the child process being blocked
497          * on the parent's lock, we can't easily use a pipe to
498          * synchronize so we just sleep in the parent to given the
499          * children a chance to setup.
500          */
501         int pid1, pid2;
502         struct flock fl;
503         int res;
504
505         /*
506          * Lock the first byte in the parent.
507          */
508         fl.l_start = 0;
509         fl.l_len = 1;
510         fl.l_type = F_WRLCK;
511         fl.l_whence = SEEK_SET;
512         if (fcntl(fd, F_SETLK, &fl) < 0)
513                 err(1, "F_SETLK 1 (parent)");
514
515         pid1 = fork();
516         if (pid1 < 0)
517                 err(1, "fork");
518
519         if (pid1 == 0) {
520                 /*
521                  * C1
522                  * Lock the second byte in the child and then sleep
523                  */
524                 fl.l_start = 1;
525                 if (fcntl(fd, F_SETLK, &fl) < 0)
526                         err(1, "F_SETLK (child1)");
527                 pause();
528                 exit(0);
529         }
530
531         pid2 = fork();
532         if (pid2 < 0)
533                 err(1, "fork");
534
535         if (pid2 == 0) {
536                 /*
537                  * C2
538                  * Lock the third byte in the child and then block on
539                  * the parent's lock.
540                  */
541                 fl.l_start = 2;
542                 if (fcntl(fd, F_SETLK, &fl) < 0)
543                         err(1, "F_SETLK (child2)");
544                 fl.l_start = 0;
545                 if (fcntl(fd, F_SETLKW, &fl) < 0)
546                         err(1, "F_SETLKW (child2)");
547                 exit(0);
548         }
549
550         /*
551          * Wait until the children have set their locks and then
552          * perform the test.
553          */
554         sleep(1);
555
556         /*
557          * fcntl should immediately return -1 with errno set to
558          * EDEADLK. If the alarm fires, we failed to detect the
559          * deadlock.
560          */
561         alarm(1);
562         printf("6 - F_SETLKW complex deadlock: ");
563
564         fl.l_start = 1;
565         fl.l_len = 2;
566         res = fcntl(fd, F_SETLKW, &fl);
567         kill(pid1, SIGTERM);
568         safe_waitpid(pid1);
569         kill(pid2, SIGTERM);
570         safe_waitpid(pid2);
571
572         fl.l_start = 0;
573         fl.l_len = 0;
574         fl.l_type = F_UNLCK;
575         if (fcntl(fd, F_SETLK, &fl) < 0)
576                 err(1, "F_UNLCK");
577
578         FAIL(res == 0);
579         FAIL(errno != EDEADLK);
580
581         /*
582          * Cancel the alarm to avoid confusing later tests.
583          */
584         alarm(0);
585
586         SUCCEED;
587 }
588
589 /*
590  * Test 7 - F_SETLK shared lock on exclusive locked region
591  *
592  * If a shared or exclusive lock cannot be set, fcntl returns
593  * immediately with EACCES or EAGAIN.
594  */
595 static int
596 test7(int fd, __unused int argc, const __unused char **argv)
597 {
598         /*
599          * We create a child process to hold the lock which we will
600          * test. We use a pipe to communicate with the child.
601          */
602         int pid;
603         int pfd[2];
604         struct flock fl;
605         char ch;
606         int res;
607
608         if (pipe(pfd) < 0)
609                 err(1, "pipe");
610
611         fl.l_start = 0;
612         fl.l_len = 0;
613         fl.l_type = F_WRLCK;
614         fl.l_whence = SEEK_SET;
615
616         pid = fork();
617         if (pid < 0)
618                 err(1, "fork");
619
620         if (pid == 0) {
621                 /*
622                  * We are the child. We set a write lock and then
623                  * write one byte back to the parent to tell it. The
624                  * parent will kill us when its done.
625                  */
626                 if (fcntl(fd, F_SETLK, &fl) < 0)
627                         err(1, "F_SETLK (child)");
628                 if (write(pfd[1], "a", 1) < 0)
629                         err(1, "writing to pipe (child)");
630                 pause();
631                 exit(0);
632         }
633
634         /*
635          * Wait until the child has set its lock and then perform the
636          * test.
637          */
638         if (read(pfd[0], &ch, 1) != 1)
639                 err(1, "reading from pipe (child)");
640
641         /*
642          * fcntl should wait until the alarm and then return -1 with
643          * errno set to EINTR.
644          */
645         printf("7 - F_SETLK shared lock on exclusive locked region: ");
646
647         fl.l_type = F_RDLCK;
648         res = fcntl(fd, F_SETLK, &fl);
649         kill(pid, SIGTERM);
650         safe_waitpid(pid);
651         close(pfd[0]);
652         close(pfd[1]);
653
654         FAIL(res == 0);
655         FAIL(errno != EACCES && errno != EAGAIN);
656
657         SUCCEED;
658 }
659
660 /*
661  * Test 8 - F_SETLK shared lock on share locked region
662  *
663  * When a shared lock is set on a segment of a file, other processes
664  * shall be able to set shared locks on that segment or a portion of
665  * it.
666  */
667 static int
668 test8(int fd, __unused int argc, const __unused char **argv)
669 {
670         /*
671          * We create a child process to hold the lock which we will
672          * test. We use a pipe to communicate with the child.
673          */
674         int pid;
675         int pfd[2];
676         struct flock fl;
677         char ch;
678         int res;
679
680         if (pipe(pfd) < 0)
681                 err(1, "pipe");
682
683         fl.l_start = 0;
684         fl.l_len = 0;
685         fl.l_type = F_RDLCK;
686         fl.l_whence = SEEK_SET;
687
688         pid = fork();
689         if (pid < 0)
690                 err(1, "fork");
691
692         if (pid == 0) {
693                 /*
694                  * We are the child. We set a write lock and then
695                  * write one byte back to the parent to tell it. The
696                  * parent will kill us when its done.
697                  */
698                 if (fcntl(fd, F_SETLK, &fl) < 0)
699                         err(1, "F_SETLK (child)");
700                 if (write(pfd[1], "a", 1) < 0)
701                         err(1, "writing to pipe (child)");
702                 pause();
703                 exit(0);
704         }
705
706         /*
707          * Wait until the child has set its lock and then perform the
708          * test.
709          */
710         if (read(pfd[0], &ch, 1) != 1)
711                 err(1, "reading from pipe (child)");
712
713         /*
714          * fcntl should wait until the alarm and then return -1 with
715          * errno set to EINTR.
716          */
717         printf("8 - F_SETLK shared lock on share locked region: ");
718
719         fl.l_type = F_RDLCK;
720         res = fcntl(fd, F_SETLK, &fl);
721
722         kill(pid, SIGTERM);
723         safe_waitpid(pid);
724         close(pfd[0]);
725         close(pfd[1]);
726
727         fl.l_start = 0;
728         fl.l_len = 0;
729         fl.l_type = F_UNLCK;
730         if (fcntl(fd, F_SETLK, &fl) < 0)
731                 err(1, "F_UNLCK");
732
733         FAIL(res != 0);
734
735         SUCCEED;
736 }
737
738 /*
739  * Test 9 - F_SETLK exclusive lock on share locked region
740  *
741  * If a shared or exclusive lock cannot be set, fcntl returns
742  * immediately with EACCES or EAGAIN.
743  */
744 static int
745 test9(int fd, __unused int argc, const __unused char **argv)
746 {
747         /*
748          * We create a child process to hold the lock which we will
749          * test. We use a pipe to communicate with the child.
750          */
751         int pid;
752         int pfd[2];
753         struct flock fl;
754         char ch;
755         int res;
756
757         if (pipe(pfd) < 0)
758                 err(1, "pipe");
759
760         fl.l_start = 0;
761         fl.l_len = 0;
762         fl.l_type = F_RDLCK;
763         fl.l_whence = SEEK_SET;
764
765         pid = fork();
766         if (pid < 0)
767                 err(1, "fork");
768
769         if (pid == 0) {
770                 /*
771                  * We are the child. We set a write lock and then
772                  * write one byte back to the parent to tell it. The
773                  * parent will kill us when its done.
774                  */
775                 if (fcntl(fd, F_SETLK, &fl) < 0)
776                         err(1, "F_SETLK (child)");
777                 if (write(pfd[1], "a", 1) < 0)
778                         err(1, "writing to pipe (child)");
779                 pause();
780                 exit(0);
781         }
782
783         /*
784          * Wait until the child has set its lock and then perform the
785          * test.
786          */
787         if (read(pfd[0], &ch, 1) != 1)
788                 err(1, "reading from pipe (child)");
789
790         /*
791          * fcntl should wait until the alarm and then return -1 with
792          * errno set to EINTR.
793          */
794         printf("9 - F_SETLK exclusive lock on share locked region: ");
795
796         fl.l_type = F_WRLCK;
797         res = fcntl(fd, F_SETLK, &fl);
798         kill(pid, SIGTERM);
799         safe_waitpid(pid);
800         close(pfd[0]);
801         close(pfd[1]);
802
803         FAIL(res == 0);
804         FAIL(errno != EACCES && errno != EAGAIN);
805
806         SUCCEED;
807 }
808
809 /*
810  * Test 10 - trying to set bogus pid or sysid values
811  *
812  * The l_pid and l_sysid fields are only used with F_GETLK to return
813  * the process ID of the process holding a blocking lock and the
814  * system ID of the system that owns that process
815  */
816 static int
817 test10(int fd, __unused int argc, const __unused char **argv)
818 {
819         /*
820          * We create a child process to hold the lock which we will
821          * test. We use a pipe to communicate with the child.
822          */
823         int pid;
824         int pfd[2];
825         struct flock fl;
826         char ch;
827
828         if (pipe(pfd) < 0)
829                 err(1, "pipe");
830
831         fl.l_start = 0;
832         fl.l_len = 0;
833         fl.l_type = F_WRLCK;
834         fl.l_whence = SEEK_SET;
835         fl.l_pid = 9999;
836 #ifdef HAVE_SYSID
837         fl.l_sysid = 9999;
838 #endif
839
840         pid = fork();
841         if (pid < 0)
842                 err(1, "fork");
843
844         if (pid == 0) {
845                 /*
846                  * We are the child. We set a write lock and then
847                  * write one byte back to the parent to tell it. The
848                  * parent will kill us when its done.
849                  */
850                 if (fcntl(fd, F_SETLK, &fl) < 0)
851                         err(1, "F_SETLK (child)");
852                 if (write(pfd[1], "a", 1) < 0)
853                         err(1, "writing to pipe (child)");
854                 pause();
855                 exit(0);
856         }
857
858         /*
859          * Wait until the child has set its lock and then perform the
860          * test.
861          */
862         if (read(pfd[0], &ch, 1) != 1)
863                 err(1, "reading from pipe (child)");
864
865         printf("10 - trying to set bogus pid or sysid values: ");
866
867         if (fcntl(fd, F_GETLK, &fl) < 0)
868                 err(1, "F_GETLK");
869
870         kill(pid, SIGTERM);
871         safe_waitpid(pid);
872         close(pfd[0]);
873         close(pfd[1]);
874
875         FAIL(fl.l_pid != pid);
876 #ifdef HAVE_SYSID
877         FAIL(fl.l_sysid != 0);
878 #endif
879
880         SUCCEED;
881 }
882
883 /*
884  * Test 11 - remote locks
885  *
886  * XXX temporary interface which will be removed when the kernel lockd
887  * is added.
888  */
889 static int
890 test11(int fd, __unused int argc, const __unused char **argv)
891 {
892 #ifdef F_SETLK_REMOTE
893         struct flock fl;
894         int res;
895
896         if (geteuid() != 0)
897                 return 0;
898
899         fl.l_start = 0;
900         fl.l_len = 0;
901         fl.l_type = F_WRLCK;
902         fl.l_whence = SEEK_SET;
903         fl.l_pid = 9999;
904         fl.l_sysid = 1001;
905
906         printf("11 - remote locks: ");
907
908         res = fcntl(fd, F_SETLK_REMOTE, &fl);
909         FAIL(res != 0);
910
911         fl.l_sysid = 1002;
912         res = fcntl(fd, F_SETLK_REMOTE, &fl);
913         FAIL(res == 0);
914         FAIL(errno != EACCES && errno != EAGAIN);
915
916         res = fcntl(fd, F_GETLK, &fl);
917         FAIL(res != 0);
918         FAIL(fl.l_pid != 9999);
919         FAIL(fl.l_sysid != 1001);
920
921         fl.l_type = F_UNLCK;
922         fl.l_sysid = 1001;
923         fl.l_start = 0;
924         fl.l_len = 0;
925         res = fcntl(fd, F_SETLK_REMOTE, &fl);
926         FAIL(res != 0);
927
928         fl.l_pid = 1234;
929         fl.l_sysid = 1001;
930         fl.l_start = 0;
931         fl.l_len = 1;
932         fl.l_whence = SEEK_SET;
933         fl.l_type = F_RDLCK;
934         res = fcntl(fd, F_SETLK_REMOTE, &fl);
935         FAIL(res != 0);
936
937         fl.l_sysid = 1002;
938         res = fcntl(fd, F_SETLK_REMOTE, &fl);
939         FAIL(res != 0);
940
941         fl.l_type = F_UNLCKSYS;
942         fl.l_sysid = 1001;
943         res = fcntl(fd, F_SETLK_REMOTE, &fl);
944         FAIL(res != 0);
945
946         fl.l_type = F_WRLCK;
947         res = fcntl(fd, F_GETLK, &fl);
948         FAIL(res != 0);
949         FAIL(fl.l_pid != 1234);
950         FAIL(fl.l_sysid != 1002);
951
952         fl.l_type = F_UNLCKSYS;
953         fl.l_sysid = 1002;
954         res = fcntl(fd, F_SETLK_REMOTE, &fl);
955         FAIL(res != 0);
956
957         SUCCEED;
958 #else
959         return 0;
960 #endif
961 }
962
963 /*
964  * Test 12 - F_SETLKW on locked region which is then unlocked
965  *
966  * If a shared or exclusive lock is blocked by other locks, the
967  * process waits until the request can be satisfied.
968  */
969 static int
970 test12(int fd, __unused int argc, const __unused char **argv)
971 {
972         /*
973          * We create a child process to hold the lock which we will
974          * test. We use a pipe to communicate with the child.
975          */
976         int pid;
977         int pfd[2];
978         struct flock fl;
979         char ch;
980         int res;
981
982         if (pipe(pfd) < 0)
983                 err(1, "pipe");
984
985         fl.l_start = 0;
986         fl.l_len = 0;
987         fl.l_type = F_WRLCK;
988         fl.l_whence = SEEK_SET;
989
990         pid = fork();
991         if (pid < 0)
992                 err(1, "fork");
993
994         if (pid == 0) {
995                 /*
996                  * We are the child. We set a write lock and then
997                  * write one byte back to the parent to tell it. The
998                  * parent will kill us when its done.
999                  */
1000                 if (fcntl(fd, F_SETLK, &fl) < 0)
1001                         err(1, "F_SETLK (child)");
1002                 if (write(pfd[1], "a", 1) < 0)
1003                         err(1, "writing to pipe (child)");
1004
1005                 sleep(1);
1006                 exit(0);
1007         }
1008
1009         /*
1010          * Wait until the child has set its lock and then perform the
1011          * test.
1012          */
1013         if (read(pfd[0], &ch, 1) != 1)
1014                 err(1, "reading from pipe (child)");
1015
1016         /*
1017          * fcntl should wait until the alarm and then return -1 with
1018          * errno set to EINTR.
1019          */
1020         printf("12 - F_SETLKW on locked region which is then unlocked: ");
1021
1022         //alarm(1);
1023
1024         res = fcntl(fd, F_SETLKW, &fl);
1025         kill(pid, SIGTERM);
1026         safe_waitpid(pid);
1027         close(pfd[0]);
1028         close(pfd[1]);
1029         FAIL(res != 0);
1030
1031         fl.l_start = 0;
1032         fl.l_len = 0;
1033         fl.l_type = F_UNLCK;
1034         if (fcntl(fd, F_SETLK, &fl) < 0)
1035                 err(1, "F_UNLCK");
1036
1037         SUCCEED;
1038 }
1039
1040 /*
1041  * Test 13 - F_SETLKW on locked region, race with owner
1042  *
1043  * If a shared or exclusive lock is blocked by other locks, the
1044  * process waits until the request can be satisfied.
1045  */
1046 static int
1047 test13(int fd, __unused int argc, const __unused char **argv)
1048 {
1049         /*
1050          * We create a child process to hold the lock which we will
1051          * test. We use a pipe to communicate with the child.
1052          */
1053         int i;
1054         int pid;
1055         int pfd[2];
1056         struct flock fl;
1057         char ch;
1058         int res;
1059         struct itimerval itv;
1060
1061         printf("13 - F_SETLKW on locked region, race with owner: ");
1062         fflush(stdout);
1063
1064         for (i = 0; i < 100; i++) {
1065                 if (pipe(pfd) < 0)
1066                         err(1, "pipe");
1067
1068                 fl.l_start = 0;
1069                 fl.l_len = 0;
1070                 fl.l_type = F_WRLCK;
1071                 fl.l_whence = SEEK_SET;
1072
1073                 pid = fork();
1074                 if (pid < 0)
1075                         err(1, "fork");
1076
1077                 if (pid == 0) {
1078                         /*
1079                          * We are the child. We set a write lock and then
1080                          * write one byte back to the parent to tell it. The
1081                          * parent will kill us when its done.
1082                          */
1083                         if (fcntl(fd, F_SETLK, &fl) < 0)
1084                                 err(1, "F_SETLK (child)");
1085                         if (write(pfd[1], "a", 1) < 0)
1086                                 err(1, "writing to pipe (child)");
1087
1088                         usleep(1);
1089                         exit(0);
1090                 }
1091
1092                 /*
1093                  * Wait until the child has set its lock and then perform the
1094                  * test.
1095                  */
1096                 while (read(pfd[0], &ch, 1) != 1) {
1097                         if (errno == EINTR)
1098                                 continue;
1099                         err(1, "reading from pipe (child)");
1100                 }
1101
1102                 /*
1103                  * fcntl should wait until the alarm and then return -1 with
1104                  * errno set to EINTR.
1105                  */
1106                 itv.it_interval.tv_sec = 0;
1107                 itv.it_interval.tv_usec = 0;
1108                 itv.it_value.tv_sec = 0;
1109                 itv.it_value.tv_usec = 2;
1110                 setitimer(ITIMER_REAL, &itv, NULL);
1111
1112                 res = fcntl(fd, F_SETLKW, &fl);
1113                 kill(pid, SIGTERM);
1114                 safe_waitpid(pid);
1115                 close(pfd[0]);
1116                 close(pfd[1]);
1117                 FAIL(!(res == 0 || (res == -1 && errno == EINTR)));
1118
1119                 fl.l_start = 0;
1120                 fl.l_len = 0;
1121                 fl.l_type = F_UNLCK;
1122                 if (fcntl(fd, F_SETLK, &fl) < 0)
1123                         err(1, "F_UNLCK");
1124         }
1125         SUCCEED;
1126 }
1127
1128 /*
1129  * Test 14 - soak test
1130  */
1131 static int
1132 test14(int fd, int argc, const char **argv)
1133 {
1134 #define CHILD_COUNT 20
1135         /*
1136          * We create a set of child processes and let each one run
1137          * through a random sequence of locks and unlocks.
1138          */
1139         int i, j, id, id_base;
1140         int pids[CHILD_COUNT], pid;
1141         char buf[128];
1142         char tbuf[128];
1143         int map[128];
1144         char outbuf[512];
1145         struct flock fl;
1146         struct itimerval itv;
1147         int status;
1148
1149         id_base = 0;
1150         if (argc >= 2)
1151                 id_base = strtol(argv[1], NULL, 0);
1152
1153         printf("14 - soak test: ");
1154         fflush(stdout);
1155
1156         for (i = 0; i < 128; i++)
1157                 map[i] = F_UNLCK;
1158
1159         for (i = 0; i < CHILD_COUNT; i++) {
1160
1161                 pid = fork();
1162                 if (pid < 0)
1163                         err(1, "fork");
1164                 if (pid) {
1165                         /*
1166                          * Parent - record the pid and continue.
1167                          */
1168                         pids[i] = pid;
1169                         continue;
1170                 }
1171
1172                 /*
1173                  * Child - do some work and exit.
1174                  */
1175                 id = id_base + i;
1176                 srandom(getpid());
1177
1178                 for (j = 0; j < 50; j++) {
1179                         int start, end, len;
1180                         int set, wrlock;
1181
1182                         do {
1183                                 start = random() & 127;
1184                                 end = random() & 127;
1185                         } while (end <= start);
1186
1187                         set = random() & 1;
1188                         wrlock = random() & 1;
1189
1190                         len = end - start;
1191                         fl.l_start = start;
1192                         fl.l_len = len;
1193                         fl.l_whence = SEEK_SET;
1194                         if (set)
1195                                 fl.l_type = wrlock ? F_WRLCK : F_RDLCK;
1196                         else
1197                                 fl.l_type = F_UNLCK;
1198
1199                         itv.it_interval.tv_sec = 0;
1200                         itv.it_interval.tv_usec = 0;
1201                         itv.it_value.tv_sec = 0;
1202                         itv.it_value.tv_usec = 3000;
1203                         setitimer(ITIMER_REAL, &itv, NULL);
1204
1205                         if (fcntl(fd, F_SETLKW, &fl) < 0) {
1206                                 if (errno == EDEADLK || errno == EINTR) {
1207                                         if (verbose) {
1208                                                 snprintf(outbuf, sizeof(outbuf),
1209                                                     "%d[%d]: %s [%d .. %d] %s\n",
1210                                                     id, j,
1211                                                     set ? (wrlock ? "write lock"
1212                                                         : "read lock")
1213                                                     : "unlock", start, end,
1214                                                     errno == EDEADLK
1215                                                     ? "deadlock"
1216                                                     : "interrupted");
1217                                                 write(1, outbuf,
1218                                                     strlen(outbuf));
1219                                         }
1220                                         continue;
1221                                 } else {
1222                                         perror("fcntl");
1223                                 }
1224                         }
1225
1226                         itv.it_interval.tv_sec = 0;
1227                         itv.it_interval.tv_usec = 0;
1228                         itv.it_value.tv_sec = 0;
1229                         itv.it_value.tv_usec = 0;
1230                         setitimer(ITIMER_REAL, &itv, NULL);
1231
1232                         if (verbose) {
1233                                 snprintf(outbuf, sizeof(outbuf),
1234                                     "%d[%d]: %s [%d .. %d] succeeded\n",
1235                                     id, j,
1236                                     set ? (wrlock ? "write lock" : "read lock")
1237                                     : "unlock", start, end);
1238                                 write(1, outbuf, strlen(outbuf));
1239                         }
1240
1241                         if (set) {
1242                                 if (wrlock) {
1243                                         /*
1244                                          * We got a write lock - write
1245                                          * our ID to each byte that we
1246                                          * managed to claim.
1247                                          */
1248                                         for (i = start; i < end; i++)
1249                                                 map[i] = F_WRLCK;
1250                                         memset(&buf[start], id, len);
1251                                         if (pwrite(fd, &buf[start], len,
1252                                                 start) != len) {
1253                                                 printf("%d: short write\n", id);
1254                                                 exit(1);
1255                                         }
1256                                 } else {
1257                                         /*
1258                                          * We got a read lock - read
1259                                          * the bytes which we claimed
1260                                          * so that we can check that
1261                                          * they don't change
1262                                          * unexpectedly.
1263                                          */
1264                                         for (i = start; i < end; i++)
1265                                                 map[i] = F_RDLCK;
1266                                         if (pread(fd, &buf[start], len,
1267                                                 start) != len) {
1268                                                 printf("%d: short read\n", id);
1269                                                 exit(1);
1270                                         }
1271                                 }
1272                         } else {
1273                                 for (i = start; i < end; i++)
1274                                         map[i] = F_UNLCK;
1275                         }
1276
1277                         usleep(1000);
1278
1279                         /*
1280                          * Read back the whole region so that we can
1281                          * check that all the bytes we have some kind
1282                          * of claim to have the correct value.
1283                          */
1284                         if (pread(fd, tbuf, sizeof(tbuf), 0) != sizeof(tbuf)) {
1285                                 printf("%d: short read\n", id);
1286                                 exit(1);
1287                         }
1288
1289                         for (i = 0; i < 128; i++) {
1290                                 if (map[i] != F_UNLCK && buf[i] != tbuf[i]) {
1291                                         snprintf(outbuf, sizeof(outbuf),
1292                                             "%d: byte %d expected %d, "
1293                                             "got %d\n", id, i, buf[i], tbuf[i]);
1294                                         write(1, outbuf, strlen(outbuf));
1295                                         exit(1);
1296                                 }
1297                         }
1298                 }
1299                 if (verbose)
1300                         printf("%d[%d]: done\n", id, j);
1301
1302                 exit(0);
1303         }
1304
1305         status = 0;
1306         for (i = 0; i < CHILD_COUNT; i++) {
1307                 status += safe_waitpid(pids[i]);
1308         }
1309         if (status)
1310                 FAIL(status != 0);
1311
1312         SUCCEED;
1313 }
1314
1315 /*
1316  * Test 15 - flock(2) semantcs
1317  *
1318  * When a lock holder has a shared lock and attempts to upgrade that
1319  * shared lock to exclusive, it must drop the shared lock before
1320  * blocking on the exclusive lock.
1321  *
1322  * To test this, we first arrange for two shared locks on the file,
1323  * and then attempt to upgrade one of them to exclusive. This should
1324  * drop one of the shared locks and block. We interrupt the blocking
1325  * lock request and examine the lock state of the file after dropping
1326  * the other shared lock - there should be no active locks at this
1327  * point.
1328  */
1329 static int
1330 test15(int fd, __unused int argc, const __unused char **argv)
1331 {
1332 #ifdef LOCK_EX
1333         /*
1334          * We create a child process to hold the lock which we will
1335          * test. We use a pipe to communicate with the child.
1336          *
1337          * Since we only have one file descriptors and lock ownership
1338          * for flock(2) goes with the file descriptor, we use fcntl to
1339          * set the child's shared lock.
1340          */
1341         int pid;
1342         int pfd[2];
1343         struct flock fl;
1344         char ch;
1345         int res;
1346
1347         if (pipe(pfd) < 0)
1348                 err(1, "pipe");
1349
1350         pid = fork();
1351         if (pid < 0)
1352                 err(1, "fork");
1353
1354         if (pid == 0) {
1355                 /*
1356                  * We are the child. We set a shared lock and then
1357                  * write one byte back to the parent to tell it. The
1358                  * parent will kill us when its done.
1359                  */
1360                 fl.l_start = 0;
1361                 fl.l_len = 0;
1362                 fl.l_type = F_RDLCK;
1363                 fl.l_whence = SEEK_SET;
1364                 if (fcntl(fd, F_SETLK, &fl) < 0)
1365                         err(1, "fcntl(F_SETLK) (child)");
1366                 if (write(pfd[1], "a", 1) < 0)
1367                         err(1, "writing to pipe (child)");
1368                 pause();
1369                 exit(0);
1370         }
1371
1372         /*
1373          * Wait until the child has set its lock and then perform the
1374          * test.
1375          */
1376         if (read(pfd[0], &ch, 1) != 1)
1377                 err(1, "reading from pipe (child)");
1378
1379         (void)dup(fd);
1380         if (flock(fd, LOCK_SH) < 0)
1381                 err(1, "flock shared");
1382
1383         /*
1384          * flock should wait until the alarm and then return -1 with
1385          * errno set to EINTR.
1386          */
1387         printf("15 - flock(2) semantics: ");
1388
1389         alarm(1);
1390         flock(fd, LOCK_EX);
1391
1392         /*
1393          * Kill the child to force it to drop its locks.
1394          */
1395         kill(pid, SIGTERM);
1396         safe_waitpid(pid);
1397
1398         fl.l_start = 0;
1399         fl.l_len = 0;
1400         fl.l_type = F_WRLCK;
1401         fl.l_whence = SEEK_SET;
1402         res = fcntl(fd, F_GETLK, &fl);
1403
1404         close(pfd[0]);
1405         close(pfd[1]);
1406         FAIL(res != 0);
1407         FAIL(fl.l_type != F_UNLCK);
1408
1409         SUCCEED;
1410 #else
1411         return 0;
1412 #endif
1413 }
1414
1415 struct test_ctx {
1416         struct flock tc_fl;
1417         int tc_fd;
1418 };
1419
1420 static void *
1421 test16_func(void *tc_in)
1422 {
1423         uintptr_t error;
1424         struct test_ctx *tc = tc_in;
1425
1426         error = fcntl(tc->tc_fd, F_SETLKW, &tc->tc_fl);
1427
1428         pthread_exit((void *)error);
1429 }
1430
1431 #define THREADS 10
1432
1433 /*
1434  * Test 16 - F_SETLKW from two threads
1435  *
1436  * If two threads within a process are blocked on a lock and the lock
1437  * is granted, make sure things are sane.
1438  */
1439 static int
1440 test16(int fd, __unused int argc, const __unused char **argv)
1441 {
1442         /*
1443          * We create a child process to hold the lock which we will
1444          * test. We use a pipe to communicate with the child.
1445          */
1446         int pid;
1447         int pfd[2];
1448         struct test_ctx tc = { .tc_fd = fd };
1449         char ch;
1450         int i;
1451         int error;
1452         pthread_t thr[THREADS];
1453
1454         if (pipe(pfd) < 0)
1455                 err(1, "pipe");
1456
1457         tc.tc_fl.l_start = 0;
1458         tc.tc_fl.l_len = 0;
1459         tc.tc_fl.l_type = F_WRLCK;
1460         tc.tc_fl.l_whence = SEEK_SET;
1461
1462         pid = fork();
1463         if (pid < 0)
1464                 err(1, "fork");
1465
1466         if (pid == 0) {
1467                 /*
1468                  * We are the child. We set a write lock and then
1469                  * write one byte back to the parent to tell it. The
1470                  * parent will kill us when its done.
1471                  */
1472                 if (fcntl(fd, F_SETLK, &tc.tc_fl) < 0)
1473                         err(1, "F_SETLK (child)");
1474                 if (write(pfd[1], "a", 1) < 0)
1475                         err(1, "writing to pipe (child)");
1476                 pause();
1477                 exit(0);
1478         }
1479
1480         /*
1481          * Wait until the child has set its lock and then perform the
1482          * test.
1483          */
1484         if (read(pfd[0], &ch, 1) != 1)
1485                 err(1, "reading from pipe (child)");
1486
1487         /*
1488          * fcntl should wait until the alarm and then return -1 with
1489          * errno set to EINTR.
1490          */
1491         printf("16 - F_SETLKW on locked region by two threads: ");
1492
1493         for (i = 0; i < THREADS; i++) {
1494                 error = pthread_create(&thr[i], NULL, test16_func, &tc);
1495                 if (error)
1496                         err(1, "pthread_create");
1497         }
1498
1499         /*
1500          * Sleep, then kill the child. This makes me a little sad, but it's
1501          * tricky to tell whether the threads are all really blocked by this
1502          * point.
1503          */
1504         sleep(1);
1505         kill(pid, SIGTERM);
1506         safe_waitpid(pid);
1507         close(pfd[0]);
1508         close(pfd[1]);
1509
1510         for (i = 0; i < THREADS; i++) {
1511                 void *res;
1512                 error = pthread_join(thr[i], &res);
1513                 if (error)
1514                         err(1, "pthread_join");
1515                 FAIL((uintptr_t)res != 0);
1516         }
1517
1518         SUCCEED;
1519 }
1520
1521 struct test {
1522         int (*testfn)(int, int, const char **); /* function to perform the test */
1523         int num;                /* test number */
1524         int intr;               /* non-zero if the test interrupts a lock */
1525 };
1526
1527 static struct test tests[] = {
1528         {       test1,          1,      0       },
1529         {       test2,          2,      0       },
1530         {       test3,          3,      1       },
1531         {       test4,          4,      0       },
1532         {       test5,          5,      1       },
1533         {       test6,          6,      1       },
1534         {       test7,          7,      0       },
1535         {       test8,          8,      0       },
1536         {       test9,          9,      0       },
1537         {       test10,         10,     0       },
1538         {       test11,         11,     1       },
1539         {       test12,         12,     0       },
1540         {       test13,         13,     1       },
1541         {       test14,         14,     0       },
1542         {       test15,         15,     1       },
1543         {       test16,         16,     1       },
1544 };
1545
1546 int
1547 main(int argc, const char *argv[])
1548 {
1549         int testnum;
1550         int fd;
1551         int nointr;
1552         unsigned i;
1553         struct sigaction sa;
1554         int test_argc;
1555         const char **test_argv;
1556
1557         if (argc < 2) {
1558                 errx(1, "usage: flock <directory> [test number] ...");
1559         }
1560
1561         fd = make_file(argv[1], 1024);
1562         if (argc >= 3) {
1563                 testnum = strtol(argv[2], NULL, 0);
1564                 test_argc = argc - 2;
1565                 test_argv = argv + 2;
1566         } else {
1567                 testnum = 0;
1568                 test_argc = 0;
1569                 test_argv = 0;
1570         }
1571
1572         sa.sa_handler = ignore_alarm;
1573         sigemptyset(&sa.sa_mask);
1574         sa.sa_flags = 0;
1575         sigaction(SIGALRM, &sa, 0);
1576
1577         nointr = 0;
1578 #if defined(__FreeBSD__) && __FreeBSD_version < 800040
1579         {
1580                 /*
1581                  * FreeBSD with userland NLM can't interrupt a blocked
1582                  * lock request on an NFS mounted filesystem.
1583                  */
1584                 struct statfs st;
1585                 fstatfs(fd, &st);
1586                 nointr = !strcmp(st.f_fstypename, "nfs");
1587         }
1588 #endif
1589
1590         for (i = 0; i < nitems(tests); i++) {
1591                 if (tests[i].intr && nointr)
1592                         continue;
1593                 if (!testnum || tests[i].num == testnum)
1594                         tests[i].testfn(fd, test_argc, test_argv);
1595         }
1596
1597         return 0;
1598 }