1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright 2018 Joyent, Inc.
14 */
15
16 /*
17 * Validate various fcntl(2) and flock(3C) operations.
18 */
19
20 #include "util.h"
21 #include <err.h>
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <libgen.h>
25 #include <signal.h>
26 #include <stdlib.h>
27 #include <strings.h>
28 #include <sys/debug.h>
29 #include <sys/file.h>
30 #include <sys/stat.h>
31 #include <sys/wait.h>
32 #include <unistd.h>
33
34
35 #define LOCKFILE_FMT "/tmp/.lockfile-%s-%ld"
36 #define LOCKDIR_FMT "/tmp/.lockdir-%s-%ld"
37
38 typedef struct lockinfo {
39 char *lf_name;
40 char *lf_path;
41 int lf_fd;
42 } lockinfo_t;
43
44
45 static void assert_write_locked_by(lockinfo_t *, pid_t);
46 static void assert_read_locked_by(lockinfo_t *, pid_t);
47 static void assert_unlocked(lockinfo_t *);
48 static void assert_all_unlocked(void);
49
50 static int flock_copyfil(lockinfo_t *, lockinfo_t *);
51 static int flock_mkfil(lockinfo_t *);
52 static int flock_mkdir(lockinfo_t *);
53 static void flock_rminfo(lockinfo_t *);
54
55 static void flock_fcntl(lockinfo_t *lf, int cmd, struct flock *fl);
56 static void flock_run(lock_style_t, boolean_t, lockinfo_t *,
57 pid_t *, int[]);
58 static int flock_wait(pid_t pid);
59 static void flock_cleanup_child(pid_t, int []);
60
61 static void flock_test_invalid(lockinfo_t *, int, short, short,
62 off_t, off_t);
63 static void flock_test_invalid64(lockinfo_t *, int, short, short,
64 off_t, off_t);
65 static void flock_test_exclusive(lock_style_t, lock_style_t,
66 lockinfo_t *, lockinfo_t *, boolean_t);
67 static void flock_test_shared(lock_style_t, lock_style_t, lockinfo_t *,
68 lockinfo_t *, boolean_t);
69 static void flock_test_upgrade_downgrade(void);
70
71 static char *acqprog = NULL;
72
73 static lockinfo_t flock_fileA = { "a", NULL, -1 };
74 static lockinfo_t flock_fileB = { "b", NULL, -1 };
75 static lockinfo_t flock_dirA = { "a", NULL, -1 };
76 static lockinfo_t flock_dirB = { "b", NULL, -1 };
77
78
79 static short cmds[8] = {
80 F_SETLK, F_SETLKW, F_GETLK,
81 F_OFD_SETLK, F_OFD_SETLKW, F_OFD_GETLK,
82 F_FLOCK, F_FLOCKW
83 };
84
85 static short cmds64[3] = {
86 F_OFD_SETLK64, F_OFD_SETLKW64, F_OFD_GETLK64
87 };
88
89
90 static void
91 flock_kill(pid_t pid)
92 {
93 while (kill(pid, SIGKILL) == -1) {
94 if (errno == EINTR)
95 continue;
96
97 err(EXIT_FAILURE, "kill failed");
98 }
99 }
100
101
102 static void
103 flock_fcntl(lockinfo_t *lf, int cmd, struct flock *fl)
104 {
105 if (fcntl(lf->lf_fd, cmd, fl) == -1) {
106 err(EXIT_FAILURE, "fcntl failed");
107 }
108 }
109
110
111 static void
112 assert_write_locked_by(lockinfo_t *lf, pid_t pid)
113 {
114 struct flock fl;
115
116 flock_reinit(&fl, F_WRLCK);
117 flock_fcntl(lf, F_GETLK, &fl);
118 VERIFY3_IMPL(fl.l_type, ==, F_WRLCK, short);
119 VERIFY3_IMPL(fl.l_sysid, ==, 0, int);
120 VERIFY3_IMPL(fl.l_pid, ==, pid, pid_t);
121
122 flock_reinit(&fl, F_WRLCK);
123 flock_fcntl(lf, F_OFD_GETLK, &fl);
124 VERIFY3_IMPL(fl.l_type, ==, F_WRLCK, short);
125 VERIFY3_IMPL(fl.l_sysid, ==, 0, int);
126 VERIFY3_IMPL(fl.l_pid, ==, pid, pid_t);
127
128 flock_reinit(&fl, F_RDLCK);
129 flock_fcntl(lf, F_GETLK, &fl);
130 VERIFY3_IMPL(fl.l_type, ==, F_WRLCK, short);
131 VERIFY3_IMPL(fl.l_sysid, ==, 0, int);
132 VERIFY3_IMPL(fl.l_pid, ==, pid, pid_t);
133
134 flock_reinit(&fl, F_RDLCK);
135 flock_fcntl(lf, F_OFD_GETLK, &fl);
136 VERIFY3_IMPL(fl.l_type, ==, F_WRLCK, short);
137 VERIFY3_IMPL(fl.l_sysid, ==, 0, int);
138 VERIFY3_IMPL(fl.l_pid, ==, pid, pid_t);
139 }
140
141
142 static void
143 assert_read_locked_by(lockinfo_t *lf, pid_t pid)
144 {
145 struct flock fl;
146
147 flock_reinit(&fl, F_WRLCK);
148 flock_fcntl(lf, F_GETLK, &fl);
149 VERIFY3_IMPL(fl.l_type, ==, F_RDLCK, short);
150 VERIFY3_IMPL(fl.l_sysid, ==, 0, int);
151 VERIFY3_IMPL(fl.l_pid, ==, pid, pid_t);
152
153 flock_reinit(&fl, F_WRLCK);
154 flock_fcntl(lf, F_OFD_GETLK, &fl);
155 VERIFY3_IMPL(fl.l_type, ==, F_RDLCK, short);
156 VERIFY3_IMPL(fl.l_sysid, ==, 0, int);
157 VERIFY3_IMPL(fl.l_pid, ==, pid, pid_t);
158
159 flock_reinit(&fl, F_RDLCK);
160 flock_fcntl(lf, F_GETLK, &fl);
161 VERIFY3_IMPL(fl.l_type, ==, F_UNLCK, short);
162 VERIFY3_IMPL(fl.l_sysid, ==, 0, int);
163 VERIFY3_IMPL(fl.l_pid, ==, 0, pid_t);
164
165 flock_reinit(&fl, F_RDLCK);
166 flock_fcntl(lf, F_OFD_GETLK, &fl);
167 VERIFY3_IMPL(fl.l_type, ==, F_UNLCK, short);
168 VERIFY3_IMPL(fl.l_sysid, ==, 0, int);
169 VERIFY3_IMPL(fl.l_pid, ==, 0, pid_t);
170 }
171
172 static void
173 assert_unlocked(lockinfo_t *lf)
174 {
175 struct flock fl;
176
177 flock_reinit(&fl, F_WRLCK);
178 flock_fcntl(lf, F_GETLK, &fl);
179 VERIFY3_IMPL(fl.l_type, ==, F_UNLCK, short);
180 VERIFY3_IMPL(fl.l_sysid, ==, 0, int);
181 VERIFY3_IMPL(fl.l_pid, ==, 0, pid_t);
182
183 flock_reinit(&fl, F_WRLCK);
184 flock_fcntl(lf, F_OFD_GETLK, &fl);
185 VERIFY3_IMPL(fl.l_type, ==, F_UNLCK, short);
186 VERIFY3_IMPL(fl.l_sysid, ==, 0, int);
187 VERIFY3_IMPL(fl.l_pid, ==, 0, pid_t);
188
189 flock_reinit(&fl, F_RDLCK);
190 flock_fcntl(lf, F_GETLK, &fl);
191 VERIFY3_IMPL(fl.l_type, ==, F_UNLCK, short);
192 VERIFY3_IMPL(fl.l_sysid, ==, 0, int);
193 VERIFY3_IMPL(fl.l_pid, ==, 0, pid_t);
194
195 flock_reinit(&fl, F_RDLCK);
196 flock_fcntl(lf, F_OFD_GETLK, &fl);
197 VERIFY3_IMPL(fl.l_type, ==, F_UNLCK, short);
198 VERIFY3_IMPL(fl.l_sysid, ==, 0, int);
199 VERIFY3_IMPL(fl.l_pid, ==, 0, pid_t);
200 }
201
202
203 static void
204 assert_all_unlocked(void)
205 {
206 assert_unlocked(&flock_fileA);
207 assert_unlocked(&flock_fileB);
208 assert_unlocked(&flock_dirA);
209 assert_unlocked(&flock_dirB);
210 }
211
212
213 static int
214 flock_copyfil(lockinfo_t *src, lockinfo_t *dst)
215 {
216 dst->lf_name = NULL;
217 dst->lf_path = NULL;
218 if ((dst->lf_fd = open(src->lf_path, O_RDWR)) == -1) {
219 warn("Failed to open %s", src->lf_path);
220 return (-1);
221 }
222
223 return (0);
224 }
225
226
227 static int
228 flock_mkfil(lockinfo_t *lf)
229 {
230 if (asprintf(&lf->lf_path, LOCKFILE_FMT, lf->lf_name, getpid()) < 0) {
231 warnx("Failed to generate lockfile name");
232 return (-1);
233 }
234
235 if ((lf->lf_fd = open(lf->lf_path, O_RDWR|O_CREAT, 0600)) == -1) {
236 warn("Failed to open %s", lf->lf_path);
237 return (-1);
238 }
239
240 return (0);
241 }
242
243
244 static int
245 flock_mkdir(lockinfo_t *lf)
246 {
247 if (asprintf(&lf->lf_path, LOCKDIR_FMT, lf->lf_name, getpid()) < 0) {
248 warnx("Failed to generate lockfile name");
249 return (-1);
250 }
251
252 if (mkdir(lf->lf_path, 0700) == -1) {
253 warn("Failed to make %s", lf->lf_path);
254 return (-1);
255 }
256
257 if ((lf->lf_fd = open(lf->lf_path, O_RDONLY)) == -1) {
258 warn("Failed to open %s", lf->lf_path);
259 return (-1);
260 }
261
262 return (0);
263 }
264
265
266 static void
267 flock_rminfo(lockinfo_t *lf)
268 {
269 if (lf->lf_fd != -1) {
270 (void) close(lf->lf_fd);
271 }
272 if (lf->lf_path != NULL) {
273 (void) unlink(lf->lf_path);
274 free(lf->lf_path);
275 }
276 }
277
278
279 static void
280 flock_run(lock_style_t style, boolean_t is_exclusive, lockinfo_t *lf,
281 pid_t *pid, int fds[])
282 {
283 char *stylestr = flock_stylestr(style);
284 char *modestr = is_exclusive ? "exclusive" : "shared";
285 char *argv[5] = { acqprog, stylestr, modestr, lf->lf_path, NULL };
286 int ret = pipe(fds);
287 if (ret == -1) {
288 err(EXIT_FAILURE, "pipe failed");
289 }
290
291 *pid = fork();
292 if (*pid == (pid_t)-1) {
293 err(EXIT_FAILURE, "fork failed");
294 } else if (*pid == (pid_t)0) {
295 /* Set up pipe for communicating with child */
296 ret = dup2(fds[1], 0);
297 if (ret == -1) {
298 err(EXIT_FAILURE, "dup2 failed");
299 }
300 ret = dup2(fds[1], 1);
301 if (ret == -1) {
302 err(EXIT_FAILURE, "dup2 failed");
303 }
304 closefrom(3);
305
306 (void) execv(acqprog, argv);
307 err(EXIT_FAILURE, "Failed to execute %s", acqprog);
308 }
309 }
310
311
312 static int
313 flock_wait(pid_t pid)
314 {
315 int childstat = 0;
316
317 while (waitpid(pid, &childstat, 0) == -1) {
318 if (errno == EINTR)
319 continue;
320
321 err(EXIT_FAILURE, "Failed to wait on child");
322 }
323
324 if (WIFEXITED(childstat)) {
325 return (WEXITSTATUS(childstat));
326 } else if (WIFSIGNALED(childstat)) {
327 return (1);
328 } else {
329 abort();
330 return (1);
331 }
332 }
333
334
335 static void
336 flock_cleanup_child(pid_t pid, int fds[])
337 {
338 (void) flock_wait(pid);
339 (void) close(fds[0]);
340 (void) close(fds[1]);
341 }
342
343
344 static void
345 flock_test_upgrade_downgrade(void)
346 {
347 lockinfo_t afd1, afd2, afd3;
348 pid_t pid;
349 int fds[2];
350
351 VERIFY3S(flock_copyfil(&flock_fileA, &afd1), ==, 0);
352 VERIFY3S(flock_copyfil(&flock_fileA, &afd2), ==, 0);
353 VERIFY3S(flock_copyfil(&flock_fileA, &afd3), ==, 0);
354
355 flock_log("Acquiring shared locks 1, 2 and 3...");
356 VERIFY3S(flock(afd1.lf_fd, LOCK_SH), ==, 0);
357 VERIFY3S(flock(afd2.lf_fd, LOCK_SH), ==, 0);
358 VERIFY3S(flock(afd3.lf_fd, LOCK_SH), ==, 0);
359 assert_read_locked_by(&flock_fileA, -1);
360 flock_log(" ok\n");
361
362 flock_log("Upgrading lock 3 should fail w/ EWOULDBLOCK...");
363 VERIFY3S(flock(afd3.lf_fd, LOCK_EX|LOCK_NB), ==, -1);
364 VERIFY3U(errno, ==, EWOULDBLOCK);
365 assert_read_locked_by(&flock_fileA, -1);
366 flock_log(" ok\n");
367
368 flock_log("Upgrading 3 should succeed after releasing locks 1 & 2...");
369 VERIFY3S(flock(afd1.lf_fd, LOCK_UN), ==, 0);
370 VERIFY3S(flock(afd2.lf_fd, LOCK_UN), ==, 0);
371 VERIFY3S(flock(afd3.lf_fd, LOCK_EX), ==, 0);
372 assert_write_locked_by(&flock_fileA, -1);
373 flock_log(" ok\n");
374
375
376 flock_log("Starting up child, then downgrading lock 3 to shared...");
377 flock_run(LSTYLE_FLOCK, B_FALSE, &flock_fileA, &pid, fds);
378 VERIFY3_IMPL(flock_nodata(fds[0]), ==, B_TRUE, boolean_t);
379 VERIFY3S(flock(afd3.lf_fd, LOCK_SH), ==, 0);
380 flock_block(fds[0]);
381 assert_read_locked_by(&flock_fileA, -1);
382 flock_log(" ok\n");
383
384 flock_log("Releasing child and upgrading...");
385 flock_alert(fds[0]);
386 flock_cleanup_child(pid, fds);
387 assert_read_locked_by(&flock_fileA, -1);
388 VERIFY3S(flock(afd3.lf_fd, LOCK_EX), ==, 0);
389 assert_write_locked_by(&flock_fileA, -1);
390 flock_log(" ok\n");
391
392 flock_log("Releasing lock 3...");
393 VERIFY3S(flock(afd3.lf_fd, LOCK_UN), ==, 0);
394 flock_rminfo(&afd1);
395 flock_rminfo(&afd2);
396 flock_rminfo(&afd3);
397 assert_all_unlocked();
398 flock_log(" ok\n");
399 }
400
401
402 static void
403 flock_test_invalid(lockinfo_t *lf, int cmd, short l_type, short l_whence,
404 off_t l_start, off_t l_len)
405 {
406 struct flock fl = {
407 .l_type = l_type,
408 .l_whence = l_whence,
409 .l_start = l_start,
410 .l_len = l_len
411 };
412
413 flock_log("fcntl(fd, %s, { %hd, %hd, %ld, %ld, ... })...",
414 flock_cmdname(cmd), l_type, l_whence, l_start, l_len);
415 VERIFY3S(fcntl(lf->lf_fd, cmd, &fl), ==, -1);
416 VERIFY3U(errno, ==, EINVAL);
417 flock_log(" ok\n");
418 }
419
420 static void
421 flock_test_invalid64(lockinfo_t *lf, int cmd, short l_type, short l_whence,
422 off_t l_start, off_t l_len)
423 {
424 struct flock64 fl = {
425 .l_type = l_type,
426 .l_whence = l_whence,
427 .l_start = l_start,
428 .l_len = l_len
429 };
430
431 flock_log("fcntl(fd, %s, { %hd, %hd, %ld, %ld, ... })...",
432 flock_cmdname(cmd), l_type, l_whence, l_start, l_len);
433 VERIFY3S(fcntl(lf->lf_fd, cmd, &fl), ==, -1);
434 VERIFY3U(errno, ==, EINVAL);
435 flock_log(" ok\n");
436 }
437
438 static void
439 flock_test_exclusive(lock_style_t styleA, lock_style_t styleB,
440 lockinfo_t *lock1, lockinfo_t *lock2, boolean_t kill_firstborn)
441 {
442 pid_t pidA, pidB;
443 int fdsA[2], fdsB[2];
444
445 flock_log("Running %s + %s tests (%s)...",
446 flock_stylename(styleA), flock_stylename(styleB),
447 kill_firstborn ? "kill child" : "child exits");
448
449 /* Create child, and wait for it to acquire the lock */
450 flock_run(styleA, B_TRUE, lock1, &pidA, fdsA);
451 flock_block(fdsA[0]);
452
453 /* Create second child, which shouldn't acquire & signal */
454 flock_run(styleB, B_TRUE, lock1, &pidB, fdsB);
455 VERIFY3_IMPL(flock_nodata(fdsB[0]), ==, B_TRUE, boolean_t);
456
457 /* lock1 is blocked for reading and writing */
458 assert_write_locked_by(lock1, styleA == LSTYLE_POSIX ? pidA : -1);
459 assert_unlocked(lock2);
460
461 /* Tell pidA to exit */
462 if (kill_firstborn) {
463 flock_kill(pidA);
464 } else {
465 flock_alert(fdsA[0]);
466 }
467 flock_cleanup_child(pidA, fdsA);
468
469 /* Wait for pidB to signal us */
470 flock_block(fdsB[0]);
471
472 /* lock1 is blocked for reading and writing */
473 assert_write_locked_by(lock1, styleB == LSTYLE_POSIX ? pidB : -1);
474 assert_unlocked(lock2);
475
476 /* Tell pidB to exit */
477 flock_alert(fdsB[0]);
478
479 flock_cleanup_child(pidB, fdsB);
480
481 /*
482 * Tests after child has released lock
483 */
484 assert_all_unlocked();
485
486 flock_log(" ok\n");
487 }
488
489
490 static void
491 flock_test_shared(lock_style_t styleA, lock_style_t styleB,
492 lockinfo_t *lock1, lockinfo_t *lock2, boolean_t kill_firstborn)
493 {
494 pid_t pidA, pidB;
495 int fdsA[2], fdsB[2];
496
497 flock_log("Running %s + %s tests (%s)...",
498 flock_stylename(styleA), flock_stylename(styleB),
499 kill_firstborn ? "kill child" : "child exits");
500
501 /* Create children, and wait for it to acquire the lock */
502 flock_run(styleB, B_FALSE, lock1, &pidB, fdsB);
503 flock_block(fdsB[0]);
504 flock_run(styleA, B_FALSE, lock1, &pidA, fdsA);
505 flock_block(fdsA[0]);
506
507 /* testfileA is only blocked for writing */
508 assert_read_locked_by(lock1, styleA == LSTYLE_POSIX ? pidA : -1);
509 assert_unlocked(lock2);
510
511 /* Tell pidA to exit */
512 if (kill_firstborn) {
513 flock_kill(pidA);
514 } else {
515 flock_alert(fdsA[0]);
516 }
517 flock_cleanup_child(pidA, fdsA);
518
519 /* testfileA is still blocked for writing by pidB */
520 assert_read_locked_by(lock1, styleB == LSTYLE_POSIX ? pidB : -1);
521 assert_unlocked(lock2);
522
523 /* Tell pidB to exit */
524 flock_alert(fdsB[0]);
525 flock_cleanup_child(pidB, fdsB);
526
527 assert_all_unlocked();
528
529 flock_log(" ok\n");
530 }
531
532
533 static void
534 flock_test_ofd_sameproc(void)
535 {
536 lockinfo_t afd1, afd2, afd3;
537
538 VERIFY3S(flock_copyfil(&flock_fileA, &afd1), ==, 0);
539 VERIFY3S(flock_copyfil(&flock_fileA, &afd2), ==, 0);
540 VERIFY3S(flock_copyfil(&flock_fileA, &afd3), ==, 0);
541
542 flock_log("Acquiring first two shared locks...");
543 VERIFY3S(flock(afd1.lf_fd, LOCK_SH), ==, 0);
544 VERIFY3S(flock(afd2.lf_fd, LOCK_SH), ==, 0);
545 assert_read_locked_by(&flock_fileA, -1);
546 flock_log(" ok\n");
547
548 flock_log("Acquiring an exclusive lock should fail w/ EWOULDBLOCK...");
549 VERIFY3S(flock(afd3.lf_fd, LOCK_EX|LOCK_NB), ==, -1);
550 VERIFY3U(errno, ==, EWOULDBLOCK);
551 flock_log(" ok\n");
552
553 flock_log("Releasing to acquire an exclusive lock...");
554 VERIFY3S(flock(afd1.lf_fd, LOCK_UN), ==, 0);
555 VERIFY3S(flock(afd2.lf_fd, LOCK_UN), ==, 0);
556 flock_log(" ok\n");
557
558 flock_log("Acquiring an exclusive lock...");
559 VERIFY3S(flock(afd3.lf_fd, LOCK_EX), ==, 0);
560 assert_write_locked_by(&flock_fileA, -1);
561 flock_log(" ok\n");
562
563 flock_log("Acquiring a shared lock should fail w/ EWOULDBLOCK...");
564 VERIFY3S(flock(afd1.lf_fd, LOCK_EX|LOCK_NB), ==, -1);
565 VERIFY3U(errno, ==, EWOULDBLOCK);
566 VERIFY3S(flock(afd2.lf_fd, LOCK_EX|LOCK_NB), ==, -1);
567 VERIFY3U(errno, ==, EWOULDBLOCK);
568 flock_log(" ok\n");
569
570 flock_log("Releasing exclusive lock...");
571 VERIFY3S(flock(afd3.lf_fd, LOCK_UN), ==, 0);
572 assert_all_unlocked();
573 flock_log(" ok\n");
574
575 flock_rminfo(&afd1);
576 flock_rminfo(&afd2);
577 flock_rminfo(&afd3);
578 }
579
580
581 static void
582 flock_runtests(void)
583 {
584 lock_style_t first, second;
585 int i;
586
587 flock_log("# Exclusive lock tests\n");
588 for (first = (lock_style_t)0; first < LSTYLE_LAST; first++) {
589 for (second = (lock_style_t)0; second < LSTYLE_LAST; second++) {
590 flock_test_exclusive(first, second,
591 &flock_fileA, &flock_fileB, B_TRUE);
592 flock_test_exclusive(first, second,
593 &flock_fileA, &flock_fileB, B_FALSE);
594 }
595 }
596
597 flock_log("# Shared lock tests\n");
598 for (first = (lock_style_t)0; first < LSTYLE_LAST; first++) {
599 for (second = (lock_style_t)0; second < LSTYLE_LAST; second++) {
600 flock_test_shared(first, second,
601 &flock_fileA, &flock_fileB, B_TRUE);
602 flock_test_shared(first, second,
603 &flock_fileA, &flock_fileB, B_FALSE);
604 }
605 }
606
607 flock_log("# flock(3C) directory lock tests\n");
608 flock_test_exclusive(LSTYLE_FLOCK, LSTYLE_FLOCK,
609 &flock_dirA, &flock_dirB, B_TRUE);
610 flock_test_exclusive(LSTYLE_FLOCK, LSTYLE_FLOCK,
611 &flock_dirA, &flock_dirB, B_FALSE);
612 flock_test_shared(LSTYLE_FLOCK, LSTYLE_FLOCK,
613 &flock_dirA, &flock_dirB, B_TRUE);
614 flock_test_shared(LSTYLE_FLOCK, LSTYLE_FLOCK,
615 &flock_dirA, &flock_dirB, B_FALSE);
616
617
618 flock_log("# Invalid fcntl(2) parameters tests\n");
619 for (i = 0; i < sizeof (cmds) / sizeof (short); i++) {
620 flock_test_invalid(&flock_fileA, cmds[i], 200, 0, 0, 0);
621 flock_test_invalid(&flock_fileA, cmds[i], -1, 0, 0, 0);
622 }
623 for (i = 3; i < sizeof (cmds) / sizeof (short); i++) {
624 flock_test_invalid(&flock_fileA, cmds[i], F_WRLCK, 1, 0, 0);
625 flock_test_invalid(&flock_fileA, cmds[i], F_WRLCK, 0, 1, 0);
626 flock_test_invalid(&flock_fileA, cmds[i], F_WRLCK, 0, 0, 1);
627 }
628 for (i = 0; i < sizeof (cmds64) / sizeof (short); i++) {
629 flock_test_invalid64(&flock_fileA, cmds64[i], F_WRLCK, 1, 0, 0);
630 flock_test_invalid64(&flock_fileA, cmds64[i], F_WRLCK, 0, 1, 0);
631 flock_test_invalid64(&flock_fileA, cmds64[i], F_WRLCK, 0, 0, 1);
632 }
633
634 flock_log("# Testing that multiple OFD locks work in a process\n");
635 flock_test_ofd_sameproc();
636
637 flock_log("# Testing flock(3C) upgrade/downgrade tests\n");
638 flock_test_upgrade_downgrade();
639 }
640
641
642 int
643 main(int argc, char *argv[])
644 {
645 char *basestr, *suffix, *dirstr, *dirpath;
646 pid_t testrunner;
647 int exval;
648
649 LOG = B_TRUE;
650
651 if (argc < 1) {
652 errx(EXIT_FAILURE, "Can't find program name!");
653 }
654
655 dirstr = strdup(argv[0]);
656 dirpath = dirname(dirstr);
657 basestr = strdup(argv[0]);
658 suffix = basename(basestr);
659
660 while (*suffix != '.' && *suffix != '\0') {
661 suffix += 1;
662 }
663
664 if (asprintf(&acqprog, "%s/acquire-lock%s", dirpath, suffix) < 0) {
665 errx(EXIT_FAILURE,
666 "Can't generate lock acquisition program name!");
667 }
668
669 if (access(acqprog, X_OK) != 0) {
670 err(EXIT_FAILURE,
671 "Can't run lock acquisition program %s", acqprog);
672 }
673
674 /* Create several lockfiles for testing */
675 if (flock_mkfil(&flock_fileA) != 0 ||
676 flock_mkfil(&flock_fileB) != 0 ||
677 flock_mkdir(&flock_dirA) != 0 ||
678 flock_mkdir(&flock_dirB) != 0) {
679 exval = 1;
680 goto cleanup;
681 }
682
683 /*
684 * We run the tests in a child process so that when tests fail
685 * we can still clean up our temporary files.
686 */
687 testrunner = fork();
688 if (testrunner == (pid_t)-1) {
689 err(EXIT_FAILURE, "Unable to fork to run tests");
690 } else if (testrunner == (pid_t)0) {
691 flock_runtests();
692 return (0);
693 }
694
695 exval = flock_wait(testrunner);
696
697 cleanup:
698 free(basestr);
699 free(dirstr);
700 flock_rminfo(&flock_fileA);
701 flock_rminfo(&flock_fileB);
702 flock_rminfo(&flock_dirA);
703 flock_rminfo(&flock_dirB);
704 return (exval);
705 }