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 63 random_uint32(void) 64 { 65 return lrand48(); 66 } 67 68 69 static void 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 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