190221f91SCody Peter Mello /*
290221f91SCody Peter Mello  * This file and its contents are supplied under the terms of the
390221f91SCody Peter Mello  * Common Development and Distribution License ("CDDL"), version 1.0.
490221f91SCody Peter Mello  * You may only use this file in accordance with the terms of version
590221f91SCody Peter Mello  * 1.0 of the CDDL.
690221f91SCody Peter Mello  *
790221f91SCody Peter Mello  * A full copy of the text of the CDDL should have accompanied this
890221f91SCody Peter Mello  * source.  A copy of the CDDL is also available via the Internet at
990221f91SCody Peter Mello  * http://www.illumos.org/license/CDDL.
1090221f91SCody Peter Mello  */
1190221f91SCody Peter Mello 
1290221f91SCody Peter Mello /*
13*44bf619dSJohn Levon  * Copyright 2019 Joyent, Inc.
1490221f91SCody Peter Mello  */
1590221f91SCody Peter Mello 
1690221f91SCody Peter Mello /*
1790221f91SCody Peter Mello  * Validate various fcntl(2) and flock(3C) operations.
1890221f91SCody Peter Mello  */
1990221f91SCody Peter Mello 
2090221f91SCody Peter Mello #include "util.h"
2190221f91SCody Peter Mello #include <err.h>
2290221f91SCody Peter Mello #include <errno.h>
2390221f91SCody Peter Mello #include <fcntl.h>
2490221f91SCody Peter Mello #include <libgen.h>
2590221f91SCody Peter Mello #include <signal.h>
2690221f91SCody Peter Mello #include <stdlib.h>
2790221f91SCody Peter Mello #include <strings.h>
2890221f91SCody Peter Mello #include <sys/debug.h>
2990221f91SCody Peter Mello #include <sys/file.h>
3090221f91SCody Peter Mello #include <sys/stat.h>
3190221f91SCody Peter Mello #include <sys/wait.h>
3290221f91SCody Peter Mello #include <unistd.h>
3390221f91SCody Peter Mello 
3490221f91SCody Peter Mello 
3590221f91SCody Peter Mello #define	LOCKFILE_FMT	"/tmp/.lockfile-%s-%ld"
3690221f91SCody Peter Mello #define	LOCKDIR_FMT	"/tmp/.lockdir-%s-%ld"
3790221f91SCody Peter Mello 
3890221f91SCody Peter Mello typedef struct lockinfo {
3990221f91SCody Peter Mello 	char *lf_name;
4090221f91SCody Peter Mello 	char *lf_path;
4190221f91SCody Peter Mello 	int lf_fd;
4290221f91SCody Peter Mello } lockinfo_t;
4390221f91SCody Peter Mello 
4490221f91SCody Peter Mello 
4590221f91SCody Peter Mello static	void	assert_write_locked_by(lockinfo_t *, pid_t);
4690221f91SCody Peter Mello static	void	assert_read_locked_by(lockinfo_t *, pid_t);
4790221f91SCody Peter Mello static	void	assert_unlocked(lockinfo_t *);
4890221f91SCody Peter Mello static	void	assert_all_unlocked(void);
4990221f91SCody Peter Mello 
5090221f91SCody Peter Mello static	int	flock_copyfil(lockinfo_t *, lockinfo_t *);
5190221f91SCody Peter Mello static	int	flock_mkfil(lockinfo_t *);
5290221f91SCody Peter Mello static	int	flock_mkdir(lockinfo_t *);
5390221f91SCody Peter Mello static	void	flock_rminfo(lockinfo_t *);
5490221f91SCody Peter Mello 
5590221f91SCody Peter Mello static	void	flock_fcntl(lockinfo_t *lf, int cmd, struct flock *fl);
5690221f91SCody Peter Mello static	void	flock_run(lock_style_t, boolean_t, lockinfo_t *,
5790221f91SCody Peter Mello 		    pid_t *, int[]);
5890221f91SCody Peter Mello static	int	flock_wait(pid_t pid);
5990221f91SCody Peter Mello static	void	flock_cleanup_child(pid_t, int []);
6090221f91SCody Peter Mello 
6190221f91SCody Peter Mello static	void	flock_test_invalid(lockinfo_t *, int, short, short,
6290221f91SCody Peter Mello 		    off_t, off_t);
639c7f1ae0SJerry Jelinek static	void	flock_test_invalid64(lockinfo_t *, int, short, short,
649c7f1ae0SJerry Jelinek 		    off_t, off_t);
6590221f91SCody Peter Mello static	void	flock_test_exclusive(lock_style_t, lock_style_t,
6690221f91SCody Peter Mello 		    lockinfo_t *, lockinfo_t *, boolean_t);
6790221f91SCody Peter Mello static	void	flock_test_shared(lock_style_t, lock_style_t, lockinfo_t *,
6890221f91SCody Peter Mello 		    lockinfo_t *, boolean_t);
6990221f91SCody Peter Mello static	void	flock_test_upgrade_downgrade(void);
7090221f91SCody Peter Mello 
7190221f91SCody Peter Mello static char *acqprog = NULL;
7290221f91SCody Peter Mello 
7390221f91SCody Peter Mello static lockinfo_t flock_fileA = { "a", NULL, -1 };
7490221f91SCody Peter Mello static lockinfo_t flock_fileB = { "b", NULL, -1 };
7590221f91SCody Peter Mello static lockinfo_t flock_dirA = { "a", NULL, -1 };
7690221f91SCody Peter Mello static lockinfo_t flock_dirB = { "b", NULL, -1 };
7790221f91SCody Peter Mello 
7890221f91SCody Peter Mello 
7990221f91SCody Peter Mello static short cmds[8] = {
8090221f91SCody Peter Mello 	F_SETLK, F_SETLKW, F_GETLK,
8190221f91SCody Peter Mello 	F_OFD_SETLK, F_OFD_SETLKW, F_OFD_GETLK,
8290221f91SCody Peter Mello 	F_FLOCK, F_FLOCKW
8390221f91SCody Peter Mello };
8490221f91SCody Peter Mello 
859c7f1ae0SJerry Jelinek static short cmds64[3] = {
869c7f1ae0SJerry Jelinek 	F_OFD_SETLK64, F_OFD_SETLKW64, F_OFD_GETLK64
879c7f1ae0SJerry Jelinek };
889c7f1ae0SJerry Jelinek 
8990221f91SCody Peter Mello 
9090221f91SCody Peter Mello static void
flock_kill(pid_t pid)9190221f91SCody Peter Mello flock_kill(pid_t pid)
9290221f91SCody Peter Mello {
9390221f91SCody Peter Mello 	while (kill(pid, SIGKILL) == -1) {
9490221f91SCody Peter Mello 		if (errno == EINTR)
9590221f91SCody Peter Mello 			continue;
9690221f91SCody Peter Mello 
9790221f91SCody Peter Mello 		err(EXIT_FAILURE, "kill failed");
9890221f91SCody Peter Mello 	}
9990221f91SCody Peter Mello }
10090221f91SCody Peter Mello 
10190221f91SCody Peter Mello 
10290221f91SCody Peter Mello static void
flock_fcntl(lockinfo_t * lf,int cmd,struct flock * fl)10390221f91SCody Peter Mello flock_fcntl(lockinfo_t *lf, int cmd, struct flock *fl)
10490221f91SCody Peter Mello {
10590221f91SCody Peter Mello 	if (fcntl(lf->lf_fd, cmd, fl) == -1) {
10690221f91SCody Peter Mello 		err(EXIT_FAILURE, "fcntl failed");
10790221f91SCody Peter Mello 	}
10890221f91SCody Peter Mello }
10990221f91SCody Peter Mello 
11090221f91SCody Peter Mello 
11190221f91SCody Peter Mello static void
assert_write_locked_by(lockinfo_t * lf,pid_t pid)11290221f91SCody Peter Mello assert_write_locked_by(lockinfo_t *lf, pid_t pid)
11390221f91SCody Peter Mello {
11490221f91SCody Peter Mello 	struct flock fl;
11590221f91SCody Peter Mello 
11690221f91SCody Peter Mello 	flock_reinit(&fl, F_WRLCK);
11790221f91SCody Peter Mello 	flock_fcntl(lf, F_GETLK, &fl);
11890221f91SCody Peter Mello 	VERIFY3_IMPL(fl.l_type, ==, F_WRLCK, short);
11990221f91SCody Peter Mello 	VERIFY3_IMPL(fl.l_sysid, ==, 0, int);
12090221f91SCody Peter Mello 	VERIFY3_IMPL(fl.l_pid, ==, pid, pid_t);
12190221f91SCody Peter Mello 
12290221f91SCody Peter Mello 	flock_reinit(&fl, F_WRLCK);
12390221f91SCody Peter Mello 	flock_fcntl(lf, F_OFD_GETLK, &fl);
12490221f91SCody Peter Mello 	VERIFY3_IMPL(fl.l_type, ==, F_WRLCK, short);
12590221f91SCody Peter Mello 	VERIFY3_IMPL(fl.l_sysid, ==, 0, int);
12690221f91SCody Peter Mello 	VERIFY3_IMPL(fl.l_pid, ==, pid, pid_t);
12790221f91SCody Peter Mello 
12890221f91SCody Peter Mello 	flock_reinit(&fl, F_RDLCK);
12990221f91SCody Peter Mello 	flock_fcntl(lf, F_GETLK, &fl);
13090221f91SCody Peter Mello 	VERIFY3_IMPL(fl.l_type, ==, F_WRLCK, short);
13190221f91SCody Peter Mello 	VERIFY3_IMPL(fl.l_sysid, ==, 0, int);
13290221f91SCody Peter Mello 	VERIFY3_IMPL(fl.l_pid, ==, pid, pid_t);
13390221f91SCody Peter Mello 
13490221f91SCody Peter Mello 	flock_reinit(&fl, F_RDLCK);
13590221f91SCody Peter Mello 	flock_fcntl(lf, F_OFD_GETLK, &fl);
13690221f91SCody Peter Mello 	VERIFY3_IMPL(fl.l_type, ==, F_WRLCK, short);
13790221f91SCody Peter Mello 	VERIFY3_IMPL(fl.l_sysid, ==, 0, int);
13890221f91SCody Peter Mello 	VERIFY3_IMPL(fl.l_pid, ==, pid, pid_t);
13990221f91SCody Peter Mello }
14090221f91SCody Peter Mello 
14190221f91SCody Peter Mello 
14290221f91SCody Peter Mello static void
assert_read_locked_by(lockinfo_t * lf,pid_t pid)14390221f91SCody Peter Mello assert_read_locked_by(lockinfo_t *lf, pid_t pid)
14490221f91SCody Peter Mello {
14590221f91SCody Peter Mello 	struct flock fl;
14690221f91SCody Peter Mello 
14790221f91SCody Peter Mello 	flock_reinit(&fl, F_WRLCK);
14890221f91SCody Peter Mello 	flock_fcntl(lf, F_GETLK, &fl);
14990221f91SCody Peter Mello 	VERIFY3_IMPL(fl.l_type, ==, F_RDLCK, short);
15090221f91SCody Peter Mello 	VERIFY3_IMPL(fl.l_sysid, ==, 0, int);
15190221f91SCody Peter Mello 	VERIFY3_IMPL(fl.l_pid, ==, pid, pid_t);
15290221f91SCody Peter Mello 
15390221f91SCody Peter Mello 	flock_reinit(&fl, F_WRLCK);
15490221f91SCody Peter Mello 	flock_fcntl(lf, F_OFD_GETLK, &fl);
15590221f91SCody Peter Mello 	VERIFY3_IMPL(fl.l_type, ==, F_RDLCK, short);
15690221f91SCody Peter Mello 	VERIFY3_IMPL(fl.l_sysid, ==, 0, int);
15790221f91SCody Peter Mello 	VERIFY3_IMPL(fl.l_pid, ==, pid, pid_t);
15890221f91SCody Peter Mello 
15990221f91SCody Peter Mello 	flock_reinit(&fl, F_RDLCK);
16090221f91SCody Peter Mello 	flock_fcntl(lf, F_GETLK, &fl);
16190221f91SCody Peter Mello 	VERIFY3_IMPL(fl.l_type, ==, F_UNLCK, short);
16290221f91SCody Peter Mello 	VERIFY3_IMPL(fl.l_sysid, ==, 0, int);
16390221f91SCody Peter Mello 	VERIFY3_IMPL(fl.l_pid, ==, 0, pid_t);
16490221f91SCody Peter Mello 
16590221f91SCody Peter Mello 	flock_reinit(&fl, F_RDLCK);
16690221f91SCody Peter Mello 	flock_fcntl(lf, F_OFD_GETLK, &fl);
16790221f91SCody Peter Mello 	VERIFY3_IMPL(fl.l_type, ==, F_UNLCK, short);
16890221f91SCody Peter Mello 	VERIFY3_IMPL(fl.l_sysid, ==, 0, int);
16990221f91SCody Peter Mello 	VERIFY3_IMPL(fl.l_pid, ==, 0, pid_t);
17090221f91SCody Peter Mello }
17190221f91SCody Peter Mello 
17290221f91SCody Peter Mello static void
assert_unlocked(lockinfo_t * lf)17390221f91SCody Peter Mello assert_unlocked(lockinfo_t *lf)
17490221f91SCody Peter Mello {
17590221f91SCody Peter Mello 	struct flock fl;
17690221f91SCody Peter Mello 
17790221f91SCody Peter Mello 	flock_reinit(&fl, F_WRLCK);
17890221f91SCody Peter Mello 	flock_fcntl(lf, F_GETLK, &fl);
17990221f91SCody Peter Mello 	VERIFY3_IMPL(fl.l_type, ==, F_UNLCK, short);
18090221f91SCody Peter Mello 	VERIFY3_IMPL(fl.l_sysid, ==, 0, int);
18190221f91SCody Peter Mello 	VERIFY3_IMPL(fl.l_pid, ==, 0, pid_t);
18290221f91SCody Peter Mello 
18390221f91SCody Peter Mello 	flock_reinit(&fl, F_WRLCK);
18490221f91SCody Peter Mello 	flock_fcntl(lf, F_OFD_GETLK, &fl);
18590221f91SCody Peter Mello 	VERIFY3_IMPL(fl.l_type, ==, F_UNLCK, short);
18690221f91SCody Peter Mello 	VERIFY3_IMPL(fl.l_sysid, ==, 0, int);
18790221f91SCody Peter Mello 	VERIFY3_IMPL(fl.l_pid, ==, 0, pid_t);
18890221f91SCody Peter Mello 
18990221f91SCody Peter Mello 	flock_reinit(&fl, F_RDLCK);
19090221f91SCody Peter Mello 	flock_fcntl(lf, F_GETLK, &fl);
19190221f91SCody Peter Mello 	VERIFY3_IMPL(fl.l_type, ==, F_UNLCK, short);
19290221f91SCody Peter Mello 	VERIFY3_IMPL(fl.l_sysid, ==, 0, int);
19390221f91SCody Peter Mello 	VERIFY3_IMPL(fl.l_pid, ==, 0, pid_t);
19490221f91SCody Peter Mello 
19590221f91SCody Peter Mello 	flock_reinit(&fl, F_RDLCK);
19690221f91SCody Peter Mello 	flock_fcntl(lf, F_OFD_GETLK, &fl);
19790221f91SCody Peter Mello 	VERIFY3_IMPL(fl.l_type, ==, F_UNLCK, short);
19890221f91SCody Peter Mello 	VERIFY3_IMPL(fl.l_sysid, ==, 0, int);
19990221f91SCody Peter Mello 	VERIFY3_IMPL(fl.l_pid, ==, 0, pid_t);
20090221f91SCody Peter Mello }
20190221f91SCody Peter Mello 
20290221f91SCody Peter Mello 
20390221f91SCody Peter Mello static void
assert_all_unlocked(void)20490221f91SCody Peter Mello assert_all_unlocked(void)
20590221f91SCody Peter Mello {
20690221f91SCody Peter Mello 	assert_unlocked(&flock_fileA);
20790221f91SCody Peter Mello 	assert_unlocked(&flock_fileB);
20890221f91SCody Peter Mello 	assert_unlocked(&flock_dirA);
20990221f91SCody Peter Mello 	assert_unlocked(&flock_dirB);
21090221f91SCody Peter Mello }
21190221f91SCody Peter Mello 
21290221f91SCody Peter Mello 
21390221f91SCody Peter Mello static int
flock_copyfil(lockinfo_t * src,lockinfo_t * dst)21490221f91SCody Peter Mello flock_copyfil(lockinfo_t *src, lockinfo_t *dst)
21590221f91SCody Peter Mello {
21690221f91SCody Peter Mello 	dst->lf_name = NULL;
21790221f91SCody Peter Mello 	dst->lf_path = NULL;
21890221f91SCody Peter Mello 	if ((dst->lf_fd = open(src->lf_path, O_RDWR)) == -1) {
21990221f91SCody Peter Mello 		warn("Failed to open %s", src->lf_path);
22090221f91SCody Peter Mello 		return (-1);
22190221f91SCody Peter Mello 	}
22290221f91SCody Peter Mello 
22390221f91SCody Peter Mello 	return (0);
22490221f91SCody Peter Mello }
22590221f91SCody Peter Mello 
22690221f91SCody Peter Mello 
22790221f91SCody Peter Mello static int
flock_mkfil(lockinfo_t * lf)22890221f91SCody Peter Mello flock_mkfil(lockinfo_t *lf)
22990221f91SCody Peter Mello {
23090221f91SCody Peter Mello 	if (asprintf(&lf->lf_path, LOCKFILE_FMT, lf->lf_name, getpid()) < 0) {
23190221f91SCody Peter Mello 		warnx("Failed to generate lockfile name");
23290221f91SCody Peter Mello 		return (-1);
23390221f91SCody Peter Mello 	}
23490221f91SCody Peter Mello 
23590221f91SCody Peter Mello 	if ((lf->lf_fd = open(lf->lf_path, O_RDWR|O_CREAT, 0600)) == -1)  {
23690221f91SCody Peter Mello 		warn("Failed to open %s", lf->lf_path);
23790221f91SCody Peter Mello 		return (-1);
23890221f91SCody Peter Mello 	}
23990221f91SCody Peter Mello 
24090221f91SCody Peter Mello 	return (0);
24190221f91SCody Peter Mello }
24290221f91SCody Peter Mello 
24390221f91SCody Peter Mello 
24490221f91SCody Peter Mello static int
flock_mkdir(lockinfo_t * lf)24590221f91SCody Peter Mello flock_mkdir(lockinfo_t *lf)
24690221f91SCody Peter Mello {
24790221f91SCody Peter Mello 	if (asprintf(&lf->lf_path, LOCKDIR_FMT, lf->lf_name, getpid()) < 0) {
24890221f91SCody Peter Mello 		warnx("Failed to generate lockfile name");
24990221f91SCody Peter Mello 		return (-1);
25090221f91SCody Peter Mello 	}
25190221f91SCody Peter Mello 
25290221f91SCody Peter Mello 	if (mkdir(lf->lf_path, 0700) == -1)  {
25390221f91SCody Peter Mello 		warn("Failed to make %s", lf->lf_path);
25490221f91SCody Peter Mello 		return (-1);
25590221f91SCody Peter Mello 	}
25690221f91SCody Peter Mello 
25790221f91SCody Peter Mello 	if ((lf->lf_fd = open(lf->lf_path, O_RDONLY)) == -1)  {
25890221f91SCody Peter Mello 		warn("Failed to open %s", lf->lf_path);
25990221f91SCody Peter Mello 		return (-1);
26090221f91SCody Peter Mello 	}
26190221f91SCody Peter Mello 
26290221f91SCody Peter Mello 	return (0);
26390221f91SCody Peter Mello }
26490221f91SCody Peter Mello 
26590221f91SCody Peter Mello 
26690221f91SCody Peter Mello static void
flock_rminfo(lockinfo_t * lf)26790221f91SCody Peter Mello flock_rminfo(lockinfo_t *lf)
26890221f91SCody Peter Mello {
26990221f91SCody Peter Mello 	if (lf->lf_fd != -1) {
27090221f91SCody Peter Mello 		(void) close(lf->lf_fd);
27190221f91SCody Peter Mello 	}
27290221f91SCody Peter Mello 	if (lf->lf_path != NULL) {
27390221f91SCody Peter Mello 		(void) unlink(lf->lf_path);
27490221f91SCody Peter Mello 		free(lf->lf_path);
27590221f91SCody Peter Mello 	}
27690221f91SCody Peter Mello }
27790221f91SCody Peter Mello 
27890221f91SCody Peter Mello 
27990221f91SCody Peter Mello static void
flock_run(lock_style_t style,boolean_t is_exclusive,lockinfo_t * lf,pid_t * pid,int fds[])28090221f91SCody Peter Mello flock_run(lock_style_t style, boolean_t is_exclusive, lockinfo_t *lf,
28190221f91SCody Peter Mello     pid_t *pid, int fds[])
28290221f91SCody Peter Mello {
28390221f91SCody Peter Mello 	char *stylestr = flock_stylestr(style);
28490221f91SCody Peter Mello 	char *modestr = is_exclusive ? "exclusive" : "shared";
28590221f91SCody Peter Mello 	char *argv[5] = { acqprog, stylestr, modestr, lf->lf_path, NULL };
28690221f91SCody Peter Mello 	int ret = pipe(fds);
28790221f91SCody Peter Mello 	if (ret == -1) {
28890221f91SCody Peter Mello 		err(EXIT_FAILURE, "pipe failed");
28990221f91SCody Peter Mello 	}
29090221f91SCody Peter Mello 
29190221f91SCody Peter Mello 	*pid = fork();
29290221f91SCody Peter Mello 	if (*pid == (pid_t)-1) {
29390221f91SCody Peter Mello 		err(EXIT_FAILURE, "fork failed");
29490221f91SCody Peter Mello 	} else if (*pid == (pid_t)0) {
29590221f91SCody Peter Mello 		/* Set up pipe for communicating with child */
29690221f91SCody Peter Mello 		ret = dup2(fds[1], 0);
29790221f91SCody Peter Mello 		if (ret == -1) {
29890221f91SCody Peter Mello 			err(EXIT_FAILURE, "dup2 failed");
29990221f91SCody Peter Mello 		}
30090221f91SCody Peter Mello 		ret = dup2(fds[1], 1);
30190221f91SCody Peter Mello 		if (ret == -1) {
30290221f91SCody Peter Mello 			err(EXIT_FAILURE, "dup2 failed");
30390221f91SCody Peter Mello 		}
30490221f91SCody Peter Mello 		closefrom(3);
30590221f91SCody Peter Mello 
30690221f91SCody Peter Mello 		(void) execv(acqprog, argv);
30790221f91SCody Peter Mello 		err(EXIT_FAILURE, "Failed to execute %s", acqprog);
30890221f91SCody Peter Mello 	}
30990221f91SCody Peter Mello }
31090221f91SCody Peter Mello 
31190221f91SCody Peter Mello 
31290221f91SCody Peter Mello static int
flock_wait(pid_t pid)31390221f91SCody Peter Mello flock_wait(pid_t pid)
31490221f91SCody Peter Mello {
31590221f91SCody Peter Mello 	int childstat = 0;
31690221f91SCody Peter Mello 
31790221f91SCody Peter Mello 	while (waitpid(pid, &childstat, 0) == -1) {
31890221f91SCody Peter Mello 		if (errno == EINTR)
31990221f91SCody Peter Mello 			continue;
32090221f91SCody Peter Mello 
32190221f91SCody Peter Mello 		err(EXIT_FAILURE, "Failed to wait on child");
32290221f91SCody Peter Mello 	}
32390221f91SCody Peter Mello 
32490221f91SCody Peter Mello 	if (WIFEXITED(childstat)) {
32590221f91SCody Peter Mello 		return (WEXITSTATUS(childstat));
32690221f91SCody Peter Mello 	} else if (WIFSIGNALED(childstat)) {
32790221f91SCody Peter Mello 		return (1);
32890221f91SCody Peter Mello 	} else {
32990221f91SCody Peter Mello 		abort();
33090221f91SCody Peter Mello 	}
33190221f91SCody Peter Mello }
33290221f91SCody Peter Mello 
33390221f91SCody Peter Mello 
33490221f91SCody Peter Mello static void
flock_cleanup_child(pid_t pid,int fds[])33590221f91SCody Peter Mello flock_cleanup_child(pid_t pid, int fds[])
33690221f91SCody Peter Mello {
33790221f91SCody Peter Mello 	(void) flock_wait(pid);
33890221f91SCody Peter Mello 	(void) close(fds[0]);
33990221f91SCody Peter Mello 	(void) close(fds[1]);
34090221f91SCody Peter Mello }
34190221f91SCody Peter Mello 
34290221f91SCody Peter Mello 
34390221f91SCody Peter Mello static void
flock_test_upgrade_downgrade(void)34490221f91SCody Peter Mello flock_test_upgrade_downgrade(void)
34590221f91SCody Peter Mello {
34690221f91SCody Peter Mello 	lockinfo_t afd1, afd2, afd3;
34790221f91SCody Peter Mello 	pid_t pid;
34890221f91SCody Peter Mello 	int fds[2];
34990221f91SCody Peter Mello 
35090221f91SCody Peter Mello 	VERIFY3S(flock_copyfil(&flock_fileA, &afd1), ==, 0);
35190221f91SCody Peter Mello 	VERIFY3S(flock_copyfil(&flock_fileA, &afd2), ==, 0);
35290221f91SCody Peter Mello 	VERIFY3S(flock_copyfil(&flock_fileA, &afd3), ==, 0);
35390221f91SCody Peter Mello 
35490221f91SCody Peter Mello 	flock_log("Acquiring shared locks 1, 2 and 3...");
35590221f91SCody Peter Mello 	VERIFY3S(flock(afd1.lf_fd, LOCK_SH), ==, 0);
35690221f91SCody Peter Mello 	VERIFY3S(flock(afd2.lf_fd, LOCK_SH), ==, 0);
35790221f91SCody Peter Mello 	VERIFY3S(flock(afd3.lf_fd, LOCK_SH), ==, 0);
35890221f91SCody Peter Mello 	assert_read_locked_by(&flock_fileA, -1);
35990221f91SCody Peter Mello 	flock_log(" ok\n");
36090221f91SCody Peter Mello 
36190221f91SCody Peter Mello 	flock_log("Upgrading lock 3 should fail w/ EWOULDBLOCK...");
36290221f91SCody Peter Mello 	VERIFY3S(flock(afd3.lf_fd, LOCK_EX|LOCK_NB), ==, -1);
36390221f91SCody Peter Mello 	VERIFY3U(errno, ==, EWOULDBLOCK);
36490221f91SCody Peter Mello 	assert_read_locked_by(&flock_fileA, -1);
36590221f91SCody Peter Mello 	flock_log(" ok\n");
36690221f91SCody Peter Mello 
36790221f91SCody Peter Mello 	flock_log("Upgrading 3 should succeed after releasing locks 1 & 2...");
36890221f91SCody Peter Mello 	VERIFY3S(flock(afd1.lf_fd, LOCK_UN), ==, 0);
36990221f91SCody Peter Mello 	VERIFY3S(flock(afd2.lf_fd, LOCK_UN), ==, 0);
37090221f91SCody Peter Mello 	VERIFY3S(flock(afd3.lf_fd, LOCK_EX), ==, 0);
37190221f91SCody Peter Mello 	assert_write_locked_by(&flock_fileA, -1);
37290221f91SCody Peter Mello 	flock_log(" ok\n");
37390221f91SCody Peter Mello 
37490221f91SCody Peter Mello 
37590221f91SCody Peter Mello 	flock_log("Starting up child, then downgrading lock 3 to shared...");
37690221f91SCody Peter Mello 	flock_run(LSTYLE_FLOCK, B_FALSE, &flock_fileA, &pid, fds);
37790221f91SCody Peter Mello 	VERIFY3_IMPL(flock_nodata(fds[0]), ==, B_TRUE, boolean_t);
37890221f91SCody Peter Mello 	VERIFY3S(flock(afd3.lf_fd, LOCK_SH), ==, 0);
37990221f91SCody Peter Mello 	flock_block(fds[0]);
38090221f91SCody Peter Mello 	assert_read_locked_by(&flock_fileA, -1);
38190221f91SCody Peter Mello 	flock_log(" ok\n");
38290221f91SCody Peter Mello 
38390221f91SCody Peter Mello 	flock_log("Releasing child and upgrading...");
38490221f91SCody Peter Mello 	flock_alert(fds[0]);
38590221f91SCody Peter Mello 	flock_cleanup_child(pid, fds);
38690221f91SCody Peter Mello 	assert_read_locked_by(&flock_fileA, -1);
38790221f91SCody Peter Mello 	VERIFY3S(flock(afd3.lf_fd, LOCK_EX), ==, 0);
38890221f91SCody Peter Mello 	assert_write_locked_by(&flock_fileA, -1);
38990221f91SCody Peter Mello 	flock_log(" ok\n");
39090221f91SCody Peter Mello 
39190221f91SCody Peter Mello 	flock_log("Releasing lock 3...");
39290221f91SCody Peter Mello 	VERIFY3S(flock(afd3.lf_fd, LOCK_UN), ==, 0);
39390221f91SCody Peter Mello 	flock_rminfo(&afd1);
39490221f91SCody Peter Mello 	flock_rminfo(&afd2);
39590221f91SCody Peter Mello 	flock_rminfo(&afd3);
39690221f91SCody Peter Mello 	assert_all_unlocked();
39790221f91SCody Peter Mello 	flock_log(" ok\n");
39890221f91SCody Peter Mello }
39990221f91SCody Peter Mello 
40090221f91SCody Peter Mello 
40190221f91SCody Peter Mello static void
flock_test_invalid(lockinfo_t * lf,int cmd,short l_type,short l_whence,off_t l_start,off_t l_len)40290221f91SCody Peter Mello flock_test_invalid(lockinfo_t *lf, int cmd, short l_type, short l_whence,
40390221f91SCody Peter Mello     off_t l_start, off_t l_len)
40490221f91SCody Peter Mello {
40590221f91SCody Peter Mello 	struct flock fl = {
40690221f91SCody Peter Mello 		.l_type = l_type,
40790221f91SCody Peter Mello 		.l_whence = l_whence,
40890221f91SCody Peter Mello 		.l_start = l_start,
40990221f91SCody Peter Mello 		.l_len = l_len
41090221f91SCody Peter Mello 	};
41190221f91SCody Peter Mello 
41290221f91SCody Peter Mello 	flock_log("fcntl(fd, %s, { %hd, %hd, %ld, %ld, ... })...",
41390221f91SCody Peter Mello 	    flock_cmdname(cmd), l_type, l_whence, l_start, l_len);
41490221f91SCody Peter Mello 	VERIFY3S(fcntl(lf->lf_fd, cmd, &fl), ==, -1);
41590221f91SCody Peter Mello 	VERIFY3U(errno, ==, EINVAL);
41690221f91SCody Peter Mello 	flock_log(" ok\n");
41790221f91SCody Peter Mello }
41890221f91SCody Peter Mello 
4199c7f1ae0SJerry Jelinek static void
flock_test_invalid64(lockinfo_t * lf,int cmd,short l_type,short l_whence,off_t l_start,off_t l_len)4209c7f1ae0SJerry Jelinek flock_test_invalid64(lockinfo_t *lf, int cmd, short l_type, short l_whence,
4219c7f1ae0SJerry Jelinek     off_t l_start, off_t l_len)
4229c7f1ae0SJerry Jelinek {
4239c7f1ae0SJerry Jelinek 	struct flock64 fl = {
4249c7f1ae0SJerry Jelinek 		.l_type = l_type,
4259c7f1ae0SJerry Jelinek 		.l_whence = l_whence,
4269c7f1ae0SJerry Jelinek 		.l_start = l_start,
4279c7f1ae0SJerry Jelinek 		.l_len = l_len
4289c7f1ae0SJerry Jelinek 	};
4299c7f1ae0SJerry Jelinek 
4309c7f1ae0SJerry Jelinek 	flock_log("fcntl(fd, %s, { %hd, %hd, %ld, %ld, ... })...",
4319c7f1ae0SJerry Jelinek 	    flock_cmdname(cmd), l_type, l_whence, l_start, l_len);
4329c7f1ae0SJerry Jelinek 	VERIFY3S(fcntl(lf->lf_fd, cmd, &fl), ==, -1);
4339c7f1ae0SJerry Jelinek 	VERIFY3U(errno, ==, EINVAL);
4349c7f1ae0SJerry Jelinek 	flock_log(" ok\n");
4359c7f1ae0SJerry Jelinek }
43690221f91SCody Peter Mello 
43790221f91SCody Peter Mello static void
flock_test_exclusive(lock_style_t styleA,lock_style_t styleB,lockinfo_t * lock1,lockinfo_t * lock2,boolean_t kill_firstborn)43890221f91SCody Peter Mello flock_test_exclusive(lock_style_t styleA, lock_style_t styleB,
43990221f91SCody Peter Mello     lockinfo_t *lock1, lockinfo_t *lock2, boolean_t kill_firstborn)
44090221f91SCody Peter Mello {
44190221f91SCody Peter Mello 	pid_t pidA, pidB;
44290221f91SCody Peter Mello 	int fdsA[2], fdsB[2];
44390221f91SCody Peter Mello 
44490221f91SCody Peter Mello 	flock_log("Running %s + %s tests (%s)...",
44590221f91SCody Peter Mello 	    flock_stylename(styleA), flock_stylename(styleB),
44690221f91SCody Peter Mello 	    kill_firstborn ? "kill child" : "child exits");
44790221f91SCody Peter Mello 
44890221f91SCody Peter Mello 	/* Create child, and wait for it to acquire the lock */
44990221f91SCody Peter Mello 	flock_run(styleA, B_TRUE, lock1, &pidA, fdsA);
45090221f91SCody Peter Mello 	flock_block(fdsA[0]);
45190221f91SCody Peter Mello 
45290221f91SCody Peter Mello 	/* Create second child, which shouldn't acquire & signal */
45390221f91SCody Peter Mello 	flock_run(styleB, B_TRUE, lock1, &pidB, fdsB);
45490221f91SCody Peter Mello 	VERIFY3_IMPL(flock_nodata(fdsB[0]), ==, B_TRUE, boolean_t);
45590221f91SCody Peter Mello 
45690221f91SCody Peter Mello 	/* lock1 is blocked for reading and writing */
45790221f91SCody Peter Mello 	assert_write_locked_by(lock1, styleA == LSTYLE_POSIX ? pidA : -1);
45890221f91SCody Peter Mello 	assert_unlocked(lock2);
45990221f91SCody Peter Mello 
46090221f91SCody Peter Mello 	/* Tell pidA to exit */
46190221f91SCody Peter Mello 	if (kill_firstborn) {
46290221f91SCody Peter Mello 		flock_kill(pidA);
46390221f91SCody Peter Mello 	} else {
46490221f91SCody Peter Mello 		flock_alert(fdsA[0]);
46590221f91SCody Peter Mello 	}
46690221f91SCody Peter Mello 	flock_cleanup_child(pidA, fdsA);
46790221f91SCody Peter Mello 
46890221f91SCody Peter Mello 	/* Wait for pidB to signal us */
46990221f91SCody Peter Mello 	flock_block(fdsB[0]);
47090221f91SCody Peter Mello 
47190221f91SCody Peter Mello 	/* lock1 is blocked for reading and writing */
47290221f91SCody Peter Mello 	assert_write_locked_by(lock1, styleB == LSTYLE_POSIX ? pidB : -1);
47390221f91SCody Peter Mello 	assert_unlocked(lock2);
47490221f91SCody Peter Mello 
47590221f91SCody Peter Mello 	/* Tell pidB to exit */
47690221f91SCody Peter Mello 	flock_alert(fdsB[0]);
47790221f91SCody Peter Mello 
47890221f91SCody Peter Mello 	flock_cleanup_child(pidB, fdsB);
47990221f91SCody Peter Mello 
48090221f91SCody Peter Mello 	/*
48190221f91SCody Peter Mello 	 * Tests after child has released lock
48290221f91SCody Peter Mello 	 */
48390221f91SCody Peter Mello 	assert_all_unlocked();
48490221f91SCody Peter Mello 
48590221f91SCody Peter Mello 	flock_log(" ok\n");
48690221f91SCody Peter Mello }
48790221f91SCody Peter Mello 
48890221f91SCody Peter Mello 
48990221f91SCody Peter Mello static void
flock_test_shared(lock_style_t styleA,lock_style_t styleB,lockinfo_t * lock1,lockinfo_t * lock2,boolean_t kill_firstborn)49090221f91SCody Peter Mello flock_test_shared(lock_style_t styleA, lock_style_t styleB,
49190221f91SCody Peter Mello     lockinfo_t *lock1, lockinfo_t *lock2, boolean_t kill_firstborn)
49290221f91SCody Peter Mello {
49390221f91SCody Peter Mello 	pid_t pidA, pidB;
49490221f91SCody Peter Mello 	int fdsA[2], fdsB[2];
49590221f91SCody Peter Mello 
49690221f91SCody Peter Mello 	flock_log("Running %s + %s tests (%s)...",
49790221f91SCody Peter Mello 	    flock_stylename(styleA), flock_stylename(styleB),
49890221f91SCody Peter Mello 	    kill_firstborn ? "kill child" : "child exits");
49990221f91SCody Peter Mello 
50090221f91SCody Peter Mello 	/* Create children, and wait for it to acquire the lock */
50190221f91SCody Peter Mello 	flock_run(styleB, B_FALSE, lock1, &pidB, fdsB);
50290221f91SCody Peter Mello 	flock_block(fdsB[0]);
50390221f91SCody Peter Mello 	flock_run(styleA, B_FALSE, lock1, &pidA, fdsA);
50490221f91SCody Peter Mello 	flock_block(fdsA[0]);
50590221f91SCody Peter Mello 
50690221f91SCody Peter Mello 	/* testfileA is only blocked for writing */
50790221f91SCody Peter Mello 	assert_read_locked_by(lock1, styleA == LSTYLE_POSIX ? pidA : -1);
50890221f91SCody Peter Mello 	assert_unlocked(lock2);
50990221f91SCody Peter Mello 
51090221f91SCody Peter Mello 	/* Tell pidA to exit */
51190221f91SCody Peter Mello 	if (kill_firstborn) {
51290221f91SCody Peter Mello 		flock_kill(pidA);
51390221f91SCody Peter Mello 	} else {
51490221f91SCody Peter Mello 		flock_alert(fdsA[0]);
51590221f91SCody Peter Mello 	}
51690221f91SCody Peter Mello 	flock_cleanup_child(pidA, fdsA);
51790221f91SCody Peter Mello 
51890221f91SCody Peter Mello 	/* testfileA is still blocked for writing by pidB */
51990221f91SCody Peter Mello 	assert_read_locked_by(lock1, styleB == LSTYLE_POSIX ? pidB : -1);
52090221f91SCody Peter Mello 	assert_unlocked(lock2);
52190221f91SCody Peter Mello 
52290221f91SCody Peter Mello 	/* Tell pidB to exit */
52390221f91SCody Peter Mello 	flock_alert(fdsB[0]);
52490221f91SCody Peter Mello 	flock_cleanup_child(pidB, fdsB);
52590221f91SCody Peter Mello 
52690221f91SCody Peter Mello 	assert_all_unlocked();
52790221f91SCody Peter Mello 
52890221f91SCody Peter Mello 	flock_log(" ok\n");
52990221f91SCody Peter Mello }
53090221f91SCody Peter Mello 
53190221f91SCody Peter Mello 
53290221f91SCody Peter Mello static void
flock_test_ofd_sameproc(void)53390221f91SCody Peter Mello flock_test_ofd_sameproc(void)
53490221f91SCody Peter Mello {
53590221f91SCody Peter Mello 	lockinfo_t afd1, afd2, afd3;
53690221f91SCody Peter Mello 
53790221f91SCody Peter Mello 	VERIFY3S(flock_copyfil(&flock_fileA, &afd1), ==, 0);
53890221f91SCody Peter Mello 	VERIFY3S(flock_copyfil(&flock_fileA, &afd2), ==, 0);
53990221f91SCody Peter Mello 	VERIFY3S(flock_copyfil(&flock_fileA, &afd3), ==, 0);
54090221f91SCody Peter Mello 
54190221f91SCody Peter Mello 	flock_log("Acquiring first two shared locks...");
54290221f91SCody Peter Mello 	VERIFY3S(flock(afd1.lf_fd, LOCK_SH), ==, 0);
54390221f91SCody Peter Mello 	VERIFY3S(flock(afd2.lf_fd, LOCK_SH), ==, 0);
54490221f91SCody Peter Mello 	assert_read_locked_by(&flock_fileA, -1);
54590221f91SCody Peter Mello 	flock_log(" ok\n");
54690221f91SCody Peter Mello 
54790221f91SCody Peter Mello 	flock_log("Acquiring an exclusive lock should fail w/ EWOULDBLOCK...");
54890221f91SCody Peter Mello 	VERIFY3S(flock(afd3.lf_fd, LOCK_EX|LOCK_NB), ==, -1);
54990221f91SCody Peter Mello 	VERIFY3U(errno, ==, EWOULDBLOCK);
55090221f91SCody Peter Mello 	flock_log(" ok\n");
55190221f91SCody Peter Mello 
55290221f91SCody Peter Mello 	flock_log("Releasing to acquire an exclusive lock...");
55390221f91SCody Peter Mello 	VERIFY3S(flock(afd1.lf_fd, LOCK_UN), ==, 0);
55490221f91SCody Peter Mello 	VERIFY3S(flock(afd2.lf_fd, LOCK_UN), ==, 0);
55590221f91SCody Peter Mello 	flock_log(" ok\n");
55690221f91SCody Peter Mello 
55790221f91SCody Peter Mello 	flock_log("Acquiring an exclusive lock...");
55890221f91SCody Peter Mello 	VERIFY3S(flock(afd3.lf_fd, LOCK_EX), ==, 0);
55990221f91SCody Peter Mello 	assert_write_locked_by(&flock_fileA, -1);
56090221f91SCody Peter Mello 	flock_log(" ok\n");
56190221f91SCody Peter Mello 
56290221f91SCody Peter Mello 	flock_log("Acquiring a shared lock should fail w/ EWOULDBLOCK...");
56390221f91SCody Peter Mello 	VERIFY3S(flock(afd1.lf_fd, LOCK_EX|LOCK_NB), ==, -1);
56490221f91SCody Peter Mello 	VERIFY3U(errno, ==, EWOULDBLOCK);
56590221f91SCody Peter Mello 	VERIFY3S(flock(afd2.lf_fd, LOCK_EX|LOCK_NB), ==, -1);
56690221f91SCody Peter Mello 	VERIFY3U(errno, ==, EWOULDBLOCK);
56790221f91SCody Peter Mello 	flock_log(" ok\n");
56890221f91SCody Peter Mello 
56990221f91SCody Peter Mello 	flock_log("Releasing exclusive lock...");
57090221f91SCody Peter Mello 	VERIFY3S(flock(afd3.lf_fd, LOCK_UN), ==, 0);
57190221f91SCody Peter Mello 	assert_all_unlocked();
57290221f91SCody Peter Mello 	flock_log(" ok\n");
57390221f91SCody Peter Mello 
57490221f91SCody Peter Mello 	flock_rminfo(&afd1);
57590221f91SCody Peter Mello 	flock_rminfo(&afd2);
57690221f91SCody Peter Mello 	flock_rminfo(&afd3);
57790221f91SCody Peter Mello }
57890221f91SCody Peter Mello 
57990221f91SCody Peter Mello 
58090221f91SCody Peter Mello static void
flock_runtests(void)58190221f91SCody Peter Mello flock_runtests(void)
58290221f91SCody Peter Mello {
58390221f91SCody Peter Mello 	lock_style_t first, second;
58490221f91SCody Peter Mello 	int i;
58590221f91SCody Peter Mello 
58690221f91SCody Peter Mello 	flock_log("# Exclusive lock tests\n");
58790221f91SCody Peter Mello 	for (first = (lock_style_t)0; first < LSTYLE_LAST; first++) {
58890221f91SCody Peter Mello 		for (second = (lock_style_t)0; second < LSTYLE_LAST; second++) {
58990221f91SCody Peter Mello 			flock_test_exclusive(first, second,
59090221f91SCody Peter Mello 			    &flock_fileA, &flock_fileB, B_TRUE);
59190221f91SCody Peter Mello 			flock_test_exclusive(first, second,
59290221f91SCody Peter Mello 			    &flock_fileA, &flock_fileB, B_FALSE);
59390221f91SCody Peter Mello 		}
59490221f91SCody Peter Mello 	}
59590221f91SCody Peter Mello 
59690221f91SCody Peter Mello 	flock_log("# Shared lock tests\n");
59790221f91SCody Peter Mello 	for (first = (lock_style_t)0; first < LSTYLE_LAST; first++) {
59890221f91SCody Peter Mello 		for (second = (lock_style_t)0; second < LSTYLE_LAST; second++) {
59990221f91SCody Peter Mello 			flock_test_shared(first, second,
60090221f91SCody Peter Mello 			    &flock_fileA, &flock_fileB, B_TRUE);
60190221f91SCody Peter Mello 			flock_test_shared(first, second,
60290221f91SCody Peter Mello 			    &flock_fileA, &flock_fileB, B_FALSE);
60390221f91SCody Peter Mello 		}
60490221f91SCody Peter Mello 	}
60590221f91SCody Peter Mello 
60690221f91SCody Peter Mello 	flock_log("# flock(3C) directory lock tests\n");
60790221f91SCody Peter Mello 	flock_test_exclusive(LSTYLE_FLOCK, LSTYLE_FLOCK,
60890221f91SCody Peter Mello 	    &flock_dirA, &flock_dirB, B_TRUE);
60990221f91SCody Peter Mello 	flock_test_exclusive(LSTYLE_FLOCK, LSTYLE_FLOCK,
61090221f91SCody Peter Mello 	    &flock_dirA, &flock_dirB, B_FALSE);
61190221f91SCody Peter Mello 	flock_test_shared(LSTYLE_FLOCK, LSTYLE_FLOCK,
61290221f91SCody Peter Mello 	    &flock_dirA, &flock_dirB, B_TRUE);
61390221f91SCody Peter Mello 	flock_test_shared(LSTYLE_FLOCK, LSTYLE_FLOCK,
61490221f91SCody Peter Mello 	    &flock_dirA, &flock_dirB, B_FALSE);
61590221f91SCody Peter Mello 
61690221f91SCody Peter Mello 
61790221f91SCody Peter Mello 	flock_log("# Invalid fcntl(2) parameters tests\n");
61890221f91SCody Peter Mello 	for (i = 0; i < sizeof (cmds) / sizeof (short); i++) {
61990221f91SCody Peter Mello 		flock_test_invalid(&flock_fileA, cmds[i], 200, 0, 0, 0);
62090221f91SCody Peter Mello 		flock_test_invalid(&flock_fileA, cmds[i], -1, 0, 0, 0);
62190221f91SCody Peter Mello 	}
62290221f91SCody Peter Mello 	for (i = 3; i < sizeof (cmds) / sizeof (short); i++) {
62390221f91SCody Peter Mello 		flock_test_invalid(&flock_fileA, cmds[i], F_WRLCK, 1, 0, 0);
62490221f91SCody Peter Mello 		flock_test_invalid(&flock_fileA, cmds[i], F_WRLCK, 0, 1, 0);
62590221f91SCody Peter Mello 		flock_test_invalid(&flock_fileA, cmds[i], F_WRLCK, 0, 0, 1);
62690221f91SCody Peter Mello 	}
6279c7f1ae0SJerry Jelinek 	for (i = 0; i < sizeof (cmds64) / sizeof (short); i++) {
6289c7f1ae0SJerry Jelinek 		flock_test_invalid64(&flock_fileA, cmds64[i], F_WRLCK, 1, 0, 0);
6299c7f1ae0SJerry Jelinek 		flock_test_invalid64(&flock_fileA, cmds64[i], F_WRLCK, 0, 1, 0);
6309c7f1ae0SJerry Jelinek 		flock_test_invalid64(&flock_fileA, cmds64[i], F_WRLCK, 0, 0, 1);
6319c7f1ae0SJerry Jelinek 	}
63290221f91SCody Peter Mello 
63390221f91SCody Peter Mello 	flock_log("# Testing that multiple OFD locks work in a process\n");
63490221f91SCody Peter Mello 	flock_test_ofd_sameproc();
63590221f91SCody Peter Mello 
63690221f91SCody Peter Mello 	flock_log("# Testing flock(3C) upgrade/downgrade tests\n");
63790221f91SCody Peter Mello 	flock_test_upgrade_downgrade();
63890221f91SCody Peter Mello }
63990221f91SCody Peter Mello 
64090221f91SCody Peter Mello 
64190221f91SCody Peter Mello int
main(int argc,char * argv[])64290221f91SCody Peter Mello main(int argc, char *argv[])
64390221f91SCody Peter Mello {
64490221f91SCody Peter Mello 	char *basestr, *suffix, *dirstr, *dirpath;
64590221f91SCody Peter Mello 	pid_t testrunner;
64690221f91SCody Peter Mello 	int exval;
64790221f91SCody Peter Mello 
64890221f91SCody Peter Mello 	LOG = B_TRUE;
64990221f91SCody Peter Mello 
65090221f91SCody Peter Mello 	if (argc < 1) {
65190221f91SCody Peter Mello 		errx(EXIT_FAILURE, "Can't find program name!");
65290221f91SCody Peter Mello 	}
65390221f91SCody Peter Mello 
65490221f91SCody Peter Mello 	dirstr = strdup(argv[0]);
65590221f91SCody Peter Mello 	dirpath = dirname(dirstr);
65690221f91SCody Peter Mello 	basestr = strdup(argv[0]);
65790221f91SCody Peter Mello 	suffix = basename(basestr);
65890221f91SCody Peter Mello 
65990221f91SCody Peter Mello 	while (*suffix != '.' && *suffix != '\0') {
66090221f91SCody Peter Mello 		suffix += 1;
66190221f91SCody Peter Mello 	}
66290221f91SCody Peter Mello 
66390221f91SCody Peter Mello 	if (asprintf(&acqprog, "%s/acquire-lock%s", dirpath, suffix) < 0) {
66490221f91SCody Peter Mello 		errx(EXIT_FAILURE,
66590221f91SCody Peter Mello 		    "Can't generate lock acquisition program name!");
66690221f91SCody Peter Mello 	}
66790221f91SCody Peter Mello 
66890221f91SCody Peter Mello 	if (access(acqprog, X_OK) != 0) {
66990221f91SCody Peter Mello 		err(EXIT_FAILURE,
67090221f91SCody Peter Mello 		    "Can't run lock acquisition program %s", acqprog);
67190221f91SCody Peter Mello 	}
67290221f91SCody Peter Mello 
67390221f91SCody Peter Mello 	/* Create several lockfiles for testing */
67490221f91SCody Peter Mello 	if (flock_mkfil(&flock_fileA) != 0 ||
67590221f91SCody Peter Mello 	    flock_mkfil(&flock_fileB) != 0 ||
67690221f91SCody Peter Mello 	    flock_mkdir(&flock_dirA) != 0 ||
67790221f91SCody Peter Mello 	    flock_mkdir(&flock_dirB) != 0) {
67890221f91SCody Peter Mello 		exval = 1;
67990221f91SCody Peter Mello 		goto cleanup;
68090221f91SCody Peter Mello 	}
68190221f91SCody Peter Mello 
68290221f91SCody Peter Mello 	/*
68390221f91SCody Peter Mello 	 * We run the tests in a child process so that when tests fail
68490221f91SCody Peter Mello 	 * we can still clean up our temporary files.
68590221f91SCody Peter Mello 	 */
68690221f91SCody Peter Mello 	testrunner = fork();
68790221f91SCody Peter Mello 	if (testrunner == (pid_t)-1) {
68890221f91SCody Peter Mello 		err(EXIT_FAILURE, "Unable to fork to run tests");
68990221f91SCody Peter Mello 	} else if (testrunner == (pid_t)0) {
69090221f91SCody Peter Mello 		flock_runtests();
69190221f91SCody Peter Mello 		return (0);
69290221f91SCody Peter Mello 	}
69390221f91SCody Peter Mello 
69490221f91SCody Peter Mello 	exval = flock_wait(testrunner);
69590221f91SCody Peter Mello 
69690221f91SCody Peter Mello cleanup:
69790221f91SCody Peter Mello 	free(basestr);
69890221f91SCody Peter Mello 	free(dirstr);
69990221f91SCody Peter Mello 	flock_rminfo(&flock_fileA);
70090221f91SCody Peter Mello 	flock_rminfo(&flock_fileB);
70190221f91SCody Peter Mello 	flock_rminfo(&flock_dirA);
70290221f91SCody Peter Mello 	flock_rminfo(&flock_dirB);
70390221f91SCody Peter Mello 	return (exval);
70490221f91SCody Peter Mello }