xref: /dflybsd-src/test/lockf/lockf.c (revision 86d7f5d305c6adaa56ff4582ece9859d73106103)
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