xref: /dragonfly/test/lockf/lockf.c (revision 86d7f5d305c6adaa56ff4582ece9859d73106103)
1 /*        $NetBSD: lockf.c,v 1.4 2000/07/30 09:16:06 jdolecek Exp $   */
2 /* $DragonFly: src/test/lockf/lockf.c,v 1.1 2004/05/11 08:03:57 joerg Exp $ */
3 
4 /*-
5  * Copyright (c) 2000 The NetBSD Foundation, Inc.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *        This product includes software developed by the NetBSD
19  *        Foundation, Inc. and its contributors.
20  * 4. Neither the name of The NetBSD Foundation nor the names of its
21  *    contributors may be used to endorse or promote products derived
22  *    from this software without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
25  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
26  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
27  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
28  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34  * POSSIBILITY OF SUCH DAMAGE.
35  */
36 
37 /*
38  * lockf regression test:
39  *
40  * Tests:
41  * 1) fork N child processes, do a bunch of random byte range lock/unlock.
42  */
43 
44 #include <sys/types.h>
45 #include <sys/wait.h>
46 #include <sys/ptrace.h>
47 
48 #include <unistd.h>
49 #include <fcntl.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <err.h>
53 #include <signal.h>
54 #include <errno.h>
55 
56 int nlocks = 10000;                     /* number of locks per thread */
57 int nprocs = 100;             /* number of processes to spawn */
58 int sleeptime = 50000;                  /* sleep time between locks, usec */
59 off_t size = 65536;           /* size of file to lock */
60 const char *lockfile = "/tmp/lockf_test";
61 
62 static uint32_t
random_uint32(void)63 random_uint32(void)
64 {
65           return lrand48();
66 }
67 
68 
69 static void
trylocks(int id)70 trylocks(int id)
71 {
72           int i, ret, fd;
73           int uids[3];
74           const char *which;
75 
76           uids[0] = -1;
77           uids[1] = getuid();
78           uids[2] = geteuid();
79           srand48(getpid());
80 
81           fd = open (lockfile, O_RDWR, 0);
82 
83           if (fd < 0)
84                     err(1, lockfile);
85 
86           printf("%d: start\n", id);
87 
88           for (i=0; i<nlocks; i++) {
89                     struct flock fl;
90                     ret = random_uint32() % 3;
91                     if (uids[ret] != -1) {
92                               printf("switching to uid %d\n", uids[ret]);
93                               setuid(uids[ret]);
94                     }
95 
96                     fl.l_start = random_uint32() % size;
97                     fl.l_len = random_uint32() % size;
98                     switch (random_uint32() % 3) {
99                     case 0:
100                               which = "read";
101                               fl.l_type = F_RDLCK;
102                               break;
103                     case 1:
104                               which = "write";
105                               fl.l_type = F_WRLCK;
106                               break;
107                     case 2:
108                               which = "un";
109                               fl.l_type = F_UNLCK;
110                               break;
111                     }
112                     fl.l_whence = SEEK_SET;
113 
114                     printf("%d: try %slock %d to %d\n", id, which, (int)fl.l_start,
115                         (int)(fl.l_start + fl.l_len));
116 
117                     ret = fcntl(fd, F_SETLKW, &fl);
118 
119                     if (ret < 0)
120                               perror("fcntl");
121                     printf("%d: got %slock %d to %d\n", id, which, (int)fl.l_start,
122                         ((int)(fl.l_start + fl.l_len)));
123 
124                     if (usleep(sleeptime) < 0)
125                       err(1, "usleep");
126           }
127           printf("%d: done\n", id);
128           close (fd);
129 }
130 
131 /* ARGSUSED */
132 int
main(int argc,char ** argv)133 main(int argc, char **argv)
134 {
135           int i, j;
136           pid_t *pid;
137           int status;
138           int fd;
139 
140           unlink(lockfile);
141 
142           fd = open (lockfile, O_RDWR|O_CREAT|O_EXCL|O_TRUNC, 0666);
143           if (fd < 0)
144                     err(1, "%s", lockfile);
145 
146           if (ftruncate(fd, size) < 0)
147                     err(1, "ftruncate of %s failed", lockfile);
148 
149           fsync(fd);
150           close(fd);
151 
152           pid = malloc(nprocs * sizeof(pid_t));
153 
154           for (i=0; i<nprocs; i++) {
155                     pid[i] = fork();
156                     switch (pid[i]) {
157                     case 0:
158                               trylocks(i);
159                               _exit(0);
160                               break;
161                     case -1:
162                               err(1, "fork failed");
163                               break;
164                     default:
165                               break;
166                     }
167           }
168           for (j=0; j<100; j++) {
169                     printf("parent: run %i\n", j+1);
170                     for (i=0; i<nprocs; i++) {
171                               printf("stop %d\n", i);
172                               if (ptrace(PT_ATTACH, pid[i], 0, 0) < 0)
173                                         err(1, "ptrace attach %d", pid[i]);
174                               printf("wait %d\n", i);
175                               if (waitpid(pid[i], &status, WUNTRACED) < 0)
176                                         err(1, "waitpid(ptrace)");
177                               printf("awake %d\n", i);
178                               usleep(sleeptime/3);
179                               if (ptrace(PT_DETACH, pid[i], (caddr_t)1, 0) < 0)
180                                         err(1, "ptrace detach %d", pid[i]);
181                               printf("done %d\n", i);
182                               usleep(sleeptime/3);
183                     }
184           }
185           for (i=0; i<nprocs; i++) {
186                     printf("reap %d: ", i);
187                     fflush(stdout);
188                     kill(pid[i], SIGINT);
189                     waitpid(pid[i], &status, 0);
190                     printf(" status %d\n", status);
191           }
192           exit(0);
193           /* NOTREACHED */
194 }
195