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