197a3f8ceSart /*-
297a3f8ceSart * Copyright (c) 2008 Isilon Inc http://www.isilon.com/
397a3f8ceSart * Authors: Doug Rabson <dfr@rabson.org>
497a3f8ceSart * Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org>
597a3f8ceSart *
697a3f8ceSart * Redistribution and use in source and binary forms, with or without
797a3f8ceSart * modification, are permitted provided that the following conditions
897a3f8ceSart * are met:
997a3f8ceSart * 1. Redistributions of source code must retain the above copyright
1097a3f8ceSart * notice, this list of conditions and the following disclaimer.
1197a3f8ceSart * 2. Redistributions in binary form must reproduce the above copyright
1297a3f8ceSart * notice, this list of conditions and the following disclaimer in the
1397a3f8ceSart * documentation and/or other materials provided with the distribution.
1497a3f8ceSart *
1597a3f8ceSart * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1697a3f8ceSart * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1797a3f8ceSart * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1897a3f8ceSart * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1997a3f8ceSart * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2097a3f8ceSart * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2197a3f8ceSart * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2297a3f8ceSart * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2397a3f8ceSart * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2497a3f8ceSart * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2597a3f8ceSart * SUCH DAMAGE.
2697a3f8ceSart *
2797a3f8ceSart * $FreeBSD: src/tools/regression/file/flock/flock.c,v 1.3 2008/06/26 10:21:54 dfr Exp $
2897a3f8ceSart */
2997a3f8ceSart
3097a3f8ceSart #include <sys/time.h>
3197a3f8ceSart #include <sys/stat.h>
3297a3f8ceSart
3397a3f8ceSart #include <err.h>
3497a3f8ceSart #include <errno.h>
3597a3f8ceSart #include <fcntl.h>
360d5ae59dSanton #include <limits.h>
3797a3f8ceSart #include <signal.h>
3897a3f8ceSart #include <stdio.h>
3997a3f8ceSart #include <stdlib.h>
4097a3f8ceSart #include <string.h>
41afb1c1edSanton #include <termios.h>
4297a3f8ceSart #include <unistd.h>
43afb1c1edSanton #include <util.h>
4497a3f8ceSart
45cdea53deSanton #include "util.h"
4697a3f8ceSart
47cdea53deSanton int verbose = 0;
4897a3f8ceSart
4997a3f8ceSart static void
ignore_alarm(int __unused sig)5097a3f8ceSart ignore_alarm(int __unused sig)
5197a3f8ceSart {
5297a3f8ceSart }
5397a3f8ceSart
5497a3f8ceSart static int
safe_kill(pid_t pid,int sig)5597a3f8ceSart safe_kill(pid_t pid, int sig)
5697a3f8ceSart {
5797a3f8ceSart int save_errno;
5897a3f8ceSart int status;
5997a3f8ceSart
6097a3f8ceSart save_errno = errno;
6197a3f8ceSart errno = 0;
6297a3f8ceSart status = kill(pid, sig);
6397a3f8ceSart errno = save_errno;
6497a3f8ceSart
6597a3f8ceSart return (status);
6697a3f8ceSart }
6797a3f8ceSart
6897a3f8ceSart /*
6997a3f8ceSart * Test 1 - F_GETLK on unlocked region
7097a3f8ceSart *
7197a3f8ceSart * If no lock is found that would prevent this lock from being
7297a3f8ceSart * created, the structure is left unchanged by this function call
7397a3f8ceSart * except for the lock type which is set to F_UNLCK.
7497a3f8ceSart */
7597a3f8ceSart static int
test1(int fd)7627fff5e2Santon test1(int fd)
7797a3f8ceSart {
7897a3f8ceSart struct flock fl1, fl2;
7997a3f8ceSart
8097a3f8ceSart memset(&fl1, 1, sizeof(fl1));
8197a3f8ceSart fl1.l_type = F_WRLCK;
8297a3f8ceSart fl1.l_whence = SEEK_SET;
8397a3f8ceSart fl2 = fl1;
8497a3f8ceSart
8597a3f8ceSart if (fcntl(fd, F_GETLK, &fl1) < 0)
8697a3f8ceSart err(1, "F_GETLK");
8797a3f8ceSart
8897a3f8ceSart if (verbose) printf("1 - F_GETLK on unlocked region: ");
8997a3f8ceSart FAIL(fl1.l_start != fl2.l_start);
9097a3f8ceSart FAIL(fl1.l_len != fl2.l_len);
9197a3f8ceSart FAIL(fl1.l_pid != fl2.l_pid);
9297a3f8ceSart FAIL(fl1.l_type != F_UNLCK);
9397a3f8ceSart FAIL(fl1.l_whence != fl2.l_whence);
9497a3f8ceSart
9597a3f8ceSart SUCCEED;
9697a3f8ceSart }
9797a3f8ceSart
9897a3f8ceSart /*
9997a3f8ceSart * Test 2 - F_SETLK on locked region
10097a3f8ceSart *
10197a3f8ceSart * If a shared or exclusive lock cannot be set, fcntl returns
10297a3f8ceSart * immediately with EACCES or EAGAIN.
10397a3f8ceSart */
10497a3f8ceSart static int
test2(int fd)10527fff5e2Santon test2(int fd)
10697a3f8ceSart {
10797a3f8ceSart /*
10897a3f8ceSart * We create a child process to hold the lock which we will
10997a3f8ceSart * test. We use a pipe to communicate with the child.
11097a3f8ceSart */
11197a3f8ceSart int pid;
11297a3f8ceSart int pfd[2];
11397a3f8ceSart struct flock fl;
11497a3f8ceSart char ch;
11597a3f8ceSart int res;
11697a3f8ceSart
11797a3f8ceSart if (pipe(pfd) < 0)
11897a3f8ceSart err(1, "pipe");
11997a3f8ceSart
12097a3f8ceSart fl.l_start = 0;
12197a3f8ceSart fl.l_len = 0;
12297a3f8ceSart fl.l_type = F_WRLCK;
12397a3f8ceSart fl.l_whence = SEEK_SET;
12497a3f8ceSart
12597a3f8ceSart pid = fork();
12697a3f8ceSart if (pid < 0)
12797a3f8ceSart err(1, "fork");
12897a3f8ceSart
12997a3f8ceSart if (pid == 0) {
13097a3f8ceSart /*
13197a3f8ceSart * We are the child. We set a write lock and then
13297a3f8ceSart * write one byte back to the parent to tell it. The
13397a3f8ceSart * parent will kill us when its done.
13497a3f8ceSart */
13597a3f8ceSart if (fcntl(fd, F_SETLK, &fl) < 0)
13697a3f8ceSart err(1, "F_SETLK (child)");
13797a3f8ceSart if (write(pfd[1], "a", 1) < 0)
13897a3f8ceSart err(1, "writing to pipe (child)");
13997a3f8ceSart pause();
14097a3f8ceSart exit(0);
14197a3f8ceSart }
14297a3f8ceSart
14397a3f8ceSart /*
14497a3f8ceSart * Wait until the child has set its lock and then perform the
14597a3f8ceSart * test.
14697a3f8ceSart */
14797a3f8ceSart if (read(pfd[0], &ch, 1) != 1)
14897a3f8ceSart err(1, "reading from pipe (child)");
14997a3f8ceSart
15097a3f8ceSart /*
15197a3f8ceSart * fcntl should return -1 with errno set to either EACCES or
15297a3f8ceSart * EAGAIN.
15397a3f8ceSart */
15497a3f8ceSart if (verbose) printf("2 - F_SETLK on locked region: ");
15597a3f8ceSart res = fcntl(fd, F_SETLK, &fl);
15697a3f8ceSart safe_kill(pid, SIGTERM);
15797a3f8ceSart safe_waitpid(pid);
15897a3f8ceSart close(pfd[0]);
15997a3f8ceSart close(pfd[1]);
16097a3f8ceSart FAIL(res == 0);
16197a3f8ceSart FAIL(errno != EACCES && errno != EAGAIN);
16297a3f8ceSart
16397a3f8ceSart SUCCEED;
16497a3f8ceSart }
16597a3f8ceSart
16697a3f8ceSart /*
16797a3f8ceSart * Test 3 - F_SETLKW on locked region
16897a3f8ceSart *
16997a3f8ceSart * If a shared or exclusive lock is blocked by other locks, the
17097a3f8ceSart * process waits until the request can be satisfied.
17197a3f8ceSart *
17297a3f8ceSart * XXX this test hangs on FreeBSD NFS filesystems due to limitations
17397a3f8ceSart * in FreeBSD's client (and server) lockd implementation.
17497a3f8ceSart */
17597a3f8ceSart static int
test3(int fd)17627fff5e2Santon test3(int fd)
17797a3f8ceSart {
17897a3f8ceSart /*
17997a3f8ceSart * We create a child process to hold the lock which we will
18097a3f8ceSart * test. We use a pipe to communicate with the child.
18197a3f8ceSart */
18297a3f8ceSart int pid;
18397a3f8ceSart int pfd[2];
18497a3f8ceSart struct flock fl;
18597a3f8ceSart char ch;
18697a3f8ceSart int res;
18797a3f8ceSart
18897a3f8ceSart if (pipe(pfd) < 0)
18997a3f8ceSart err(1, "pipe");
19097a3f8ceSart
19197a3f8ceSart fl.l_start = 0;
19297a3f8ceSart fl.l_len = 0;
19397a3f8ceSart fl.l_type = F_WRLCK;
19497a3f8ceSart fl.l_whence = SEEK_SET;
19597a3f8ceSart
19697a3f8ceSart pid = fork();
19797a3f8ceSart if (pid < 0)
19897a3f8ceSart err(1, "fork");
19997a3f8ceSart
20097a3f8ceSart if (pid == 0) {
20197a3f8ceSart /*
20297a3f8ceSart * We are the child. We set a write lock and then
20397a3f8ceSart * write one byte back to the parent to tell it. The
20497a3f8ceSart * parent will kill us when its done.
20597a3f8ceSart */
20697a3f8ceSart if (fcntl(fd, F_SETLK, &fl) < 0)
20797a3f8ceSart err(1, "F_SETLK (child)");
20897a3f8ceSart if (write(pfd[1], "a", 1) < 0)
20997a3f8ceSart err(1, "writing to pipe (child)");
21097a3f8ceSart pause();
21197a3f8ceSart exit(0);
21297a3f8ceSart }
21397a3f8ceSart
21497a3f8ceSart /*
21597a3f8ceSart * Wait until the child has set its lock and then perform the
21697a3f8ceSart * test.
21797a3f8ceSart */
21897a3f8ceSart if (read(pfd[0], &ch, 1) != 1)
21997a3f8ceSart err(1, "reading from pipe (child)");
22097a3f8ceSart
22197a3f8ceSart /*
22297a3f8ceSart * fcntl should wait until the alarm and then return -1 with
22397a3f8ceSart * errno set to EINTR.
22497a3f8ceSart */
22597a3f8ceSart if (verbose) printf("3 - F_SETLKW on locked region: ");
22697a3f8ceSart
22797a3f8ceSart alarm(1);
22897a3f8ceSart
22997a3f8ceSart res = fcntl(fd, F_SETLKW, &fl);
23097a3f8ceSart safe_kill(pid, SIGTERM);
23197a3f8ceSart safe_waitpid(pid);
23297a3f8ceSart close(pfd[0]);
23397a3f8ceSart close(pfd[1]);
23497a3f8ceSart FAIL(res == 0);
23597a3f8ceSart FAIL(errno != EINTR);
23697a3f8ceSart
23797a3f8ceSart SUCCEED;
23897a3f8ceSart }
23997a3f8ceSart
24097a3f8ceSart /*
24197a3f8ceSart * Test 4 - F_GETLK on locked region
24297a3f8ceSart *
24397a3f8ceSart * Get the first lock that blocks the lock.
24497a3f8ceSart */
24597a3f8ceSart static int
test4(int fd)24627fff5e2Santon test4(int fd)
24797a3f8ceSart {
24897a3f8ceSart /*
24997a3f8ceSart * We create a child process to hold the lock which we will
25097a3f8ceSart * test. We use a pipe to communicate with the child.
25197a3f8ceSart */
25297a3f8ceSart int pid;
25397a3f8ceSart int pfd[2];
25497a3f8ceSart struct flock fl;
25597a3f8ceSart char ch;
25697a3f8ceSart
25797a3f8ceSart if (pipe(pfd) < 0)
25897a3f8ceSart err(1, "pipe");
25997a3f8ceSart
26097a3f8ceSart fl.l_start = 0;
26197a3f8ceSart fl.l_len = 99;
26297a3f8ceSart fl.l_type = F_WRLCK;
26397a3f8ceSart fl.l_whence = SEEK_SET;
26497a3f8ceSart
26597a3f8ceSart pid = fork();
26697a3f8ceSart if (pid < 0)
26797a3f8ceSart err(1, "fork");
26897a3f8ceSart
26997a3f8ceSart if (pid == 0) {
27097a3f8ceSart /*
27197a3f8ceSart * We are the child. We set a write lock and then
27297a3f8ceSart * write one byte back to the parent to tell it. The
27397a3f8ceSart * parent will kill us when its done.
27497a3f8ceSart */
27597a3f8ceSart if (fcntl(fd, F_SETLK, &fl) < 0)
27697a3f8ceSart err(1, "F_SETLK (child)");
27797a3f8ceSart if (write(pfd[1], "a", 1) < 0)
27897a3f8ceSart err(1, "writing to pipe (child)");
27997a3f8ceSart pause();
28097a3f8ceSart exit(0);
28197a3f8ceSart }
28297a3f8ceSart
28397a3f8ceSart /*
28497a3f8ceSart * Wait until the child has set its lock and then perform the
28597a3f8ceSart * test.
28697a3f8ceSart */
28797a3f8ceSart if (read(pfd[0], &ch, 1) != 1)
28897a3f8ceSart err(1, "reading from pipe (child)");
28997a3f8ceSart
29097a3f8ceSart /*
29197a3f8ceSart * fcntl should return a lock structure reflecting the lock we
29297a3f8ceSart * made in the child process.
29397a3f8ceSart */
29497a3f8ceSart if (fcntl(fd, F_GETLK, &fl) < 0)
29597a3f8ceSart err(1, "F_GETLK");
29697a3f8ceSart
29797a3f8ceSart if (verbose) printf("4 - F_GETLK on locked region: ");
29897a3f8ceSart FAIL(fl.l_start != 0);
29997a3f8ceSart FAIL(fl.l_len != 99);
30097a3f8ceSart FAIL(fl.l_type != F_WRLCK);
30197a3f8ceSart FAIL(fl.l_pid != pid);
30297a3f8ceSart
30397a3f8ceSart safe_kill(pid, SIGTERM);
30497a3f8ceSart safe_waitpid(pid);
30597a3f8ceSart close(pfd[0]);
30697a3f8ceSart close(pfd[1]);
30797a3f8ceSart
30897a3f8ceSart SUCCEED;
30997a3f8ceSart }
31097a3f8ceSart
31197a3f8ceSart /*
31297a3f8ceSart * Test 5 - F_SETLKW simple deadlock
31397a3f8ceSart *
31497a3f8ceSart * If a blocking shared lock request would cause a deadlock (i.e. the
31597a3f8ceSart * lock request is blocked by a process which is itself blocked on a
31697a3f8ceSart * lock currently owned by the process making the new request),
31797a3f8ceSart * EDEADLK is returned.
31897a3f8ceSart */
31997a3f8ceSart static int
test5(int fd)32027fff5e2Santon test5(int fd)
32197a3f8ceSart {
32297a3f8ceSart /*
32397a3f8ceSart * We create a child process to hold the lock which we will
32497a3f8ceSart * test. Because our test relies on the child process being
32597a3f8ceSart * blocked on the parent's lock, we can't easily use a pipe to
32697a3f8ceSart * synchronize so we just sleep in the parent to given the
32797a3f8ceSart * child a chance to setup.
32897a3f8ceSart *
32997a3f8ceSart * To create the deadlock condition, we arrange for the parent
33097a3f8ceSart * to lock the first byte of the file and the child to lock
33197a3f8ceSart * the second byte. After locking the second byte, the child
33297a3f8ceSart * will attempt to lock the first byte of the file, and
33397a3f8ceSart * block. The parent will then attempt to lock the second byte
33497a3f8ceSart * (owned by the child) which should cause deadlock.
33597a3f8ceSart */
33697a3f8ceSart int pid;
33797a3f8ceSart struct flock fl;
33897a3f8ceSart int res;
33997a3f8ceSart
34097a3f8ceSart /*
34197a3f8ceSart * Lock the first byte in the parent.
34297a3f8ceSart */
34397a3f8ceSart fl.l_start = 0;
34497a3f8ceSart fl.l_len = 1;
34597a3f8ceSart fl.l_type = F_WRLCK;
34697a3f8ceSart fl.l_whence = SEEK_SET;
34797a3f8ceSart if (fcntl(fd, F_SETLK, &fl) < 0)
34897a3f8ceSart err(1, "F_SETLK 1 (parent)");
34997a3f8ceSart
35097a3f8ceSart pid = fork();
35197a3f8ceSart if (pid < 0)
35297a3f8ceSart err(1, "fork");
35397a3f8ceSart
35497a3f8ceSart if (pid == 0) {
35597a3f8ceSart /*
35697a3f8ceSart * Lock the second byte in the child and then block on
35797a3f8ceSart * the parent's lock.
35897a3f8ceSart */
35997a3f8ceSart fl.l_start = 1;
36097a3f8ceSart if (fcntl(fd, F_SETLK, &fl) < 0)
36197a3f8ceSart err(1, "F_SETLK (child)");
36297a3f8ceSart fl.l_start = 0;
36397a3f8ceSart if (fcntl(fd, F_SETLKW, &fl) < 0)
36497a3f8ceSart err(1, "F_SETLKW (child)");
36597a3f8ceSart exit(0);
36697a3f8ceSart }
36797a3f8ceSart
36897a3f8ceSart /*
36997a3f8ceSart * Wait until the child has set its lock and then perform the
37097a3f8ceSart * test.
37197a3f8ceSart */
37297a3f8ceSart sleep(1);
37397a3f8ceSart
37497a3f8ceSart /*
37597a3f8ceSart * fcntl should immediately return -1 with errno set to
37697a3f8ceSart * EDEADLK. If the alarm fires, we failed to detect the
37797a3f8ceSart * deadlock.
37897a3f8ceSart */
37997a3f8ceSart alarm(1);
38097a3f8ceSart if (verbose) printf("5 - F_SETLKW simple deadlock: ");
38197a3f8ceSart
38297a3f8ceSart fl.l_start = 1;
38397a3f8ceSart res = fcntl(fd, F_SETLKW, &fl);
38497a3f8ceSart safe_kill(pid, SIGTERM);
38597a3f8ceSart safe_waitpid(pid);
38697a3f8ceSart
38797a3f8ceSart FAIL(res == 0);
38897a3f8ceSart FAIL(errno != EDEADLK);
38997a3f8ceSart
39097a3f8ceSart fl.l_start = 0;
39197a3f8ceSart fl.l_len = 0;
39297a3f8ceSart fl.l_type = F_UNLCK;
39397a3f8ceSart if (fcntl(fd, F_SETLK, &fl) < 0)
39497a3f8ceSart err(1, "F_UNLCK");
39597a3f8ceSart
39697a3f8ceSart /*
39797a3f8ceSart * Cancel the alarm to avoid confusing later tests.
39897a3f8ceSart */
39997a3f8ceSart alarm(0);
40097a3f8ceSart
40197a3f8ceSart SUCCEED;
40297a3f8ceSart }
40397a3f8ceSart
40497a3f8ceSart /*
40597a3f8ceSart * Test 6 - F_SETLKW complex deadlock.
40697a3f8ceSart *
40797a3f8ceSart * This test involves three process, P, C1 and C2. We set things up so
40897a3f8ceSart * that P locks byte zero, C1 locks byte 1 and C2 locks byte 2. We
40997a3f8ceSart * also block C2 by attempting to lock byte zero. Lastly, P attempts
41097a3f8ceSart * to lock a range including byte 1 and 2. This represents a deadlock
41197a3f8ceSart * (due to C2's blocking attempt to lock byte zero).
41297a3f8ceSart */
41397a3f8ceSart static int
test6(int fd)41427fff5e2Santon test6(int fd)
41597a3f8ceSart {
41697a3f8ceSart /*
41797a3f8ceSart * Because our test relies on the child process being blocked
41897a3f8ceSart * on the parent's lock, we can't easily use a pipe to
41997a3f8ceSart * synchronize so we just sleep in the parent to given the
42097a3f8ceSart * children a chance to setup.
42197a3f8ceSart */
42297a3f8ceSart int pid1, pid2;
42397a3f8ceSart struct flock fl;
42497a3f8ceSart int res;
42597a3f8ceSart
42697a3f8ceSart /*
42797a3f8ceSart * Lock the first byte in the parent.
42897a3f8ceSart */
42997a3f8ceSart fl.l_start = 0;
43097a3f8ceSart fl.l_len = 1;
43197a3f8ceSart fl.l_type = F_WRLCK;
43297a3f8ceSart fl.l_whence = SEEK_SET;
43397a3f8ceSart if (fcntl(fd, F_SETLK, &fl) < 0)
43497a3f8ceSart err(1, "F_SETLK 1 (parent)");
43597a3f8ceSart
43697a3f8ceSart pid1 = fork();
43797a3f8ceSart if (pid1 < 0)
43897a3f8ceSart err(1, "fork");
43997a3f8ceSart
44097a3f8ceSart if (pid1 == 0) {
44197a3f8ceSart /*
44297a3f8ceSart * C1
44397a3f8ceSart * Lock the second byte in the child and then sleep
44497a3f8ceSart */
44597a3f8ceSart fl.l_start = 1;
44697a3f8ceSart if (fcntl(fd, F_SETLK, &fl) < 0)
44797a3f8ceSart err(1, "F_SETLK (child1)");
44897a3f8ceSart pause();
44997a3f8ceSart exit(0);
45097a3f8ceSart }
45197a3f8ceSart
45297a3f8ceSart pid2 = fork();
45397a3f8ceSart if (pid2 < 0)
45497a3f8ceSart err(1, "fork");
45597a3f8ceSart
45697a3f8ceSart if (pid2 == 0) {
45797a3f8ceSart /*
45897a3f8ceSart * C2
45997a3f8ceSart * Lock the third byte in the child and then block on
46097a3f8ceSart * the parent's lock.
46197a3f8ceSart */
46297a3f8ceSart fl.l_start = 2;
46397a3f8ceSart if (fcntl(fd, F_SETLK, &fl) < 0)
46497a3f8ceSart err(1, "F_SETLK (child2)");
46597a3f8ceSart fl.l_start = 0;
46697a3f8ceSart if (fcntl(fd, F_SETLKW, &fl) < 0)
46797a3f8ceSart err(1, "F_SETLKW (child2)");
46897a3f8ceSart exit(0);
46997a3f8ceSart }
47097a3f8ceSart
47197a3f8ceSart /*
47297a3f8ceSart * Wait until the children have set their locks and then
47397a3f8ceSart * perform the test.
47497a3f8ceSart */
47597a3f8ceSart sleep(1);
47697a3f8ceSart
47797a3f8ceSart /*
47897a3f8ceSart * fcntl should immediately return -1 with errno set to
47997a3f8ceSart * EDEADLK. If the alarm fires, we failed to detect the
48097a3f8ceSart * deadlock.
48197a3f8ceSart */
48297a3f8ceSart alarm(1);
48397a3f8ceSart if (verbose) printf("6 - F_SETLKW complex deadlock: ");
48497a3f8ceSart
48597a3f8ceSart fl.l_start = 1;
48697a3f8ceSart fl.l_len = 2;
48797a3f8ceSart res = fcntl(fd, F_SETLKW, &fl);
48897a3f8ceSart safe_kill(pid1, SIGTERM);
48997a3f8ceSart safe_waitpid(pid1);
49097a3f8ceSart safe_kill(pid2, SIGTERM);
49197a3f8ceSart safe_waitpid(pid2);
49297a3f8ceSart
49397a3f8ceSart fl.l_start = 0;
49497a3f8ceSart fl.l_len = 0;
49597a3f8ceSart fl.l_type = F_UNLCK;
49697a3f8ceSart if (fcntl(fd, F_SETLK, &fl) < 0)
49797a3f8ceSart err(1, "F_UNLCK");
49897a3f8ceSart
49997a3f8ceSart FAIL(res == 0);
50097a3f8ceSart FAIL(errno != EDEADLK);
50197a3f8ceSart
50297a3f8ceSart /*
50397a3f8ceSart * Cancel the alarm to avoid confusing later tests.
50497a3f8ceSart */
50597a3f8ceSart alarm(0);
50697a3f8ceSart
50797a3f8ceSart SUCCEED;
50897a3f8ceSart }
50997a3f8ceSart
51097a3f8ceSart /*
51197a3f8ceSart * Test 7 - F_SETLK shared lock on exclusive locked region
51297a3f8ceSart *
51397a3f8ceSart * If a shared or exclusive lock cannot be set, fcntl returns
51497a3f8ceSart * immediately with EACCES or EAGAIN.
51597a3f8ceSart */
51697a3f8ceSart static int
test7(int fd)51727fff5e2Santon test7(int fd)
51897a3f8ceSart {
51997a3f8ceSart /*
52097a3f8ceSart * We create a child process to hold the lock which we will
52197a3f8ceSart * test. We use a pipe to communicate with the child.
52297a3f8ceSart */
52397a3f8ceSart int pid;
52497a3f8ceSart int pfd[2];
52597a3f8ceSart struct flock fl;
52697a3f8ceSart char ch;
52797a3f8ceSart int res;
52897a3f8ceSart
52997a3f8ceSart if (pipe(pfd) < 0)
53097a3f8ceSart err(1, "pipe");
53197a3f8ceSart
53297a3f8ceSart fl.l_start = 0;
53397a3f8ceSart fl.l_len = 0;
53497a3f8ceSart fl.l_type = F_WRLCK;
53597a3f8ceSart fl.l_whence = SEEK_SET;
53697a3f8ceSart
53797a3f8ceSart pid = fork();
53897a3f8ceSart if (pid < 0)
53997a3f8ceSart err(1, "fork");
54097a3f8ceSart
54197a3f8ceSart if (pid == 0) {
54297a3f8ceSart /*
54397a3f8ceSart * We are the child. We set a write lock and then
54497a3f8ceSart * write one byte back to the parent to tell it. The
54597a3f8ceSart * parent will kill us when its done.
54697a3f8ceSart */
54797a3f8ceSart if (fcntl(fd, F_SETLK, &fl) < 0)
54897a3f8ceSart err(1, "F_SETLK (child)");
54997a3f8ceSart if (write(pfd[1], "a", 1) < 0)
55097a3f8ceSart err(1, "writing to pipe (child)");
55197a3f8ceSart pause();
55297a3f8ceSart exit(0);
55397a3f8ceSart }
55497a3f8ceSart
55597a3f8ceSart /*
55697a3f8ceSart * Wait until the child has set its lock and then perform the
55797a3f8ceSart * test.
55897a3f8ceSart */
55997a3f8ceSart if (read(pfd[0], &ch, 1) != 1)
56097a3f8ceSart err(1, "reading from pipe (child)");
56197a3f8ceSart
56297a3f8ceSart /*
56397a3f8ceSart * fcntl should wait until the alarm and then return -1 with
56497a3f8ceSart * errno set to EINTR.
56597a3f8ceSart */
56697a3f8ceSart if (verbose) printf("7 - F_SETLK shared lock on exclusive locked region: ");
56797a3f8ceSart
56897a3f8ceSart fl.l_type = F_RDLCK;
56997a3f8ceSart res = fcntl(fd, F_SETLK, &fl);
57097a3f8ceSart safe_kill(pid, SIGTERM);
57197a3f8ceSart safe_waitpid(pid);
57297a3f8ceSart close(pfd[0]);
57397a3f8ceSart close(pfd[1]);
57497a3f8ceSart
57597a3f8ceSart FAIL(res == 0);
57697a3f8ceSart FAIL(errno != EACCES && errno != EAGAIN);
57797a3f8ceSart
57897a3f8ceSart SUCCEED;
57997a3f8ceSart }
58097a3f8ceSart
58197a3f8ceSart /*
58297a3f8ceSart * Test 8 - F_SETLK shared lock on share locked region
58397a3f8ceSart *
58497a3f8ceSart * When a shared lock is set on a segment of a file, other processes
58597a3f8ceSart * shall be able to set shared locks on that segment or a portion of
58697a3f8ceSart * it.
58797a3f8ceSart */
58897a3f8ceSart static int
test8(int fd)58927fff5e2Santon test8(int fd)
59097a3f8ceSart {
59197a3f8ceSart /*
59297a3f8ceSart * We create a child process to hold the lock which we will
59397a3f8ceSart * test. We use a pipe to communicate with the child.
59497a3f8ceSart */
59597a3f8ceSart int pid;
59697a3f8ceSart int pfd[2];
59797a3f8ceSart struct flock fl;
59897a3f8ceSart char ch;
59997a3f8ceSart int res;
60097a3f8ceSart
60197a3f8ceSart if (pipe(pfd) < 0)
60297a3f8ceSart err(1, "pipe");
60397a3f8ceSart
60497a3f8ceSart fl.l_start = 0;
60597a3f8ceSart fl.l_len = 0;
60697a3f8ceSart fl.l_type = F_RDLCK;
60797a3f8ceSart fl.l_whence = SEEK_SET;
60897a3f8ceSart
60997a3f8ceSart pid = fork();
61097a3f8ceSart if (pid < 0)
61197a3f8ceSart err(1, "fork");
61297a3f8ceSart
61397a3f8ceSart if (pid == 0) {
61497a3f8ceSart /*
61597a3f8ceSart * We are the child. We set a write lock and then
61697a3f8ceSart * write one byte back to the parent to tell it. The
61797a3f8ceSart * parent will kill us when its done.
61897a3f8ceSart */
61997a3f8ceSart if (fcntl(fd, F_SETLK, &fl) < 0)
62097a3f8ceSart err(1, "F_SETLK (child)");
62197a3f8ceSart if (write(pfd[1], "a", 1) < 0)
62297a3f8ceSart err(1, "writing to pipe (child)");
62397a3f8ceSart pause();
62497a3f8ceSart exit(0);
62597a3f8ceSart }
62697a3f8ceSart
62797a3f8ceSart /*
62897a3f8ceSart * Wait until the child has set its lock and then perform the
62997a3f8ceSart * test.
63097a3f8ceSart */
63197a3f8ceSart if (read(pfd[0], &ch, 1) != 1)
63297a3f8ceSart err(1, "reading from pipe (child)");
63397a3f8ceSart
63497a3f8ceSart /*
63597a3f8ceSart * fcntl should wait until the alarm and then return -1 with
63697a3f8ceSart * errno set to EINTR.
63797a3f8ceSart */
63897a3f8ceSart if (verbose) printf("8 - F_SETLK shared lock on share locked region: ");
63997a3f8ceSart
64097a3f8ceSart fl.l_type = F_RDLCK;
64197a3f8ceSart res = fcntl(fd, F_SETLK, &fl);
64297a3f8ceSart
64397a3f8ceSart safe_kill(pid, SIGTERM);
64497a3f8ceSart safe_waitpid(pid);
64597a3f8ceSart close(pfd[0]);
64697a3f8ceSart close(pfd[1]);
64797a3f8ceSart
64897a3f8ceSart fl.l_start = 0;
64997a3f8ceSart fl.l_len = 0;
65097a3f8ceSart fl.l_type = F_UNLCK;
65197a3f8ceSart if (fcntl(fd, F_SETLK, &fl) < 0)
65297a3f8ceSart err(1, "F_UNLCK");
65397a3f8ceSart
65497a3f8ceSart FAIL(res != 0);
65597a3f8ceSart
65697a3f8ceSart SUCCEED;
65797a3f8ceSart }
65897a3f8ceSart
65997a3f8ceSart /*
66097a3f8ceSart * Test 9 - F_SETLK exclusive lock on share locked region
66197a3f8ceSart *
66297a3f8ceSart * If a shared or exclusive lock cannot be set, fcntl returns
66397a3f8ceSart * immediately with EACCES or EAGAIN.
66497a3f8ceSart */
66597a3f8ceSart static int
test9(int fd)66627fff5e2Santon test9(int fd)
66797a3f8ceSart {
66897a3f8ceSart /*
66997a3f8ceSart * We create a child process to hold the lock which we will
67097a3f8ceSart * test. We use a pipe to communicate with the child.
67197a3f8ceSart */
67297a3f8ceSart int pid;
67397a3f8ceSart int pfd[2];
67497a3f8ceSart struct flock fl;
67597a3f8ceSart char ch;
67697a3f8ceSart int res;
67797a3f8ceSart
67897a3f8ceSart if (pipe(pfd) < 0)
67997a3f8ceSart err(1, "pipe");
68097a3f8ceSart
68197a3f8ceSart fl.l_start = 0;
68297a3f8ceSart fl.l_len = 0;
68397a3f8ceSart fl.l_type = F_RDLCK;
68497a3f8ceSart fl.l_whence = SEEK_SET;
68597a3f8ceSart
68697a3f8ceSart pid = fork();
68797a3f8ceSart if (pid < 0)
68897a3f8ceSart err(1, "fork");
68997a3f8ceSart
69097a3f8ceSart if (pid == 0) {
69197a3f8ceSart /*
69297a3f8ceSart * We are the child. We set a write lock and then
69397a3f8ceSart * write one byte back to the parent to tell it. The
69497a3f8ceSart * parent will kill us when its done.
69597a3f8ceSart */
69697a3f8ceSart if (fcntl(fd, F_SETLK, &fl) < 0)
69797a3f8ceSart err(1, "F_SETLK (child)");
69897a3f8ceSart if (write(pfd[1], "a", 1) < 0)
69997a3f8ceSart err(1, "writing to pipe (child)");
70097a3f8ceSart pause();
70197a3f8ceSart exit(0);
70297a3f8ceSart }
70397a3f8ceSart
70497a3f8ceSart /*
70597a3f8ceSart * Wait until the child has set its lock and then perform the
70697a3f8ceSart * test.
70797a3f8ceSart */
70897a3f8ceSart if (read(pfd[0], &ch, 1) != 1)
70997a3f8ceSart err(1, "reading from pipe (child)");
71097a3f8ceSart
71197a3f8ceSart /*
71297a3f8ceSart * fcntl should wait until the alarm and then return -1 with
71397a3f8ceSart * errno set to EINTR.
71497a3f8ceSart */
71597a3f8ceSart if (verbose) printf("9 - F_SETLK exclusive lock on share locked region: ");
71697a3f8ceSart
71797a3f8ceSart fl.l_type = F_WRLCK;
71897a3f8ceSart res = fcntl(fd, F_SETLK, &fl);
71997a3f8ceSart safe_kill(pid, SIGTERM);
72097a3f8ceSart safe_waitpid(pid);
72197a3f8ceSart close(pfd[0]);
72297a3f8ceSart close(pfd[1]);
72397a3f8ceSart
72497a3f8ceSart FAIL(res == 0);
72597a3f8ceSart FAIL(errno != EACCES && errno != EAGAIN);
72697a3f8ceSart
72797a3f8ceSart SUCCEED;
72897a3f8ceSart }
72997a3f8ceSart
73097a3f8ceSart /*
73197a3f8ceSart * Test 10 - trying to set bogus pid or sysid values
73297a3f8ceSart *
73397a3f8ceSart * The l_pid and l_sysid fields are only used with F_GETLK to return
73497a3f8ceSart * the process ID of the process holding a blocking lock and the
73597a3f8ceSart * system ID of the system that owns that process
73697a3f8ceSart */
73797a3f8ceSart static int
test10(int fd)73827fff5e2Santon test10(int fd)
73997a3f8ceSart {
74097a3f8ceSart /*
74197a3f8ceSart * We create a child process to hold the lock which we will
74297a3f8ceSart * test. We use a pipe to communicate with the child.
74397a3f8ceSart */
74497a3f8ceSart int pid;
74597a3f8ceSart int pfd[2];
74697a3f8ceSart struct flock fl;
74797a3f8ceSart char ch;
74897a3f8ceSart
74997a3f8ceSart if (pipe(pfd) < 0)
75097a3f8ceSart err(1, "pipe");
75197a3f8ceSart
75297a3f8ceSart fl.l_start = 0;
75397a3f8ceSart fl.l_len = 0;
75497a3f8ceSart fl.l_type = F_WRLCK;
75597a3f8ceSart fl.l_whence = SEEK_SET;
75697a3f8ceSart fl.l_pid = 9999;
75797a3f8ceSart
75897a3f8ceSart pid = fork();
75997a3f8ceSart if (pid < 0)
76097a3f8ceSart err(1, "fork");
76197a3f8ceSart
76297a3f8ceSart if (pid == 0) {
76397a3f8ceSart /*
76497a3f8ceSart * We are the child. We set a write lock and then
76597a3f8ceSart * write one byte back to the parent to tell it. The
76697a3f8ceSart * parent will kill us when its done.
76797a3f8ceSart */
76897a3f8ceSart if (fcntl(fd, F_SETLK, &fl) < 0)
76997a3f8ceSart err(1, "F_SETLK (child)");
77097a3f8ceSart if (write(pfd[1], "a", 1) < 0)
77197a3f8ceSart err(1, "writing to pipe (child)");
77297a3f8ceSart pause();
77397a3f8ceSart exit(0);
77497a3f8ceSart }
77597a3f8ceSart
77697a3f8ceSart /*
77797a3f8ceSart * Wait until the child has set its lock and then perform the
77897a3f8ceSart * test.
77997a3f8ceSart */
78097a3f8ceSart if (read(pfd[0], &ch, 1) != 1)
78197a3f8ceSart err(1, "reading from pipe (child)");
78297a3f8ceSart
78397a3f8ceSart if (verbose) printf("10 - trying to set bogus pid or sysid values: ");
78497a3f8ceSart
78597a3f8ceSart if (fcntl(fd, F_GETLK, &fl) < 0)
78697a3f8ceSart err(1, "F_GETLK");
78797a3f8ceSart
78897a3f8ceSart safe_kill(pid, SIGTERM);
78997a3f8ceSart safe_waitpid(pid);
79097a3f8ceSart close(pfd[0]);
79197a3f8ceSart close(pfd[1]);
79297a3f8ceSart
79397a3f8ceSart FAIL(fl.l_pid != pid);
79497a3f8ceSart
79597a3f8ceSart SUCCEED;
79697a3f8ceSart }
79797a3f8ceSart
79897a3f8ceSart /*
79997a3f8ceSart * Test 11 - remote locks
80097a3f8ceSart *
80197a3f8ceSart * XXX temporary interface which will be removed when the kernel lockd
80297a3f8ceSart * is added.
80397a3f8ceSart */
80497a3f8ceSart static int
test11(int fd)80527fff5e2Santon test11(int fd)
80697a3f8ceSart {
80797a3f8ceSart #ifdef F_SETLK_REMOTE
80897a3f8ceSart struct flock fl;
80997a3f8ceSart int res;
81097a3f8ceSart
81197a3f8ceSart if (geteuid() != 0)
81297a3f8ceSart return 0;
81397a3f8ceSart
81497a3f8ceSart fl.l_start = 0;
81597a3f8ceSart fl.l_len = 0;
81697a3f8ceSart fl.l_type = F_WRLCK;
81797a3f8ceSart fl.l_whence = SEEK_SET;
81897a3f8ceSart fl.l_pid = 9999;
81997a3f8ceSart fl.l_sysid = 1001;
82097a3f8ceSart
82197a3f8ceSart if (verbose) printf("11 - remote locks: ");
82297a3f8ceSart
82397a3f8ceSart res = fcntl(fd, F_SETLK_REMOTE, &fl);
82497a3f8ceSart FAIL(res != 0);
82597a3f8ceSart
82697a3f8ceSart fl.l_sysid = 1002;
82797a3f8ceSart res = fcntl(fd, F_SETLK_REMOTE, &fl);
82897a3f8ceSart FAIL(res == 0);
82997a3f8ceSart FAIL(errno != EACCES && errno != EAGAIN);
83097a3f8ceSart
83197a3f8ceSart res = fcntl(fd, F_GETLK, &fl);
83297a3f8ceSart FAIL(res != 0);
83397a3f8ceSart FAIL(fl.l_pid != 9999);
83497a3f8ceSart FAIL(fl.l_sysid != 1001);
83597a3f8ceSart
83697a3f8ceSart fl.l_type = F_UNLCK;
83797a3f8ceSart fl.l_sysid = 1001;
83897a3f8ceSart fl.l_start = 0;
83997a3f8ceSart fl.l_len = 0;
84097a3f8ceSart res = fcntl(fd, F_SETLK_REMOTE, &fl);
84197a3f8ceSart FAIL(res != 0);
84297a3f8ceSart
84397a3f8ceSart fl.l_pid = 1234;
84497a3f8ceSart fl.l_sysid = 1001;
84597a3f8ceSart fl.l_start = 0;
84697a3f8ceSart fl.l_len = 1;
84797a3f8ceSart fl.l_whence = SEEK_SET;
84897a3f8ceSart fl.l_type = F_RDLCK;
84997a3f8ceSart res = fcntl(fd, F_SETLK_REMOTE, &fl);
85097a3f8ceSart FAIL(res != 0);
85197a3f8ceSart
85297a3f8ceSart fl.l_sysid = 1002;
85397a3f8ceSart res = fcntl(fd, F_SETLK_REMOTE, &fl);
85497a3f8ceSart FAIL(res != 0);
85597a3f8ceSart
85697a3f8ceSart fl.l_type = F_UNLCKSYS;
85797a3f8ceSart fl.l_sysid = 1001;
85897a3f8ceSart res = fcntl(fd, F_SETLK_REMOTE, &fl);
85997a3f8ceSart FAIL(res != 0);
86097a3f8ceSart
86197a3f8ceSart fl.l_type = F_WRLCK;
86297a3f8ceSart res = fcntl(fd, F_GETLK, &fl);
86397a3f8ceSart FAIL(res != 0);
86497a3f8ceSart FAIL(fl.l_pid != 1234);
86597a3f8ceSart FAIL(fl.l_sysid != 1002);
86697a3f8ceSart
86797a3f8ceSart fl.l_type = F_UNLCKSYS;
86897a3f8ceSart fl.l_sysid = 1002;
86997a3f8ceSart res = fcntl(fd, F_SETLK_REMOTE, &fl);
87097a3f8ceSart FAIL(res != 0);
87197a3f8ceSart
87297a3f8ceSart SUCCEED;
87397a3f8ceSart #else
87497a3f8ceSart return 0;
87597a3f8ceSart #endif
87697a3f8ceSart }
87797a3f8ceSart
87897a3f8ceSart /*
87997a3f8ceSart * Test 12 - F_SETLKW on locked region which is then unlocked
88097a3f8ceSart *
88197a3f8ceSart * If a shared or exclusive lock is blocked by other locks, the
88297a3f8ceSart * process waits until the request can be satisfied.
88397a3f8ceSart */
88497a3f8ceSart static int
test12(int fd)88527fff5e2Santon test12(int fd)
88697a3f8ceSart {
88797a3f8ceSart /*
88897a3f8ceSart * We create a child process to hold the lock which we will
88997a3f8ceSart * test. We use a pipe to communicate with the child.
89097a3f8ceSart */
89197a3f8ceSart int pid;
89297a3f8ceSart int pfd[2];
89397a3f8ceSart struct flock fl;
89497a3f8ceSart char ch;
89597a3f8ceSart int res;
89697a3f8ceSart
89797a3f8ceSart if (pipe(pfd) < 0)
89897a3f8ceSart err(1, "pipe");
89997a3f8ceSart
90097a3f8ceSart fl.l_start = 0;
90197a3f8ceSart fl.l_len = 0;
90297a3f8ceSart fl.l_type = F_WRLCK;
90397a3f8ceSart fl.l_whence = SEEK_SET;
90497a3f8ceSart
90597a3f8ceSart pid = fork();
90697a3f8ceSart if (pid < 0)
90797a3f8ceSart err(1, "fork");
90897a3f8ceSart
90997a3f8ceSart if (pid == 0) {
91097a3f8ceSart /*
91197a3f8ceSart * We are the child. We set a write lock and then
91297a3f8ceSart * write one byte back to the parent to tell it. The
91397a3f8ceSart * parent will kill us when its done.
91497a3f8ceSart */
91597a3f8ceSart if (fcntl(fd, F_SETLK, &fl) < 0)
91697a3f8ceSart err(1, "F_SETLK (child)");
91797a3f8ceSart if (write(pfd[1], "a", 1) < 0)
91897a3f8ceSart err(1, "writing to pipe (child)");
91997a3f8ceSart
92097a3f8ceSart sleep(1);
92197a3f8ceSart exit(0);
92297a3f8ceSart }
92397a3f8ceSart
92497a3f8ceSart /*
92597a3f8ceSart * Wait until the child has set its lock and then perform the
92697a3f8ceSart * test.
92797a3f8ceSart */
92897a3f8ceSart if (read(pfd[0], &ch, 1) != 1)
92997a3f8ceSart err(1, "reading from pipe (child)");
93097a3f8ceSart
93197a3f8ceSart /*
93297a3f8ceSart * fcntl should wait until the alarm and then return -1 with
93397a3f8ceSart * errno set to EINTR.
93497a3f8ceSart */
93597a3f8ceSart if (verbose) printf("12 - F_SETLKW on locked region which is then unlocked: ");
93697a3f8ceSart
93797a3f8ceSart //alarm(1);
93897a3f8ceSart
93997a3f8ceSart res = fcntl(fd, F_SETLKW, &fl);
94097a3f8ceSart safe_kill(pid, SIGTERM);
94197a3f8ceSart safe_waitpid(pid);
94297a3f8ceSart close(pfd[0]);
94397a3f8ceSart close(pfd[1]);
94497a3f8ceSart FAIL(res != 0);
94597a3f8ceSart
94697a3f8ceSart fl.l_start = 0;
94797a3f8ceSart fl.l_len = 0;
94897a3f8ceSart fl.l_type = F_UNLCK;
94997a3f8ceSart if (fcntl(fd, F_SETLK, &fl) < 0)
95097a3f8ceSart err(1, "F_UNLCK");
95197a3f8ceSart
95297a3f8ceSart SUCCEED;
95397a3f8ceSart }
95497a3f8ceSart
95597a3f8ceSart /*
95697a3f8ceSart * Test 13 - F_SETLKW on locked region, race with owner
95797a3f8ceSart *
95897a3f8ceSart * If a shared or exclusive lock is blocked by other locks, the
95997a3f8ceSart * process waits until the request can be satisfied.
96097a3f8ceSart */
96197a3f8ceSart static int
test13(int fd)96227fff5e2Santon test13(int fd)
96397a3f8ceSart {
96497a3f8ceSart /*
96597a3f8ceSart * We create a child process to hold the lock which we will
96697a3f8ceSart * test. We use a pipe to communicate with the child.
96797a3f8ceSart */
96897a3f8ceSart int i;
96997a3f8ceSart int pid;
97097a3f8ceSart int pfd[2];
97197a3f8ceSart struct flock fl;
97297a3f8ceSart char ch;
97397a3f8ceSart int res;
97497a3f8ceSart struct itimerval itv;
97597a3f8ceSart
97697a3f8ceSart if (verbose) printf("13 - F_SETLKW on locked region, race with owner: ");
97797a3f8ceSart fflush(stdout);
97897a3f8ceSart
97997a3f8ceSart for (i = 0; i < 100; i++) {
98097a3f8ceSart if (pipe(pfd) < 0)
98197a3f8ceSart err(1, "pipe");
98297a3f8ceSart
98397a3f8ceSart fl.l_start = 0;
98497a3f8ceSart fl.l_len = 0;
98597a3f8ceSart fl.l_type = F_WRLCK;
98697a3f8ceSart fl.l_whence = SEEK_SET;
98797a3f8ceSart
98897a3f8ceSart pid = fork();
98997a3f8ceSart if (pid < 0)
99097a3f8ceSart err(1, "fork");
99197a3f8ceSart
99297a3f8ceSart if (pid == 0) {
99397a3f8ceSart /*
99497a3f8ceSart * We are the child. We set a write lock and then
99597a3f8ceSart * write one byte back to the parent to tell it. The
99697a3f8ceSart * parent will kill us when its done.
99797a3f8ceSart */
99897a3f8ceSart if (fcntl(fd, F_SETLK, &fl) < 0)
99997a3f8ceSart err(1, "F_SETLK (child)");
100097a3f8ceSart if (write(pfd[1], "a", 1) < 0)
100197a3f8ceSart err(1, "writing to pipe (child)");
100297a3f8ceSart
100397a3f8ceSart sleep(1);
100497a3f8ceSart exit(0);
100597a3f8ceSart }
100697a3f8ceSart
100797a3f8ceSart /*
100897a3f8ceSart * Wait until the child has set its lock and then perform the
100997a3f8ceSart * test.
101097a3f8ceSart */
101197a3f8ceSart while (read(pfd[0], &ch, 1) != 1) {
101297a3f8ceSart if (errno == EINTR)
101397a3f8ceSart continue;
101497a3f8ceSart err(1, "reading from pipe (child)");
101597a3f8ceSart }
101697a3f8ceSart
101797a3f8ceSart /*
101897a3f8ceSart * fcntl should wait until the alarm and then return -1 with
101997a3f8ceSart * errno set to EINTR.
102097a3f8ceSart */
102197a3f8ceSart itv.it_interval.tv_sec = 0;
102297a3f8ceSart itv.it_interval.tv_usec = 0;
102397a3f8ceSart itv.it_value.tv_sec = 0;
102497a3f8ceSart itv.it_value.tv_usec = 2;
102597a3f8ceSart setitimer(ITIMER_REAL, &itv, NULL);
102697a3f8ceSart
102797a3f8ceSart res = fcntl(fd, F_SETLKW, &fl);
102897a3f8ceSart safe_kill(pid, SIGTERM);
102997a3f8ceSart safe_waitpid(pid);
103097a3f8ceSart close(pfd[0]);
103197a3f8ceSart close(pfd[1]);
103297a3f8ceSart FAIL(!(res == 0 || (res == -1 && errno == EINTR)));
103397a3f8ceSart
103497a3f8ceSart fl.l_start = 0;
103597a3f8ceSart fl.l_len = 0;
103697a3f8ceSart fl.l_type = F_UNLCK;
103797a3f8ceSart if (fcntl(fd, F_SETLK, &fl) < 0)
103897a3f8ceSart err(1, "F_UNLCK");
103997a3f8ceSart }
104097a3f8ceSart SUCCEED;
104197a3f8ceSart }
104297a3f8ceSart
104397a3f8ceSart /*
104497a3f8ceSart * Test 14 - soak test
104597a3f8ceSart */
104697a3f8ceSart static int
test14(int fd)104727fff5e2Santon test14(int fd)
104897a3f8ceSart {
104997a3f8ceSart #define CHILD_COUNT 20
105097a3f8ceSart /*
105197a3f8ceSart * We create a set of child processes and let each one run
105297a3f8ceSart * through a random sequence of locks and unlocks.
105397a3f8ceSart */
105427fff5e2Santon int i, j, id;
105597a3f8ceSart int pids[CHILD_COUNT], pid;
105697a3f8ceSart char buf[128];
105797a3f8ceSart char tbuf[128];
105897a3f8ceSart int map[128];
105997a3f8ceSart char outbuf[512];
106097a3f8ceSart struct flock fl;
106197a3f8ceSart struct itimerval itv;
106297a3f8ceSart int status;
106327fff5e2Santon int id_base = 0;
106497a3f8ceSart
106597a3f8ceSart if (verbose) printf("14 - soak test: ");
106697a3f8ceSart fflush(stdout);
106797a3f8ceSart
106897a3f8ceSart for (i = 0; i < 128; i++)
106997a3f8ceSart map[i] = F_UNLCK;
107097a3f8ceSart
107197a3f8ceSart for (i = 0; i < CHILD_COUNT; i++) {
107297a3f8ceSart
107397a3f8ceSart pid = fork();
107497a3f8ceSart if (pid < 0)
107597a3f8ceSart err(1, "fork");
107697a3f8ceSart if (pid) {
107797a3f8ceSart /*
107897a3f8ceSart * Parent - record the pid and continue.
107997a3f8ceSart */
108097a3f8ceSart pids[i] = pid;
108197a3f8ceSart continue;
108297a3f8ceSart }
108397a3f8ceSart
108497a3f8ceSart /*
108597a3f8ceSart * Child - do some work and exit.
108697a3f8ceSart */
108797a3f8ceSart id = id_base + i;
108897a3f8ceSart for (j = 0; j < 50; j++) {
108997a3f8ceSart int start, end, len;
109097a3f8ceSart int set, wrlock;
109197a3f8ceSart
109297a3f8ceSart do {
1093dc4e3d0aSjsing start = arc4random_uniform(128);
1094dc4e3d0aSjsing end = arc4random_uniform(128);
109597a3f8ceSart } while (end <= start);
109697a3f8ceSart
1097dc4e3d0aSjsing set = arc4random_uniform(2);
1098dc4e3d0aSjsing wrlock = arc4random_uniform(2);
109997a3f8ceSart
110097a3f8ceSart len = end - start;
110197a3f8ceSart fl.l_start = start;
110297a3f8ceSart fl.l_len = len;
110397a3f8ceSart fl.l_whence = SEEK_SET;
110497a3f8ceSart if (set)
110597a3f8ceSart fl.l_type = wrlock ? F_WRLCK : F_RDLCK;
110697a3f8ceSart else
110797a3f8ceSart fl.l_type = F_UNLCK;
110897a3f8ceSart
110997a3f8ceSart itv.it_interval.tv_sec = 0;
111097a3f8ceSart itv.it_interval.tv_usec = 0;
111197a3f8ceSart itv.it_value.tv_sec = 0;
111297a3f8ceSart itv.it_value.tv_usec = 3000;
111397a3f8ceSart setitimer(ITIMER_REAL, &itv, NULL);
111497a3f8ceSart
111597a3f8ceSart if (fcntl(fd, F_SETLKW, &fl) < 0) {
111697a3f8ceSart if (errno == EDEADLK || errno == EINTR) {
111797a3f8ceSart if (verbose) {
111897a3f8ceSart snprintf(outbuf, sizeof(outbuf),
111997a3f8ceSart "%d[%d]: %s [%d .. %d] %s\n",
112097a3f8ceSart id, j,
112197a3f8ceSart set ? (wrlock ? "write lock"
112297a3f8ceSart : "read lock")
112397a3f8ceSart : "unlock", start, end,
112497a3f8ceSart errno == EDEADLK
112597a3f8ceSart ? "deadlock"
112697a3f8ceSart : "interrupted");
112797a3f8ceSart write(1, outbuf,
112897a3f8ceSart strlen(outbuf));
112997a3f8ceSart }
113097a3f8ceSart continue;
113197a3f8ceSart } else {
113297a3f8ceSart perror("fcntl");
113397a3f8ceSart }
113497a3f8ceSart }
113597a3f8ceSart
113697a3f8ceSart itv.it_interval.tv_sec = 0;
113797a3f8ceSart itv.it_interval.tv_usec = 0;
113897a3f8ceSart itv.it_value.tv_sec = 0;
113997a3f8ceSart itv.it_value.tv_usec = 0;
114097a3f8ceSart setitimer(ITIMER_REAL, &itv, NULL);
114197a3f8ceSart
114297a3f8ceSart if (verbose) {
114397a3f8ceSart snprintf(outbuf, sizeof(outbuf),
114497a3f8ceSart "%d[%d]: %s [%d .. %d] succeeded\n",
114597a3f8ceSart id, j,
114697a3f8ceSart set ? (wrlock ? "write lock" : "read lock")
114797a3f8ceSart : "unlock", start, end);
114897a3f8ceSart write(1, outbuf, strlen(outbuf));
114997a3f8ceSart }
115097a3f8ceSart
115197a3f8ceSart if (set) {
115297a3f8ceSart if (wrlock) {
115397a3f8ceSart /*
115497a3f8ceSart * We got a write lock - write
115597a3f8ceSart * our ID to each byte that we
115697a3f8ceSart * managed to claim.
115797a3f8ceSart */
115897a3f8ceSart for (i = start; i < end; i++)
115997a3f8ceSart map[i] = F_WRLCK;
116097a3f8ceSart memset(&buf[start], id, len);
116197a3f8ceSart if (pwrite(fd, &buf[start], len,
116297a3f8ceSart start) != len) {
116397a3f8ceSart printf("%d: short write\n", id);
116497a3f8ceSart exit(1);
116597a3f8ceSart }
116697a3f8ceSart } else {
116797a3f8ceSart /*
116897a3f8ceSart * We got a read lock - read
116997a3f8ceSart * the bytes which we claimed
117097a3f8ceSart * so that we can check that
117197a3f8ceSart * they don't change
117297a3f8ceSart * unexpectedly.
117397a3f8ceSart */
117497a3f8ceSart for (i = start; i < end; i++)
117597a3f8ceSart map[i] = F_RDLCK;
117697a3f8ceSart if (pread(fd, &buf[start], len,
117797a3f8ceSart start) != len) {
117897a3f8ceSart printf("%d: short read\n", id);
117997a3f8ceSart exit(1);
118097a3f8ceSart }
118197a3f8ceSart }
118297a3f8ceSart } else {
118397a3f8ceSart for (i = start; i < end; i++)
118497a3f8ceSart map[i] = F_UNLCK;
118597a3f8ceSart }
118697a3f8ceSart
118797a3f8ceSart usleep(1000);
118897a3f8ceSart
118997a3f8ceSart /*
119097a3f8ceSart * Read back the whole region so that we can
119197a3f8ceSart * check that all the bytes we have some kind
119297a3f8ceSart * of claim to have the correct value.
119397a3f8ceSart */
119497a3f8ceSart if (pread(fd, tbuf, sizeof(tbuf), 0) != sizeof(tbuf)) {
119597a3f8ceSart printf("%d: short read\n", id);
119697a3f8ceSart exit(1);
119797a3f8ceSart }
119897a3f8ceSart
119997a3f8ceSart for (i = 0; i < 128; i++) {
120097a3f8ceSart if (map[i] != F_UNLCK && buf[i] != tbuf[i]) {
120197a3f8ceSart snprintf(outbuf, sizeof(outbuf),
120297a3f8ceSart "%d: byte %d expected %d, "
120397a3f8ceSart "got %d\n", id, i, buf[i], tbuf[i]);
120497a3f8ceSart write(1, outbuf, strlen(outbuf));
120597a3f8ceSart exit(1);
120697a3f8ceSart }
120797a3f8ceSart }
120897a3f8ceSart }
120997a3f8ceSart if (verbose)
121097a3f8ceSart printf("%d[%d]: done\n", id, j);
121197a3f8ceSart
121297a3f8ceSart exit(0);
121397a3f8ceSart }
121497a3f8ceSart
121597a3f8ceSart status = 0;
121697a3f8ceSart for (i = 0; i < CHILD_COUNT; i++) {
121797a3f8ceSart status += safe_waitpid(pids[i]);
121897a3f8ceSart }
121997a3f8ceSart if (status)
122097a3f8ceSart FAIL(status != 0);
122197a3f8ceSart
122297a3f8ceSart SUCCEED;
122397a3f8ceSart }
122497a3f8ceSart
122597a3f8ceSart /*
122697a3f8ceSart * Test 15 - flock(2) semantcs
122797a3f8ceSart *
122897a3f8ceSart * When a lock holder has a shared lock and attempts to upgrade that
122997a3f8ceSart * shared lock to exclusive, it must drop the shared lock before
123097a3f8ceSart * blocking on the exclusive lock.
123197a3f8ceSart *
123297a3f8ceSart * To test this, we first arrange for two shared locks on the file,
123397a3f8ceSart * and then attempt to upgrade one of them to exclusive. This should
123497a3f8ceSart * drop one of the shared locks and block. We interrupt the blocking
123597a3f8ceSart * lock request and examine the lock state of the file after dropping
123697a3f8ceSart * the other shared lock - there should be no active locks at this
123797a3f8ceSart * point.
123897a3f8ceSart */
123997a3f8ceSart static int
test15(int fd)124027fff5e2Santon test15(int fd)
124197a3f8ceSart {
124297a3f8ceSart #ifdef LOCK_EX
124397a3f8ceSart /*
124497a3f8ceSart * We create a child process to hold the lock which we will
124597a3f8ceSart * test. We use a pipe to communicate with the child.
124697a3f8ceSart *
124797a3f8ceSart * Since we only have one file descriptors and lock ownership
124897a3f8ceSart * for flock(2) goes with the file descriptor, we use fcntl to
124997a3f8ceSart * set the child's shared lock.
125097a3f8ceSart */
125197a3f8ceSart int pid;
125297a3f8ceSart int pfd[2];
125397a3f8ceSart int fd2;
125497a3f8ceSart struct flock fl;
125597a3f8ceSart char ch;
125697a3f8ceSart int res;
125797a3f8ceSart
125897a3f8ceSart if (pipe(pfd) < 0)
125997a3f8ceSart err(1, "pipe");
126097a3f8ceSart
126197a3f8ceSart pid = fork();
126297a3f8ceSart if (pid < 0)
126397a3f8ceSart err(1, "fork");
126497a3f8ceSart
126597a3f8ceSart if (pid == 0) {
126697a3f8ceSart /*
126797a3f8ceSart * We are the child. We set a shared lock and then
126897a3f8ceSart * write one byte back to the parent to tell it. The
126997a3f8ceSart * parent will kill us when its done.
127097a3f8ceSart */
127197a3f8ceSart fl.l_start = 0;
127297a3f8ceSart fl.l_len = 0;
127397a3f8ceSart fl.l_type = F_RDLCK;
127497a3f8ceSart fl.l_whence = SEEK_SET;
127597a3f8ceSart if (fcntl(fd, F_SETLK, &fl) < 0)
127697a3f8ceSart err(1, "fcntl(F_SETLK) (child)");
127797a3f8ceSart if (write(pfd[1], "a", 1) < 0)
127897a3f8ceSart err(1, "writing to pipe (child)");
127997a3f8ceSart pause();
128097a3f8ceSart exit(0);
128197a3f8ceSart }
128297a3f8ceSart
128397a3f8ceSart /*
128497a3f8ceSart * Wait until the child has set its lock and then perform the
128597a3f8ceSart * test.
128697a3f8ceSart */
128797a3f8ceSart if (read(pfd[0], &ch, 1) != 1)
128897a3f8ceSart err(1, "reading from pipe (child)");
128997a3f8ceSart
129097a3f8ceSart fd2 = dup(fd);
1291c8db1e5aSanton FAIL(fd2 == -1);
129297a3f8ceSart if (flock(fd, LOCK_SH) < 0)
129397a3f8ceSart err(1, "flock shared");
129497a3f8ceSart
129597a3f8ceSart /*
129697a3f8ceSart * flock should wait until the alarm and then return -1 with
129797a3f8ceSart * errno set to EINTR.
129897a3f8ceSart */
129997a3f8ceSart if (verbose) printf("15 - flock(2) semantics: ");
130097a3f8ceSart
130197a3f8ceSart alarm(1);
130297a3f8ceSart flock(fd, LOCK_EX);
130397a3f8ceSart
130497a3f8ceSart /*
130597a3f8ceSart * Kill the child to force it to drop its locks.
130697a3f8ceSart */
130797a3f8ceSart safe_kill(pid, SIGTERM);
130897a3f8ceSart safe_waitpid(pid);
130997a3f8ceSart
131097a3f8ceSart fl.l_start = 0;
131197a3f8ceSart fl.l_len = 0;
131297a3f8ceSart fl.l_type = F_WRLCK;
131397a3f8ceSart fl.l_whence = SEEK_SET;
131497a3f8ceSart res = fcntl(fd, F_GETLK, &fl);
131597a3f8ceSart
131697a3f8ceSart close(pfd[0]);
131797a3f8ceSart close(pfd[1]);
131897a3f8ceSart FAIL(res != 0);
131997a3f8ceSart FAIL(fl.l_type != F_UNLCK);
132097a3f8ceSart
132197a3f8ceSart SUCCEED;
132297a3f8ceSart #else
132397a3f8ceSart return 0;
132497a3f8ceSart #endif
132597a3f8ceSart }
132697a3f8ceSart
1327bb03833fSanton /*
1328bb03833fSanton * Test 16 - double free regression
13290d5ae59dSanton *
13300d5ae59dSanton * Not applicable anymore due to stricter bounds validation.
1331bb03833fSanton */
1332bb03833fSanton static int
test16(int fd)133327fff5e2Santon test16(int fd)
1334bb03833fSanton {
13350d5ae59dSanton #if 0
1336bb03833fSanton struct flock fl;
1337bb03833fSanton int res;
1338bb03833fSanton
1339bb03833fSanton fl.l_pid = 0;
1340bb03833fSanton fl.l_type = 1;
1341bb03833fSanton fl.l_whence = 0;
1342bb03833fSanton
1343bb03833fSanton fl.l_start = 0;
1344bb03833fSanton fl.l_len = 0x8000000000000000;
1345bb03833fSanton res = fcntl(fd, F_SETLK, &fl);
1346bb03833fSanton FAIL(res != 0);
1347bb03833fSanton
1348bb03833fSanton fl.l_start = 0x10000;
1349bb03833fSanton fl.l_len = 0;
1350bb03833fSanton res = fcntl(fd, F_SETLK, &fl);
1351bb03833fSanton FAIL(res != 0);
1352bb03833fSanton
1353bb03833fSanton fl.l_start = 0;
1354bb03833fSanton fl.l_len = 0x8000000000000000;
1355bb03833fSanton res = fcntl(fd, F_SETLK, &fl);
1356bb03833fSanton FAIL(res != 0);
1357bb03833fSanton
1358bb03833fSanton fl.l_start = 0x10000;
1359bb03833fSanton fl.l_len = 0;
1360bb03833fSanton res = fcntl(fd, F_SETLK, &fl);
1361bb03833fSanton FAIL(res != 0);
13620d5ae59dSanton #endif
1363bb03833fSanton
1364bb03833fSanton SUCCEED;
1365bb03833fSanton }
1366bb03833fSanton
13679f8d2875Santon /*
13689f8d2875Santon * Test 17 - lf_findoverlap() case 0
13699f8d2875Santon *
13709f8d2875Santon * No overlap.
13719f8d2875Santon */
13729f8d2875Santon static int
test17(int fd)137327fff5e2Santon test17(int fd)
13749f8d2875Santon {
13759f8d2875Santon struct flock fl;
13769f8d2875Santon int nfd, res;
13779f8d2875Santon
13789f8d2875Santon /* First lock. */
13799f8d2875Santon {
13809f8d2875Santon nfd = dup(fd);
13819f8d2875Santon FAIL(nfd == -1);
13829f8d2875Santon
13839f8d2875Santon fl.l_start = 0;
13849f8d2875Santon fl.l_len = 100;
13859f8d2875Santon fl.l_pid = 0;
13869f8d2875Santon fl.l_type = F_RDLCK;
13879f8d2875Santon fl.l_whence = 0;
13889f8d2875Santon res = fcntl(fd, F_SETLK, &fl);
13899f8d2875Santon FAIL(res != 0);
13909f8d2875Santon
13919f8d2875Santon close(nfd);
13929f8d2875Santon }
13939f8d2875Santon
13949f8d2875Santon /* Insert at end. */
13959f8d2875Santon {
13969f8d2875Santon nfd = dup(fd);
13979f8d2875Santon FAIL(nfd == -1);
13989f8d2875Santon
13999f8d2875Santon fl.l_start = 100;
14009f8d2875Santon fl.l_len = 100;
14019f8d2875Santon fl.l_pid = 0;
14029f8d2875Santon fl.l_type = F_RDLCK;
14039f8d2875Santon fl.l_whence = 0;
14049f8d2875Santon res = fcntl(fd, F_SETLK, &fl);
14059f8d2875Santon FAIL(res != 0);
14069f8d2875Santon
14079f8d2875Santon fl.l_start = 200;
14089f8d2875Santon fl.l_len = 100;
14099f8d2875Santon fl.l_pid = 0;
14109f8d2875Santon fl.l_type = F_RDLCK;
14119f8d2875Santon fl.l_whence = 0;
14129f8d2875Santon res = fcntl(fd, F_SETLK, &fl);
14139f8d2875Santon FAIL(res != 0);
14149f8d2875Santon
14159f8d2875Santon close(nfd);
14169f8d2875Santon }
14179f8d2875Santon
14189f8d2875Santon /* Insert before overlap. */
14199f8d2875Santon {
14209f8d2875Santon nfd = dup(fd);
14219f8d2875Santon FAIL(nfd == -1);
14229f8d2875Santon
14239f8d2875Santon fl.l_start = 300;
14249f8d2875Santon fl.l_len = 100;
14259f8d2875Santon fl.l_pid = 0;
14269f8d2875Santon fl.l_type = F_RDLCK;
14279f8d2875Santon fl.l_whence = 0;
14289f8d2875Santon res = fcntl(fd, F_SETLK, &fl);
14299f8d2875Santon FAIL(res != 0);
14309f8d2875Santon
14319f8d2875Santon fl.l_start = 500;
14329f8d2875Santon fl.l_len = 100;
14339f8d2875Santon fl.l_pid = 0;
14349f8d2875Santon fl.l_type = F_RDLCK;
14359f8d2875Santon fl.l_whence = 0;
14369f8d2875Santon res = fcntl(fd, F_SETLK, &fl);
14379f8d2875Santon FAIL(res != 0);
14389f8d2875Santon
14399f8d2875Santon fl.l_start = 400;
14409f8d2875Santon fl.l_len = 100;
14419f8d2875Santon fl.l_pid = 0;
14429f8d2875Santon fl.l_type = F_RDLCK;
14439f8d2875Santon fl.l_whence = 0;
14449f8d2875Santon res = fcntl(fd, F_SETLK, &fl);
14459f8d2875Santon FAIL(res != 0);
14469f8d2875Santon
14479f8d2875Santon close(nfd);
14489f8d2875Santon }
14499f8d2875Santon
14509f8d2875Santon SUCCEED;
14519f8d2875Santon }
14529f8d2875Santon
14539f8d2875Santon /*
14549f8d2875Santon * Test 18 - lf_findoverlap() case 1
14559f8d2875Santon *
14569f8d2875Santon * Overlap and lock are equal.
14579f8d2875Santon */
14589f8d2875Santon static int
test18(int fd)145927fff5e2Santon test18(int fd)
14609f8d2875Santon {
14619f8d2875Santon struct flock fl;
14629f8d2875Santon int res;
14639f8d2875Santon
14649f8d2875Santon fl.l_start = 0;
14659f8d2875Santon fl.l_len = 100;
14669f8d2875Santon fl.l_pid = 0;
14679f8d2875Santon fl.l_type = F_RDLCK;
14689f8d2875Santon fl.l_whence = 0;
14699f8d2875Santon res = fcntl(fd, F_SETLK, &fl);
14709f8d2875Santon FAIL(res != 0);
14719f8d2875Santon res = fcntl(fd, F_SETLK, &fl);
14729f8d2875Santon FAIL(res != 0);
14739f8d2875Santon
14749f8d2875Santon SUCCEED;
14759f8d2875Santon }
14769f8d2875Santon
14779f8d2875Santon /*
14789f8d2875Santon * Test 19 - lf_findoverlap() case 2
14799f8d2875Santon *
14809f8d2875Santon * Overlap contains lock.
14819f8d2875Santon */
14829f8d2875Santon static int
test19(int fd)148327fff5e2Santon test19(int fd)
14849f8d2875Santon {
14859f8d2875Santon struct flock fl;
14869f8d2875Santon int nfd, res;
14879f8d2875Santon
14889f8d2875Santon /* Same type. */
14899f8d2875Santon {
14909f8d2875Santon nfd = dup(fd);
14919f8d2875Santon FAIL(nfd == -1);
14929f8d2875Santon
14939f8d2875Santon fl.l_start = 0;
14949f8d2875Santon fl.l_len = 100;
14959f8d2875Santon fl.l_pid = 0;
14969f8d2875Santon fl.l_type = F_RDLCK;
14979f8d2875Santon fl.l_whence = 0;
14989f8d2875Santon res = fcntl(fd, F_SETLK, &fl);
14999f8d2875Santon FAIL(res != 0);
15009f8d2875Santon
15019f8d2875Santon fl.l_start = 0;
15029f8d2875Santon fl.l_len = 50;
15039f8d2875Santon fl.l_pid = 0;
15049f8d2875Santon fl.l_type = F_RDLCK;
15059f8d2875Santon fl.l_whence = 0;
15069f8d2875Santon res = fcntl(fd, F_SETLK, &fl);
15079f8d2875Santon FAIL(res != 0);
15089f8d2875Santon
15099f8d2875Santon close(nfd);
15109f8d2875Santon }
15119f8d2875Santon
15129f8d2875Santon /* Different type, same start offset. */
15139f8d2875Santon {
15149f8d2875Santon nfd = dup(fd);
15159f8d2875Santon FAIL(nfd == -1);
15169f8d2875Santon
15179f8d2875Santon fl.l_start = 100;
15189f8d2875Santon fl.l_len = 100;
15199f8d2875Santon fl.l_pid = 0;
15209f8d2875Santon fl.l_type = F_RDLCK;
15219f8d2875Santon fl.l_whence = 0;
15229f8d2875Santon res = fcntl(fd, F_SETLK, &fl);
15239f8d2875Santon FAIL(res != 0);
15249f8d2875Santon
15259f8d2875Santon fl.l_start = 100;
15269f8d2875Santon fl.l_len = 50;
15279f8d2875Santon fl.l_pid = 0;
15289f8d2875Santon fl.l_type = F_WRLCK;
15299f8d2875Santon fl.l_whence = 0;
15309f8d2875Santon res = fcntl(fd, F_SETLK, &fl);
15319f8d2875Santon FAIL(res != 0);
15329f8d2875Santon
15339f8d2875Santon close(nfd);
15349f8d2875Santon }
15359f8d2875Santon
15369f8d2875Santon /* Split fallback. */
15379f8d2875Santon {
15389f8d2875Santon nfd = dup(fd);
15399f8d2875Santon FAIL(nfd == -1);
15409f8d2875Santon
15419f8d2875Santon fl.l_start = 100;
15429f8d2875Santon fl.l_len = 100;
15439f8d2875Santon fl.l_pid = 0;
15449f8d2875Santon fl.l_type = F_RDLCK;
15459f8d2875Santon fl.l_whence = 0;
15469f8d2875Santon res = fcntl(fd, F_SETLK, &fl);
15479f8d2875Santon FAIL(res != 0);
15489f8d2875Santon
15499f8d2875Santon fl.l_start = 110;
15509f8d2875Santon fl.l_len = 50;
15519f8d2875Santon fl.l_pid = 0;
15529f8d2875Santon fl.l_type = F_WRLCK;
15539f8d2875Santon fl.l_whence = 0;
15549f8d2875Santon res = fcntl(fd, F_SETLK, &fl);
15559f8d2875Santon FAIL(res != 0);
15569f8d2875Santon
15579f8d2875Santon close(nfd);
15589f8d2875Santon }
15599f8d2875Santon
15609f8d2875Santon SUCCEED;
15619f8d2875Santon }
15629f8d2875Santon
15639f8d2875Santon /*
15649f8d2875Santon * Test 20 - lf_findoverlap() case 3
15659f8d2875Santon *
15669f8d2875Santon * Lock contains overlap.
15679f8d2875Santon */
15689f8d2875Santon static int
test20(int fd)156927fff5e2Santon test20(int fd)
15709f8d2875Santon {
15719f8d2875Santon struct flock fl;
15729f8d2875Santon int res;
15739f8d2875Santon
15749f8d2875Santon fl.l_start = 0;
15759f8d2875Santon fl.l_len = 100;
15769f8d2875Santon fl.l_pid = 0;
15779f8d2875Santon fl.l_type = F_WRLCK;
15789f8d2875Santon fl.l_whence = 0;
15799f8d2875Santon res = fcntl(fd, F_SETLK, &fl);
15809f8d2875Santon FAIL(res != 0);
15819f8d2875Santon
15829f8d2875Santon fl.l_start = 0;
15839f8d2875Santon fl.l_len = 200;
15849f8d2875Santon fl.l_pid = 0;
15859f8d2875Santon fl.l_type = F_WRLCK;
15869f8d2875Santon fl.l_whence = 0;
15879f8d2875Santon res = fcntl(fd, F_SETLK, &fl);
15889f8d2875Santon FAIL(res != 0);
15899f8d2875Santon
15909f8d2875Santon SUCCEED;
15919f8d2875Santon }
15929f8d2875Santon
15939f8d2875Santon /*
15949f8d2875Santon * Test 21 - lf_findoverlap() case 4
15959f8d2875Santon *
15969f8d2875Santon * Overlap starts before lock.
15979f8d2875Santon */
15989f8d2875Santon static int
test21(int fd)159927fff5e2Santon test21(int fd)
16009f8d2875Santon {
16019f8d2875Santon struct flock fl;
16029f8d2875Santon int res;
16039f8d2875Santon
16049f8d2875Santon fl.l_start = 0;
16059f8d2875Santon fl.l_len = 100;
16069f8d2875Santon fl.l_pid = 0;
16079f8d2875Santon fl.l_type = F_WRLCK;
16089f8d2875Santon fl.l_whence = 0;
16099f8d2875Santon res = fcntl(fd, F_SETLK, &fl);
16109f8d2875Santon FAIL(res != 0);
16119f8d2875Santon
16129f8d2875Santon fl.l_start = 50;
16139f8d2875Santon fl.l_len = 100;
16149f8d2875Santon fl.l_pid = 0;
16159f8d2875Santon fl.l_type = F_WRLCK;
16169f8d2875Santon fl.l_whence = 0;
16179f8d2875Santon res = fcntl(fd, F_SETLK, &fl);
16189f8d2875Santon FAIL(res != 0);
16199f8d2875Santon
16209f8d2875Santon SUCCEED;
16219f8d2875Santon }
16229f8d2875Santon
16239f8d2875Santon /*
16249f8d2875Santon * Test 22 - lf_findoverlap() case 5
16259f8d2875Santon *
16269f8d2875Santon * Overlap ends after lock.
16279f8d2875Santon */
16289f8d2875Santon static int
test22(int fd)162927fff5e2Santon test22(int fd)
16309f8d2875Santon {
16319f8d2875Santon struct flock fl;
16329f8d2875Santon int res;
16339f8d2875Santon
16349f8d2875Santon fl.l_start = 10;
16359f8d2875Santon fl.l_len = 100;
16369f8d2875Santon fl.l_pid = 0;
16379f8d2875Santon fl.l_type = F_WRLCK;
16389f8d2875Santon fl.l_whence = 0;
16399f8d2875Santon res = fcntl(fd, F_SETLK, &fl);
16409f8d2875Santon FAIL(res != 0);
16419f8d2875Santon
16429f8d2875Santon fl.l_start = 0;
16439f8d2875Santon fl.l_len = 50;
16449f8d2875Santon fl.l_pid = 0;
16459f8d2875Santon fl.l_type = F_WRLCK;
16469f8d2875Santon fl.l_whence = 0;
16479f8d2875Santon res = fcntl(fd, F_SETLK, &fl);
16489f8d2875Santon FAIL(res != 0);
16499f8d2875Santon
16509f8d2875Santon SUCCEED;
16519f8d2875Santon }
16529f8d2875Santon
16530d5ae59dSanton /*
16540d5ae59dSanton * Test 23 - positive length overflow
16550d5ae59dSanton */
16560d5ae59dSanton static int
test23(int fd)16570d5ae59dSanton test23(int fd)
16580d5ae59dSanton {
16590d5ae59dSanton struct flock fl;
16600d5ae59dSanton int res;
16610d5ae59dSanton
16620d5ae59dSanton fl.l_pid = 0;
16630d5ae59dSanton fl.l_type = F_WRLCK;
16640d5ae59dSanton fl.l_whence = SEEK_SET;
16650d5ae59dSanton fl.l_start = 2;
16660d5ae59dSanton fl.l_len = LLONG_MAX;
16670d5ae59dSanton res = fcntl(fd, F_SETLK, &fl);
16680d5ae59dSanton FAIL(res != -1);
16690d5ae59dSanton FAIL(errno != EOVERFLOW);
16700d5ae59dSanton
16710d5ae59dSanton SUCCEED;
16720d5ae59dSanton }
16730d5ae59dSanton
16740d5ae59dSanton /*
16750d5ae59dSanton * Test 24 - negative length
16760d5ae59dSanton */
16770d5ae59dSanton static int
test24(int fd)16780d5ae59dSanton test24(int fd)
16790d5ae59dSanton {
16800d5ae59dSanton struct flock fl;
16810d5ae59dSanton pid_t pid;
16820d5ae59dSanton int res, status;
16830d5ae59dSanton
16840d5ae59dSanton fl.l_pid = 0;
16850d5ae59dSanton fl.l_type = F_WRLCK;
16860d5ae59dSanton fl.l_whence = SEEK_SET;
16870d5ae59dSanton
16880d5ae59dSanton /* Start offset plus length must be positive. */
16890d5ae59dSanton fl.l_start = 0;
16900d5ae59dSanton fl.l_len = LLONG_MIN;
16910d5ae59dSanton res = fcntl(fd, F_SETLK, &fl);
16920d5ae59dSanton FAIL(res != -1);
16930d5ae59dSanton FAIL(errno != EINVAL);
16940d5ae59dSanton
16950d5ae59dSanton /* Set exclusive lock on range [2,3] */
16960d5ae59dSanton fl.l_start = 4;
16970d5ae59dSanton fl.l_len = -2;
16980d5ae59dSanton res = fcntl(fd, F_SETLK, &fl);
16990d5ae59dSanton FAIL(res != 0);
17000d5ae59dSanton
17010d5ae59dSanton /* Another process must not be able to lock the same range. */
17020d5ae59dSanton pid = fork();
17030d5ae59dSanton if (pid == -1)
17040d5ae59dSanton err(1, "fork");
17050d5ae59dSanton if (pid == 0) {
17060d5ae59dSanton fl.l_start = 2;
17070d5ae59dSanton fl.l_len = 2;
17080d5ae59dSanton res = fcntl(fd, F_GETLK, &fl);
17090d5ae59dSanton FAIL(res != 0);
17100d5ae59dSanton FAIL(fl.l_type == F_UNLCK);
17110d5ae59dSanton _exit(0);
17120d5ae59dSanton }
17130d5ae59dSanton status = safe_waitpid(pid);
17140d5ae59dSanton FAIL(status != 0);
17150d5ae59dSanton
17160d5ae59dSanton SUCCEED;
17170d5ae59dSanton }
17180d5ae59dSanton
1719afb1c1edSanton /*
1720afb1c1edSanton * Test 25 - use after free regression
1721afb1c1edSanton *
1722afb1c1edSanton * Discovered by syzkaller.
1723afb1c1edSanton */
1724afb1c1edSanton static int
test25(int fd)1725afb1c1edSanton test25(int fd)
1726afb1c1edSanton {
1727afb1c1edSanton struct flock fl;
1728afb1c1edSanton int master, res, slave;
1729afb1c1edSanton
1730afb1c1edSanton res = openpty(&master, &slave, NULL, NULL, NULL);
1731afb1c1edSanton FAIL(res == -1);
1732afb1c1edSanton close(master);
1733afb1c1edSanton
1734afb1c1edSanton fl.l_start = 0;
1735afb1c1edSanton fl.l_len = 0;
1736afb1c1edSanton fl.l_pid = 0;
1737afb1c1edSanton fl.l_type = F_RDLCK;
1738afb1c1edSanton fl.l_whence = SEEK_SET;
1739afb1c1edSanton res = fcntl(slave, F_SETLKW, &fl);
1740afb1c1edSanton FAIL(res != 0);
1741afb1c1edSanton
1742afb1c1edSanton fl.l_start = 3;
1743afb1c1edSanton fl.l_len = 0x7ffffffffffffffd;
1744afb1c1edSanton fl.l_pid = 0;
1745afb1c1edSanton fl.l_type = F_UNLCK;
1746afb1c1edSanton fl.l_whence = SEEK_END;
1747afb1c1edSanton res = fcntl(slave, F_SETLKW, &fl);
1748afb1c1edSanton FAIL(res != 0);
1749afb1c1edSanton
1750afb1c1edSanton fl.l_start = 0;
1751afb1c1edSanton fl.l_len = 0;
1752afb1c1edSanton fl.l_pid = 0;
1753afb1c1edSanton fl.l_type = F_RDLCK;
1754afb1c1edSanton fl.l_whence = SEEK_SET;
1755afb1c1edSanton res = fcntl(slave, F_SETLKW, &fl);
1756afb1c1edSanton FAIL(res != 0);
1757afb1c1edSanton
1758afb1c1edSanton close(slave);
1759afb1c1edSanton
1760afb1c1edSanton SUCCEED;
1761afb1c1edSanton }
1762afb1c1edSanton
1763*c3602110Svisa /*
1764*c3602110Svisa * Test 26 - range end point ambiguity regression
1765*c3602110Svisa *
1766*c3602110Svisa * When a new lock range [start, LLONG_MAX] overlapped with an existing range,
1767*c3602110Svisa * kernel's lock data structure could become inconsistent.
1768*c3602110Svisa */
1769*c3602110Svisa static int
test26(int fd)1770*c3602110Svisa test26(int fd)
1771*c3602110Svisa {
1772*c3602110Svisa struct flock fl;
1773*c3602110Svisa pid_t pid;
1774*c3602110Svisa int res, status;
1775*c3602110Svisa
1776*c3602110Svisa /* Lock the whole range. */
1777*c3602110Svisa fl.l_start = 0;
1778*c3602110Svisa fl.l_len = 0;
1779*c3602110Svisa fl.l_pid = 0;
1780*c3602110Svisa fl.l_type = F_RDLCK;
1781*c3602110Svisa fl.l_whence = SEEK_SET;
1782*c3602110Svisa res = fcntl(fd, F_SETLK, &fl);
1783*c3602110Svisa FAIL(res != 0);
1784*c3602110Svisa
1785*c3602110Svisa /*
1786*c3602110Svisa * Split the range at the end.
1787*c3602110Svisa * This should be handled as if l_len == 0.
1788*c3602110Svisa */
1789*c3602110Svisa fl.l_start = LLONG_MAX;
1790*c3602110Svisa fl.l_len = 1;
1791*c3602110Svisa fl.l_pid = 0;
1792*c3602110Svisa fl.l_type = F_WRLCK;
1793*c3602110Svisa fl.l_whence = SEEK_SET;
1794*c3602110Svisa res = fcntl(fd, F_SETLK, &fl);
1795*c3602110Svisa FAIL(res != 0);
1796*c3602110Svisa
1797*c3602110Svisa /* Check the resulting ranges. */
1798*c3602110Svisa pid = fork();
1799*c3602110Svisa if (pid == -1)
1800*c3602110Svisa err(1, "fork");
1801*c3602110Svisa if (pid == 0) {
1802*c3602110Svisa fl.l_start = 0;
1803*c3602110Svisa fl.l_len = 0;
1804*c3602110Svisa fl.l_type = F_WRLCK;
1805*c3602110Svisa fl.l_whence = SEEK_SET;
1806*c3602110Svisa res = fcntl(fd, F_GETLK, &fl);
1807*c3602110Svisa FAIL(res != 0);
1808*c3602110Svisa FAIL(fl.l_type != F_RDLCK);
1809*c3602110Svisa FAIL(fl.l_start != 0);
1810*c3602110Svisa FAIL(fl.l_len != LLONG_MAX);
1811*c3602110Svisa
1812*c3602110Svisa fl.l_start = LLONG_MAX;
1813*c3602110Svisa fl.l_len = 0;
1814*c3602110Svisa fl.l_type = F_WRLCK;
1815*c3602110Svisa fl.l_whence = SEEK_SET;
1816*c3602110Svisa res = fcntl(fd, F_GETLK, &fl);
1817*c3602110Svisa FAIL(res != 0);
1818*c3602110Svisa FAIL(fl.l_type != F_WRLCK);
1819*c3602110Svisa FAIL(fl.l_start != LLONG_MAX);
1820*c3602110Svisa FAIL(fl.l_len != 0);
1821*c3602110Svisa
1822*c3602110Svisa _exit(0);
1823*c3602110Svisa }
1824*c3602110Svisa status = safe_waitpid(pid);
1825*c3602110Svisa FAIL(status != 0);
1826*c3602110Svisa
1827*c3602110Svisa /* Release all locks. */
1828*c3602110Svisa fl.l_start = 0;
1829*c3602110Svisa fl.l_len = 0;
1830*c3602110Svisa fl.l_pid = 0;
1831*c3602110Svisa fl.l_type = F_UNLCK;
1832*c3602110Svisa fl.l_whence = SEEK_SET;
1833*c3602110Svisa res = fcntl(fd, F_SETLK, &fl);
1834*c3602110Svisa FAIL(res != 0);
1835*c3602110Svisa
1836*c3602110Svisa /* Check the resulting ranges. */
1837*c3602110Svisa pid = fork();
1838*c3602110Svisa if (pid == -1)
1839*c3602110Svisa err(1, "fork");
1840*c3602110Svisa if (pid == 0) {
1841*c3602110Svisa fl.l_start = 0;
1842*c3602110Svisa fl.l_len = 0;
1843*c3602110Svisa fl.l_type = F_WRLCK;
1844*c3602110Svisa fl.l_whence = SEEK_SET;
1845*c3602110Svisa res = fcntl(fd, F_GETLK, &fl);
1846*c3602110Svisa FAIL(res != 0);
1847*c3602110Svisa FAIL(fl.l_type != F_UNLCK);
1848*c3602110Svisa FAIL(fl.l_start != 0);
1849*c3602110Svisa FAIL(fl.l_len != 0);
1850*c3602110Svisa
1851*c3602110Svisa _exit(0);
1852*c3602110Svisa }
1853*c3602110Svisa status = safe_waitpid(pid);
1854*c3602110Svisa FAIL(status != 0);
1855*c3602110Svisa
1856*c3602110Svisa SUCCEED;
1857*c3602110Svisa }
1858*c3602110Svisa
1859cdea53deSanton static struct test tests[] = {
186027fff5e2Santon { test1, 0 },
186127fff5e2Santon { test2, 0 },
186227fff5e2Santon { test3, 1 },
186327fff5e2Santon { test4, 0 },
186427fff5e2Santon { test5, 1 },
186527fff5e2Santon { test6, 1 },
186627fff5e2Santon { test7, 0 },
186727fff5e2Santon { test8, 0 },
186827fff5e2Santon { test9, 0 },
186927fff5e2Santon { test10, 0 },
187027fff5e2Santon { test11, 1 },
187127fff5e2Santon { test12, 0 },
187227fff5e2Santon { test13, 1 },
187327fff5e2Santon { test14, 0 },
187427fff5e2Santon { test15, 1 },
187527fff5e2Santon { test16, 0 },
187627fff5e2Santon { test17, 0 },
187727fff5e2Santon { test18, 0 },
187827fff5e2Santon { test19, 0 },
187927fff5e2Santon { test20, 0 },
188027fff5e2Santon { test21, 0 },
188127fff5e2Santon { test22, 0 },
18820d5ae59dSanton { test23, 0 },
18830d5ae59dSanton { test24, 0 },
1884afb1c1edSanton { test25, 0 },
1885*c3602110Svisa { test26, 0 },
188697a3f8ceSart };
1887cdea53deSanton
1888cdea53deSanton static int test_count = sizeof(tests) / sizeof(tests[0]);
188997a3f8ceSart
189097a3f8ceSart int
main(int argc,char * argv[])189127fff5e2Santon main(int argc, char *argv[])
189297a3f8ceSart {
189397a3f8ceSart struct sigaction sa;
189427fff5e2Santon const char *errstr;
189527fff5e2Santon int c, fd, i;
189627fff5e2Santon int error = 0;
189727fff5e2Santon int testnum = 0;
189897a3f8ceSart
189927fff5e2Santon while ((c = getopt(argc, argv, "v")) != -1)
190027fff5e2Santon switch (c) {
190127fff5e2Santon case 'v':
190297a3f8ceSart verbose = 1;
190327fff5e2Santon break;
190427fff5e2Santon default:
190527fff5e2Santon usage();
190697a3f8ceSart }
190727fff5e2Santon argc -= optind;
190827fff5e2Santon argv += optind;
190927fff5e2Santon if (argc > 1)
191027fff5e2Santon usage();
191127fff5e2Santon if (argc == 1) {
191227fff5e2Santon testnum = strtonum(argv[0], 1, test_count, &errstr);
191327fff5e2Santon if (testnum == 0)
191427fff5e2Santon errx(1, "test number %s", errstr);
191527fff5e2Santon }
191627fff5e2Santon
191727fff5e2Santon fd = make_file(1024);
191897a3f8ceSart
191997a3f8ceSart sa.sa_handler = ignore_alarm;
192097a3f8ceSart sigemptyset(&sa.sa_mask);
192197a3f8ceSart sa.sa_flags = 0;
192297a3f8ceSart sigaction(SIGALRM, &sa, 0);
192397a3f8ceSart
192497a3f8ceSart for (i = 0; i < test_count; i++) {
192527fff5e2Santon if (testnum == 0 || testnum == i + 1)
192627fff5e2Santon error |= tests[i].testfn(fd);
192797a3f8ceSart }
192897a3f8ceSart
192927fff5e2Santon return (error ? 1 : 0);
193097a3f8ceSart }
1931