186d7f5d3SJohn Marino /* $NetBSD: lockf.c,v 1.4 2000/07/30 09:16:06 jdolecek Exp $ */
286d7f5d3SJohn Marino /* $DragonFly: src/test/lockf/lockf.c,v 1.1 2004/05/11 08:03:57 joerg Exp $ */
386d7f5d3SJohn Marino
486d7f5d3SJohn Marino /*-
586d7f5d3SJohn Marino * Copyright (c) 2000 The NetBSD Foundation, Inc.
686d7f5d3SJohn Marino * All rights reserved.
786d7f5d3SJohn Marino *
886d7f5d3SJohn Marino * Redistribution and use in source and binary forms, with or without
986d7f5d3SJohn Marino * modification, are permitted provided that the following conditions
1086d7f5d3SJohn Marino * are met:
1186d7f5d3SJohn Marino * 1. Redistributions of source code must retain the above copyright
1286d7f5d3SJohn Marino * notice, this list of conditions and the following disclaimer.
1386d7f5d3SJohn Marino * 2. Redistributions in binary form must reproduce the above copyright
1486d7f5d3SJohn Marino * notice, this list of conditions and the following disclaimer in the
1586d7f5d3SJohn Marino * documentation and/or other materials provided with the distribution.
1686d7f5d3SJohn Marino * 3. All advertising materials mentioning features or use of this software
1786d7f5d3SJohn Marino * must display the following acknowledgement:
1886d7f5d3SJohn Marino * This product includes software developed by the NetBSD
1986d7f5d3SJohn Marino * Foundation, Inc. and its contributors.
2086d7f5d3SJohn Marino * 4. Neither the name of The NetBSD Foundation nor the names of its
2186d7f5d3SJohn Marino * contributors may be used to endorse or promote products derived
2286d7f5d3SJohn Marino * from this software without specific prior written permission.
2386d7f5d3SJohn Marino *
2486d7f5d3SJohn Marino * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2586d7f5d3SJohn Marino * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2686d7f5d3SJohn Marino * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2786d7f5d3SJohn Marino * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2886d7f5d3SJohn Marino * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2986d7f5d3SJohn Marino * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
3086d7f5d3SJohn Marino * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
3186d7f5d3SJohn Marino * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
3286d7f5d3SJohn Marino * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
3386d7f5d3SJohn Marino * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3486d7f5d3SJohn Marino * POSSIBILITY OF SUCH DAMAGE.
3586d7f5d3SJohn Marino */
3686d7f5d3SJohn Marino
3786d7f5d3SJohn Marino /*
3886d7f5d3SJohn Marino * lockf regression test:
3986d7f5d3SJohn Marino *
4086d7f5d3SJohn Marino * Tests:
4186d7f5d3SJohn Marino * 1) fork N child processes, do a bunch of random byte range lock/unlock.
4286d7f5d3SJohn Marino */
4386d7f5d3SJohn Marino
4486d7f5d3SJohn Marino #include <sys/types.h>
4586d7f5d3SJohn Marino #include <sys/wait.h>
4686d7f5d3SJohn Marino #include <sys/ptrace.h>
4786d7f5d3SJohn Marino
4886d7f5d3SJohn Marino #include <unistd.h>
4986d7f5d3SJohn Marino #include <fcntl.h>
5086d7f5d3SJohn Marino #include <stdio.h>
5186d7f5d3SJohn Marino #include <stdlib.h>
5286d7f5d3SJohn Marino #include <err.h>
5386d7f5d3SJohn Marino #include <signal.h>
5486d7f5d3SJohn Marino #include <errno.h>
5586d7f5d3SJohn Marino
5686d7f5d3SJohn Marino int nlocks = 10000; /* number of locks per thread */
5786d7f5d3SJohn Marino int nprocs = 100; /* number of processes to spawn */
5886d7f5d3SJohn Marino int sleeptime = 50000; /* sleep time between locks, usec */
5986d7f5d3SJohn Marino off_t size = 65536; /* size of file to lock */
6086d7f5d3SJohn Marino const char *lockfile = "/tmp/lockf_test";
6186d7f5d3SJohn Marino
6286d7f5d3SJohn Marino static uint32_t
random_uint32(void)6386d7f5d3SJohn Marino random_uint32(void)
6486d7f5d3SJohn Marino {
6586d7f5d3SJohn Marino return lrand48();
6686d7f5d3SJohn Marino }
6786d7f5d3SJohn Marino
6886d7f5d3SJohn Marino
6986d7f5d3SJohn Marino static void
trylocks(int id)7086d7f5d3SJohn Marino trylocks(int id)
7186d7f5d3SJohn Marino {
7286d7f5d3SJohn Marino int i, ret, fd;
7386d7f5d3SJohn Marino int uids[3];
7486d7f5d3SJohn Marino const char *which;
7586d7f5d3SJohn Marino
7686d7f5d3SJohn Marino uids[0] = -1;
7786d7f5d3SJohn Marino uids[1] = getuid();
7886d7f5d3SJohn Marino uids[2] = geteuid();
7986d7f5d3SJohn Marino srand48(getpid());
8086d7f5d3SJohn Marino
8186d7f5d3SJohn Marino fd = open (lockfile, O_RDWR, 0);
8286d7f5d3SJohn Marino
8386d7f5d3SJohn Marino if (fd < 0)
8486d7f5d3SJohn Marino err(1, lockfile);
8586d7f5d3SJohn Marino
8686d7f5d3SJohn Marino printf("%d: start\n", id);
8786d7f5d3SJohn Marino
8886d7f5d3SJohn Marino for (i=0; i<nlocks; i++) {
8986d7f5d3SJohn Marino struct flock fl;
9086d7f5d3SJohn Marino ret = random_uint32() % 3;
9186d7f5d3SJohn Marino if (uids[ret] != -1) {
9286d7f5d3SJohn Marino printf("switching to uid %d\n", uids[ret]);
9386d7f5d3SJohn Marino setuid(uids[ret]);
9486d7f5d3SJohn Marino }
9586d7f5d3SJohn Marino
9686d7f5d3SJohn Marino fl.l_start = random_uint32() % size;
9786d7f5d3SJohn Marino fl.l_len = random_uint32() % size;
9886d7f5d3SJohn Marino switch (random_uint32() % 3) {
9986d7f5d3SJohn Marino case 0:
10086d7f5d3SJohn Marino which = "read";
10186d7f5d3SJohn Marino fl.l_type = F_RDLCK;
10286d7f5d3SJohn Marino break;
10386d7f5d3SJohn Marino case 1:
10486d7f5d3SJohn Marino which = "write";
10586d7f5d3SJohn Marino fl.l_type = F_WRLCK;
10686d7f5d3SJohn Marino break;
10786d7f5d3SJohn Marino case 2:
10886d7f5d3SJohn Marino which = "un";
10986d7f5d3SJohn Marino fl.l_type = F_UNLCK;
11086d7f5d3SJohn Marino break;
11186d7f5d3SJohn Marino }
11286d7f5d3SJohn Marino fl.l_whence = SEEK_SET;
11386d7f5d3SJohn Marino
11486d7f5d3SJohn Marino printf("%d: try %slock %d to %d\n", id, which, (int)fl.l_start,
11586d7f5d3SJohn Marino (int)(fl.l_start + fl.l_len));
11686d7f5d3SJohn Marino
11786d7f5d3SJohn Marino ret = fcntl(fd, F_SETLKW, &fl);
11886d7f5d3SJohn Marino
11986d7f5d3SJohn Marino if (ret < 0)
12086d7f5d3SJohn Marino perror("fcntl");
12186d7f5d3SJohn Marino printf("%d: got %slock %d to %d\n", id, which, (int)fl.l_start,
12286d7f5d3SJohn Marino ((int)(fl.l_start + fl.l_len)));
12386d7f5d3SJohn Marino
12486d7f5d3SJohn Marino if (usleep(sleeptime) < 0)
12586d7f5d3SJohn Marino err(1, "usleep");
12686d7f5d3SJohn Marino }
12786d7f5d3SJohn Marino printf("%d: done\n", id);
12886d7f5d3SJohn Marino close (fd);
12986d7f5d3SJohn Marino }
13086d7f5d3SJohn Marino
13186d7f5d3SJohn Marino /* ARGSUSED */
13286d7f5d3SJohn Marino int
main(int argc,char ** argv)13386d7f5d3SJohn Marino main(int argc, char **argv)
13486d7f5d3SJohn Marino {
13586d7f5d3SJohn Marino int i, j;
13686d7f5d3SJohn Marino pid_t *pid;
13786d7f5d3SJohn Marino int status;
13886d7f5d3SJohn Marino int fd;
13986d7f5d3SJohn Marino
14086d7f5d3SJohn Marino unlink(lockfile);
14186d7f5d3SJohn Marino
14286d7f5d3SJohn Marino fd = open (lockfile, O_RDWR|O_CREAT|O_EXCL|O_TRUNC, 0666);
14386d7f5d3SJohn Marino if (fd < 0)
14486d7f5d3SJohn Marino err(1, "%s", lockfile);
14586d7f5d3SJohn Marino
14686d7f5d3SJohn Marino if (ftruncate(fd, size) < 0)
14786d7f5d3SJohn Marino err(1, "ftruncate of %s failed", lockfile);
14886d7f5d3SJohn Marino
14986d7f5d3SJohn Marino fsync(fd);
15086d7f5d3SJohn Marino close(fd);
15186d7f5d3SJohn Marino
15286d7f5d3SJohn Marino pid = malloc(nprocs * sizeof(pid_t));
15386d7f5d3SJohn Marino
15486d7f5d3SJohn Marino for (i=0; i<nprocs; i++) {
15586d7f5d3SJohn Marino pid[i] = fork();
15686d7f5d3SJohn Marino switch (pid[i]) {
15786d7f5d3SJohn Marino case 0:
15886d7f5d3SJohn Marino trylocks(i);
15986d7f5d3SJohn Marino _exit(0);
16086d7f5d3SJohn Marino break;
16186d7f5d3SJohn Marino case -1:
16286d7f5d3SJohn Marino err(1, "fork failed");
16386d7f5d3SJohn Marino break;
16486d7f5d3SJohn Marino default:
16586d7f5d3SJohn Marino break;
16686d7f5d3SJohn Marino }
16786d7f5d3SJohn Marino }
16886d7f5d3SJohn Marino for (j=0; j<100; j++) {
16986d7f5d3SJohn Marino printf("parent: run %i\n", j+1);
17086d7f5d3SJohn Marino for (i=0; i<nprocs; i++) {
17186d7f5d3SJohn Marino printf("stop %d\n", i);
17286d7f5d3SJohn Marino if (ptrace(PT_ATTACH, pid[i], 0, 0) < 0)
17386d7f5d3SJohn Marino err(1, "ptrace attach %d", pid[i]);
17486d7f5d3SJohn Marino printf("wait %d\n", i);
17586d7f5d3SJohn Marino if (waitpid(pid[i], &status, WUNTRACED) < 0)
17686d7f5d3SJohn Marino err(1, "waitpid(ptrace)");
17786d7f5d3SJohn Marino printf("awake %d\n", i);
17886d7f5d3SJohn Marino usleep(sleeptime/3);
17986d7f5d3SJohn Marino if (ptrace(PT_DETACH, pid[i], (caddr_t)1, 0) < 0)
18086d7f5d3SJohn Marino err(1, "ptrace detach %d", pid[i]);
18186d7f5d3SJohn Marino printf("done %d\n", i);
18286d7f5d3SJohn Marino usleep(sleeptime/3);
18386d7f5d3SJohn Marino }
18486d7f5d3SJohn Marino }
18586d7f5d3SJohn Marino for (i=0; i<nprocs; i++) {
18686d7f5d3SJohn Marino printf("reap %d: ", i);
18786d7f5d3SJohn Marino fflush(stdout);
18886d7f5d3SJohn Marino kill(pid[i], SIGINT);
18986d7f5d3SJohn Marino waitpid(pid[i], &status, 0);
19086d7f5d3SJohn Marino printf(" status %d\n", status);
19186d7f5d3SJohn Marino }
19286d7f5d3SJohn Marino exit(0);
19386d7f5d3SJohn Marino /* NOTREACHED */
19486d7f5d3SJohn Marino }
195