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 
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
flock_kill(pid_t pid)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
flock_fcntl(lockinfo_t * lf,int cmd,struct flock * fl)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
assert_write_locked_by(lockinfo_t * lf,pid_t pid)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
assert_read_locked_by(lockinfo_t * lf,pid_t pid)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
assert_unlocked(lockinfo_t * lf)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
assert_all_unlocked(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
flock_copyfil(lockinfo_t * src,lockinfo_t * dst)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
flock_mkfil(lockinfo_t * lf)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
flock_mkdir(lockinfo_t * lf)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
flock_rminfo(lockinfo_t * lf)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
flock_run(lock_style_t style,boolean_t is_exclusive,lockinfo_t * lf,pid_t * pid,int fds[])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
flock_wait(pid_t pid)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 	}
331 }
332 
333 
334 static void
flock_cleanup_child(pid_t pid,int fds[])335 flock_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 
343 static void
flock_test_upgrade_downgrade(void)344 flock_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 
401 static void
flock_test_invalid(lockinfo_t * lf,int cmd,short l_type,short l_whence,off_t l_start,off_t l_len)402 flock_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 
419 static void
flock_test_invalid64(lockinfo_t * lf,int cmd,short l_type,short l_whence,off_t l_start,off_t l_len)420 flock_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 
437 static void
flock_test_exclusive(lock_style_t styleA,lock_style_t styleB,lockinfo_t * lock1,lockinfo_t * lock2,boolean_t kill_firstborn)438 flock_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 
489 static void
flock_test_shared(lock_style_t styleA,lock_style_t styleB,lockinfo_t * lock1,lockinfo_t * lock2,boolean_t kill_firstborn)490 flock_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 
532 static void
flock_test_ofd_sameproc(void)533 flock_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 
580 static void
flock_runtests(void)581 flock_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 
641 int
main(int argc,char * argv[])642 main(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 
696 cleanup:
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