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 2019 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
38typedef struct lockinfo {
39	char *lf_name;
40	char *lf_path;
41	int lf_fd;
42} lockinfo_t;
43
44
45static	void	assert_write_locked_by(lockinfo_t *, pid_t);
46static	void	assert_read_locked_by(lockinfo_t *, pid_t);
47static	void	assert_unlocked(lockinfo_t *);
48static	void	assert_all_unlocked(void);
49
50static	int	flock_copyfil(lockinfo_t *, lockinfo_t *);
51static	int	flock_mkfil(lockinfo_t *);
52static	int	flock_mkdir(lockinfo_t *);
53static	void	flock_rminfo(lockinfo_t *);
54
55static	void	flock_fcntl(lockinfo_t *lf, int cmd, struct flock *fl);
56static	void	flock_run(lock_style_t, boolean_t, lockinfo_t *,
57		    pid_t *, int[]);
58static	int	flock_wait(pid_t pid);
59static	void	flock_cleanup_child(pid_t, int []);
60
61static	void	flock_test_invalid(lockinfo_t *, int, short, short,
62		    off_t, off_t);
63static	void	flock_test_invalid64(lockinfo_t *, int, short, short,
64		    off_t, off_t);
65static	void	flock_test_exclusive(lock_style_t, lock_style_t,
66		    lockinfo_t *, lockinfo_t *, boolean_t);
67static	void	flock_test_shared(lock_style_t, lock_style_t, lockinfo_t *,
68		    lockinfo_t *, boolean_t);
69static	void	flock_test_upgrade_downgrade(void);
70
71static char *acqprog = NULL;
72
73static lockinfo_t flock_fileA = { "a", NULL, -1 };
74static lockinfo_t flock_fileB = { "b", NULL, -1 };
75static lockinfo_t flock_dirA = { "a", NULL, -1 };
76static lockinfo_t flock_dirB = { "b", NULL, -1 };
77
78
79static 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
85static short cmds64[3] = {
86	F_OFD_SETLK64, F_OFD_SETLKW64, F_OFD_GETLK64
87};
88
89
90static void
91flock_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
102static void
103flock_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
111static void
112assert_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
142static void
143assert_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
172static void
173assert_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
203static void
204assert_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
213static int
214flock_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
227static int
228flock_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
244static int
245flock_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
266static void
267flock_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
279static void
280flock_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
312static int
313flock_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	}
331}
332
333
334static void
335flock_cleanup_child(pid_t pid, int fds[])
336{
337	(void) flock_wait(pid);
338	(void) close(fds[0]);
339	(void) close(fds[1]);
340}
341
342
343static void
344flock_test_upgrade_downgrade(void)
345{
346	lockinfo_t afd1, afd2, afd3;
347	pid_t pid;
348	int fds[2];
349
350	VERIFY3S(flock_copyfil(&flock_fileA, &afd1), ==, 0);
351	VERIFY3S(flock_copyfil(&flock_fileA, &afd2), ==, 0);
352	VERIFY3S(flock_copyfil(&flock_fileA, &afd3), ==, 0);
353
354	flock_log("Acquiring shared locks 1, 2 and 3...");
355	VERIFY3S(flock(afd1.lf_fd, LOCK_SH), ==, 0);
356	VERIFY3S(flock(afd2.lf_fd, LOCK_SH), ==, 0);
357	VERIFY3S(flock(afd3.lf_fd, LOCK_SH), ==, 0);
358	assert_read_locked_by(&flock_fileA, -1);
359	flock_log(" ok\n");
360
361	flock_log("Upgrading lock 3 should fail w/ EWOULDBLOCK...");
362	VERIFY3S(flock(afd3.lf_fd, LOCK_EX|LOCK_NB), ==, -1);
363	VERIFY3U(errno, ==, EWOULDBLOCK);
364	assert_read_locked_by(&flock_fileA, -1);
365	flock_log(" ok\n");
366
367	flock_log("Upgrading 3 should succeed after releasing locks 1 & 2...");
368	VERIFY3S(flock(afd1.lf_fd, LOCK_UN), ==, 0);
369	VERIFY3S(flock(afd2.lf_fd, LOCK_UN), ==, 0);
370	VERIFY3S(flock(afd3.lf_fd, LOCK_EX), ==, 0);
371	assert_write_locked_by(&flock_fileA, -1);
372	flock_log(" ok\n");
373
374
375	flock_log("Starting up child, then downgrading lock 3 to shared...");
376	flock_run(LSTYLE_FLOCK, B_FALSE, &flock_fileA, &pid, fds);
377	VERIFY3_IMPL(flock_nodata(fds[0]), ==, B_TRUE, boolean_t);
378	VERIFY3S(flock(afd3.lf_fd, LOCK_SH), ==, 0);
379	flock_block(fds[0]);
380	assert_read_locked_by(&flock_fileA, -1);
381	flock_log(" ok\n");
382
383	flock_log("Releasing child and upgrading...");
384	flock_alert(fds[0]);
385	flock_cleanup_child(pid, fds);
386	assert_read_locked_by(&flock_fileA, -1);
387	VERIFY3S(flock(afd3.lf_fd, LOCK_EX), ==, 0);
388	assert_write_locked_by(&flock_fileA, -1);
389	flock_log(" ok\n");
390
391	flock_log("Releasing lock 3...");
392	VERIFY3S(flock(afd3.lf_fd, LOCK_UN), ==, 0);
393	flock_rminfo(&afd1);
394	flock_rminfo(&afd2);
395	flock_rminfo(&afd3);
396	assert_all_unlocked();
397	flock_log(" ok\n");
398}
399
400
401static void
402flock_test_invalid(lockinfo_t *lf, int cmd, short l_type, short l_whence,
403    off_t l_start, off_t l_len)
404{
405	struct flock fl = {
406		.l_type = l_type,
407		.l_whence = l_whence,
408		.l_start = l_start,
409		.l_len = l_len
410	};
411
412	flock_log("fcntl(fd, %s, { %hd, %hd, %ld, %ld, ... })...",
413	    flock_cmdname(cmd), l_type, l_whence, l_start, l_len);
414	VERIFY3S(fcntl(lf->lf_fd, cmd, &fl), ==, -1);
415	VERIFY3U(errno, ==, EINVAL);
416	flock_log(" ok\n");
417}
418
419static void
420flock_test_invalid64(lockinfo_t *lf, int cmd, short l_type, short l_whence,
421    off_t l_start, off_t l_len)
422{
423	struct flock64 fl = {
424		.l_type = l_type,
425		.l_whence = l_whence,
426		.l_start = l_start,
427		.l_len = l_len
428	};
429
430	flock_log("fcntl(fd, %s, { %hd, %hd, %ld, %ld, ... })...",
431	    flock_cmdname(cmd), l_type, l_whence, l_start, l_len);
432	VERIFY3S(fcntl(lf->lf_fd, cmd, &fl), ==, -1);
433	VERIFY3U(errno, ==, EINVAL);
434	flock_log(" ok\n");
435}
436
437static void
438flock_test_exclusive(lock_style_t styleA, lock_style_t styleB,
439    lockinfo_t *lock1, lockinfo_t *lock2, boolean_t kill_firstborn)
440{
441	pid_t pidA, pidB;
442	int fdsA[2], fdsB[2];
443
444	flock_log("Running %s + %s tests (%s)...",
445	    flock_stylename(styleA), flock_stylename(styleB),
446	    kill_firstborn ? "kill child" : "child exits");
447
448	/* Create child, and wait for it to acquire the lock */
449	flock_run(styleA, B_TRUE, lock1, &pidA, fdsA);
450	flock_block(fdsA[0]);
451
452	/* Create second child, which shouldn't acquire & signal */
453	flock_run(styleB, B_TRUE, lock1, &pidB, fdsB);
454	VERIFY3_IMPL(flock_nodata(fdsB[0]), ==, B_TRUE, boolean_t);
455
456	/* lock1 is blocked for reading and writing */
457	assert_write_locked_by(lock1, styleA == LSTYLE_POSIX ? pidA : -1);
458	assert_unlocked(lock2);
459
460	/* Tell pidA to exit */
461	if (kill_firstborn) {
462		flock_kill(pidA);
463	} else {
464		flock_alert(fdsA[0]);
465	}
466	flock_cleanup_child(pidA, fdsA);
467
468	/* Wait for pidB to signal us */
469	flock_block(fdsB[0]);
470
471	/* lock1 is blocked for reading and writing */
472	assert_write_locked_by(lock1, styleB == LSTYLE_POSIX ? pidB : -1);
473	assert_unlocked(lock2);
474
475	/* Tell pidB to exit */
476	flock_alert(fdsB[0]);
477
478	flock_cleanup_child(pidB, fdsB);
479
480	/*
481	 * Tests after child has released lock
482	 */
483	assert_all_unlocked();
484
485	flock_log(" ok\n");
486}
487
488
489static void
490flock_test_shared(lock_style_t styleA, lock_style_t styleB,
491    lockinfo_t *lock1, lockinfo_t *lock2, boolean_t kill_firstborn)
492{
493	pid_t pidA, pidB;
494	int fdsA[2], fdsB[2];
495
496	flock_log("Running %s + %s tests (%s)...",
497	    flock_stylename(styleA), flock_stylename(styleB),
498	    kill_firstborn ? "kill child" : "child exits");
499
500	/* Create children, and wait for it to acquire the lock */
501	flock_run(styleB, B_FALSE, lock1, &pidB, fdsB);
502	flock_block(fdsB[0]);
503	flock_run(styleA, B_FALSE, lock1, &pidA, fdsA);
504	flock_block(fdsA[0]);
505
506	/* testfileA is only blocked for writing */
507	assert_read_locked_by(lock1, styleA == LSTYLE_POSIX ? pidA : -1);
508	assert_unlocked(lock2);
509
510	/* Tell pidA to exit */
511	if (kill_firstborn) {
512		flock_kill(pidA);
513	} else {
514		flock_alert(fdsA[0]);
515	}
516	flock_cleanup_child(pidA, fdsA);
517
518	/* testfileA is still blocked for writing by pidB */
519	assert_read_locked_by(lock1, styleB == LSTYLE_POSIX ? pidB : -1);
520	assert_unlocked(lock2);
521
522	/* Tell pidB to exit */
523	flock_alert(fdsB[0]);
524	flock_cleanup_child(pidB, fdsB);
525
526	assert_all_unlocked();
527
528	flock_log(" ok\n");
529}
530
531
532static void
533flock_test_ofd_sameproc(void)
534{
535	lockinfo_t afd1, afd2, afd3;
536
537	VERIFY3S(flock_copyfil(&flock_fileA, &afd1), ==, 0);
538	VERIFY3S(flock_copyfil(&flock_fileA, &afd2), ==, 0);
539	VERIFY3S(flock_copyfil(&flock_fileA, &afd3), ==, 0);
540
541	flock_log("Acquiring first two shared locks...");
542	VERIFY3S(flock(afd1.lf_fd, LOCK_SH), ==, 0);
543	VERIFY3S(flock(afd2.lf_fd, LOCK_SH), ==, 0);
544	assert_read_locked_by(&flock_fileA, -1);
545	flock_log(" ok\n");
546
547	flock_log("Acquiring an exclusive lock should fail w/ EWOULDBLOCK...");
548	VERIFY3S(flock(afd3.lf_fd, LOCK_EX|LOCK_NB), ==, -1);
549	VERIFY3U(errno, ==, EWOULDBLOCK);
550	flock_log(" ok\n");
551
552	flock_log("Releasing to acquire an exclusive lock...");
553	VERIFY3S(flock(afd1.lf_fd, LOCK_UN), ==, 0);
554	VERIFY3S(flock(afd2.lf_fd, LOCK_UN), ==, 0);
555	flock_log(" ok\n");
556
557	flock_log("Acquiring an exclusive lock...");
558	VERIFY3S(flock(afd3.lf_fd, LOCK_EX), ==, 0);
559	assert_write_locked_by(&flock_fileA, -1);
560	flock_log(" ok\n");
561
562	flock_log("Acquiring a shared lock should fail w/ EWOULDBLOCK...");
563	VERIFY3S(flock(afd1.lf_fd, LOCK_EX|LOCK_NB), ==, -1);
564	VERIFY3U(errno, ==, EWOULDBLOCK);
565	VERIFY3S(flock(afd2.lf_fd, LOCK_EX|LOCK_NB), ==, -1);
566	VERIFY3U(errno, ==, EWOULDBLOCK);
567	flock_log(" ok\n");
568
569	flock_log("Releasing exclusive lock...");
570	VERIFY3S(flock(afd3.lf_fd, LOCK_UN), ==, 0);
571	assert_all_unlocked();
572	flock_log(" ok\n");
573
574	flock_rminfo(&afd1);
575	flock_rminfo(&afd2);
576	flock_rminfo(&afd3);
577}
578
579
580static void
581flock_runtests(void)
582{
583	lock_style_t first, second;
584	int i;
585
586	flock_log("# Exclusive lock tests\n");
587	for (first = (lock_style_t)0; first < LSTYLE_LAST; first++) {
588		for (second = (lock_style_t)0; second < LSTYLE_LAST; second++) {
589			flock_test_exclusive(first, second,
590			    &flock_fileA, &flock_fileB, B_TRUE);
591			flock_test_exclusive(first, second,
592			    &flock_fileA, &flock_fileB, B_FALSE);
593		}
594	}
595
596	flock_log("# Shared lock tests\n");
597	for (first = (lock_style_t)0; first < LSTYLE_LAST; first++) {
598		for (second = (lock_style_t)0; second < LSTYLE_LAST; second++) {
599			flock_test_shared(first, second,
600			    &flock_fileA, &flock_fileB, B_TRUE);
601			flock_test_shared(first, second,
602			    &flock_fileA, &flock_fileB, B_FALSE);
603		}
604	}
605
606	flock_log("# flock(3C) directory lock tests\n");
607	flock_test_exclusive(LSTYLE_FLOCK, LSTYLE_FLOCK,
608	    &flock_dirA, &flock_dirB, B_TRUE);
609	flock_test_exclusive(LSTYLE_FLOCK, LSTYLE_FLOCK,
610	    &flock_dirA, &flock_dirB, B_FALSE);
611	flock_test_shared(LSTYLE_FLOCK, LSTYLE_FLOCK,
612	    &flock_dirA, &flock_dirB, B_TRUE);
613	flock_test_shared(LSTYLE_FLOCK, LSTYLE_FLOCK,
614	    &flock_dirA, &flock_dirB, B_FALSE);
615
616
617	flock_log("# Invalid fcntl(2) parameters tests\n");
618	for (i = 0; i < sizeof (cmds) / sizeof (short); i++) {
619		flock_test_invalid(&flock_fileA, cmds[i], 200, 0, 0, 0);
620		flock_test_invalid(&flock_fileA, cmds[i], -1, 0, 0, 0);
621	}
622	for (i = 3; i < sizeof (cmds) / sizeof (short); i++) {
623		flock_test_invalid(&flock_fileA, cmds[i], F_WRLCK, 1, 0, 0);
624		flock_test_invalid(&flock_fileA, cmds[i], F_WRLCK, 0, 1, 0);
625		flock_test_invalid(&flock_fileA, cmds[i], F_WRLCK, 0, 0, 1);
626	}
627	for (i = 0; i < sizeof (cmds64) / sizeof (short); i++) {
628		flock_test_invalid64(&flock_fileA, cmds64[i], F_WRLCK, 1, 0, 0);
629		flock_test_invalid64(&flock_fileA, cmds64[i], F_WRLCK, 0, 1, 0);
630		flock_test_invalid64(&flock_fileA, cmds64[i], F_WRLCK, 0, 0, 1);
631	}
632
633	flock_log("# Testing that multiple OFD locks work in a process\n");
634	flock_test_ofd_sameproc();
635
636	flock_log("# Testing flock(3C) upgrade/downgrade tests\n");
637	flock_test_upgrade_downgrade();
638}
639
640
641int
642main(int argc, char *argv[])
643{
644	char *basestr, *suffix, *dirstr, *dirpath;
645	pid_t testrunner;
646	int exval;
647
648	LOG = B_TRUE;
649
650	if (argc < 1) {
651		errx(EXIT_FAILURE, "Can't find program name!");
652	}
653
654	dirstr = strdup(argv[0]);
655	dirpath = dirname(dirstr);
656	basestr = strdup(argv[0]);
657	suffix = basename(basestr);
658
659	while (*suffix != '.' && *suffix != '\0') {
660		suffix += 1;
661	}
662
663	if (asprintf(&acqprog, "%s/acquire-lock%s", dirpath, suffix) < 0) {
664		errx(EXIT_FAILURE,
665		    "Can't generate lock acquisition program name!");
666	}
667
668	if (access(acqprog, X_OK) != 0) {
669		err(EXIT_FAILURE,
670		    "Can't run lock acquisition program %s", acqprog);
671	}
672
673	/* Create several lockfiles for testing */
674	if (flock_mkfil(&flock_fileA) != 0 ||
675	    flock_mkfil(&flock_fileB) != 0 ||
676	    flock_mkdir(&flock_dirA) != 0 ||
677	    flock_mkdir(&flock_dirB) != 0) {
678		exval = 1;
679		goto cleanup;
680	}
681
682	/*
683	 * We run the tests in a child process so that when tests fail
684	 * we can still clean up our temporary files.
685	 */
686	testrunner = fork();
687	if (testrunner == (pid_t)-1) {
688		err(EXIT_FAILURE, "Unable to fork to run tests");
689	} else if (testrunner == (pid_t)0) {
690		flock_runtests();
691		return (0);
692	}
693
694	exval = flock_wait(testrunner);
695
696cleanup:
697	free(basestr);
698	free(dirstr);
699	flock_rminfo(&flock_fileA);
700	flock_rminfo(&flock_fileB);
701	flock_rminfo(&flock_dirA);
702	flock_rminfo(&flock_dirB);
703	return (exval);
704}
705