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*9c7f1ae0SJerry Jelinek * Copyright 2018 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); 63*9c7f1ae0SJerry Jelinek static void flock_test_invalid64(lockinfo_t *, int, short, short, 64*9c7f1ae0SJerry 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 85*9c7f1ae0SJerry Jelinek static short cmds64[3] = { 86*9c7f1ae0SJerry Jelinek F_OFD_SETLK64, F_OFD_SETLKW64, F_OFD_GETLK64 87*9c7f1ae0SJerry Jelinek }; 88*9c7f1ae0SJerry Jelinek 8990221f91SCody Peter Mello 9090221f91SCody Peter Mello static void 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 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 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 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 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 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 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 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 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 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 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 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 return (1); 33190221f91SCody Peter Mello } 33290221f91SCody Peter Mello } 33390221f91SCody Peter Mello 33490221f91SCody Peter Mello 33590221f91SCody Peter Mello static void 33690221f91SCody Peter Mello flock_cleanup_child(pid_t pid, int fds[]) 33790221f91SCody Peter Mello { 33890221f91SCody Peter Mello (void) flock_wait(pid); 33990221f91SCody Peter Mello (void) close(fds[0]); 34090221f91SCody Peter Mello (void) close(fds[1]); 34190221f91SCody Peter Mello } 34290221f91SCody Peter Mello 34390221f91SCody Peter Mello 34490221f91SCody Peter Mello static void 34590221f91SCody Peter Mello flock_test_upgrade_downgrade(void) 34690221f91SCody Peter Mello { 34790221f91SCody Peter Mello lockinfo_t afd1, afd2, afd3; 34890221f91SCody Peter Mello pid_t pid; 34990221f91SCody Peter Mello int fds[2]; 35090221f91SCody Peter Mello 35190221f91SCody Peter Mello VERIFY3S(flock_copyfil(&flock_fileA, &afd1), ==, 0); 35290221f91SCody Peter Mello VERIFY3S(flock_copyfil(&flock_fileA, &afd2), ==, 0); 35390221f91SCody Peter Mello VERIFY3S(flock_copyfil(&flock_fileA, &afd3), ==, 0); 35490221f91SCody Peter Mello 35590221f91SCody Peter Mello flock_log("Acquiring shared locks 1, 2 and 3..."); 35690221f91SCody Peter Mello VERIFY3S(flock(afd1.lf_fd, LOCK_SH), ==, 0); 35790221f91SCody Peter Mello VERIFY3S(flock(afd2.lf_fd, LOCK_SH), ==, 0); 35890221f91SCody Peter Mello VERIFY3S(flock(afd3.lf_fd, LOCK_SH), ==, 0); 35990221f91SCody Peter Mello assert_read_locked_by(&flock_fileA, -1); 36090221f91SCody Peter Mello flock_log(" ok\n"); 36190221f91SCody Peter Mello 36290221f91SCody Peter Mello flock_log("Upgrading lock 3 should fail w/ EWOULDBLOCK..."); 36390221f91SCody Peter Mello VERIFY3S(flock(afd3.lf_fd, LOCK_EX|LOCK_NB), ==, -1); 36490221f91SCody Peter Mello VERIFY3U(errno, ==, EWOULDBLOCK); 36590221f91SCody Peter Mello assert_read_locked_by(&flock_fileA, -1); 36690221f91SCody Peter Mello flock_log(" ok\n"); 36790221f91SCody Peter Mello 36890221f91SCody Peter Mello flock_log("Upgrading 3 should succeed after releasing locks 1 & 2..."); 36990221f91SCody Peter Mello VERIFY3S(flock(afd1.lf_fd, LOCK_UN), ==, 0); 37090221f91SCody Peter Mello VERIFY3S(flock(afd2.lf_fd, LOCK_UN), ==, 0); 37190221f91SCody Peter Mello VERIFY3S(flock(afd3.lf_fd, LOCK_EX), ==, 0); 37290221f91SCody Peter Mello assert_write_locked_by(&flock_fileA, -1); 37390221f91SCody Peter Mello flock_log(" ok\n"); 37490221f91SCody Peter Mello 37590221f91SCody Peter Mello 37690221f91SCody Peter Mello flock_log("Starting up child, then downgrading lock 3 to shared..."); 37790221f91SCody Peter Mello flock_run(LSTYLE_FLOCK, B_FALSE, &flock_fileA, &pid, fds); 37890221f91SCody Peter Mello VERIFY3_IMPL(flock_nodata(fds[0]), ==, B_TRUE, boolean_t); 37990221f91SCody Peter Mello VERIFY3S(flock(afd3.lf_fd, LOCK_SH), ==, 0); 38090221f91SCody Peter Mello flock_block(fds[0]); 38190221f91SCody Peter Mello assert_read_locked_by(&flock_fileA, -1); 38290221f91SCody Peter Mello flock_log(" ok\n"); 38390221f91SCody Peter Mello 38490221f91SCody Peter Mello flock_log("Releasing child and upgrading..."); 38590221f91SCody Peter Mello flock_alert(fds[0]); 38690221f91SCody Peter Mello flock_cleanup_child(pid, fds); 38790221f91SCody Peter Mello assert_read_locked_by(&flock_fileA, -1); 38890221f91SCody Peter Mello VERIFY3S(flock(afd3.lf_fd, LOCK_EX), ==, 0); 38990221f91SCody Peter Mello assert_write_locked_by(&flock_fileA, -1); 39090221f91SCody Peter Mello flock_log(" ok\n"); 39190221f91SCody Peter Mello 39290221f91SCody Peter Mello flock_log("Releasing lock 3..."); 39390221f91SCody Peter Mello VERIFY3S(flock(afd3.lf_fd, LOCK_UN), ==, 0); 39490221f91SCody Peter Mello flock_rminfo(&afd1); 39590221f91SCody Peter Mello flock_rminfo(&afd2); 39690221f91SCody Peter Mello flock_rminfo(&afd3); 39790221f91SCody Peter Mello assert_all_unlocked(); 39890221f91SCody Peter Mello flock_log(" ok\n"); 39990221f91SCody Peter Mello } 40090221f91SCody Peter Mello 40190221f91SCody Peter Mello 40290221f91SCody Peter Mello static void 40390221f91SCody Peter Mello flock_test_invalid(lockinfo_t *lf, int cmd, short l_type, short l_whence, 40490221f91SCody Peter Mello off_t l_start, off_t l_len) 40590221f91SCody Peter Mello { 40690221f91SCody Peter Mello struct flock fl = { 40790221f91SCody Peter Mello .l_type = l_type, 40890221f91SCody Peter Mello .l_whence = l_whence, 40990221f91SCody Peter Mello .l_start = l_start, 41090221f91SCody Peter Mello .l_len = l_len 41190221f91SCody Peter Mello }; 41290221f91SCody Peter Mello 41390221f91SCody Peter Mello flock_log("fcntl(fd, %s, { %hd, %hd, %ld, %ld, ... })...", 41490221f91SCody Peter Mello flock_cmdname(cmd), l_type, l_whence, l_start, l_len); 41590221f91SCody Peter Mello VERIFY3S(fcntl(lf->lf_fd, cmd, &fl), ==, -1); 41690221f91SCody Peter Mello VERIFY3U(errno, ==, EINVAL); 41790221f91SCody Peter Mello flock_log(" ok\n"); 41890221f91SCody Peter Mello } 41990221f91SCody Peter Mello 420*9c7f1ae0SJerry Jelinek static void 421*9c7f1ae0SJerry Jelinek flock_test_invalid64(lockinfo_t *lf, int cmd, short l_type, short l_whence, 422*9c7f1ae0SJerry Jelinek off_t l_start, off_t l_len) 423*9c7f1ae0SJerry Jelinek { 424*9c7f1ae0SJerry Jelinek struct flock64 fl = { 425*9c7f1ae0SJerry Jelinek .l_type = l_type, 426*9c7f1ae0SJerry Jelinek .l_whence = l_whence, 427*9c7f1ae0SJerry Jelinek .l_start = l_start, 428*9c7f1ae0SJerry Jelinek .l_len = l_len 429*9c7f1ae0SJerry Jelinek }; 430*9c7f1ae0SJerry Jelinek 431*9c7f1ae0SJerry Jelinek flock_log("fcntl(fd, %s, { %hd, %hd, %ld, %ld, ... })...", 432*9c7f1ae0SJerry Jelinek flock_cmdname(cmd), l_type, l_whence, l_start, l_len); 433*9c7f1ae0SJerry Jelinek VERIFY3S(fcntl(lf->lf_fd, cmd, &fl), ==, -1); 434*9c7f1ae0SJerry Jelinek VERIFY3U(errno, ==, EINVAL); 435*9c7f1ae0SJerry Jelinek flock_log(" ok\n"); 436*9c7f1ae0SJerry Jelinek } 43790221f91SCody Peter Mello 43890221f91SCody Peter Mello static void 43990221f91SCody Peter Mello flock_test_exclusive(lock_style_t styleA, lock_style_t styleB, 44090221f91SCody Peter Mello lockinfo_t *lock1, lockinfo_t *lock2, boolean_t kill_firstborn) 44190221f91SCody Peter Mello { 44290221f91SCody Peter Mello pid_t pidA, pidB; 44390221f91SCody Peter Mello int fdsA[2], fdsB[2]; 44490221f91SCody Peter Mello 44590221f91SCody Peter Mello flock_log("Running %s + %s tests (%s)...", 44690221f91SCody Peter Mello flock_stylename(styleA), flock_stylename(styleB), 44790221f91SCody Peter Mello kill_firstborn ? "kill child" : "child exits"); 44890221f91SCody Peter Mello 44990221f91SCody Peter Mello /* Create child, and wait for it to acquire the lock */ 45090221f91SCody Peter Mello flock_run(styleA, B_TRUE, lock1, &pidA, fdsA); 45190221f91SCody Peter Mello flock_block(fdsA[0]); 45290221f91SCody Peter Mello 45390221f91SCody Peter Mello /* Create second child, which shouldn't acquire & signal */ 45490221f91SCody Peter Mello flock_run(styleB, B_TRUE, lock1, &pidB, fdsB); 45590221f91SCody Peter Mello VERIFY3_IMPL(flock_nodata(fdsB[0]), ==, B_TRUE, boolean_t); 45690221f91SCody Peter Mello 45790221f91SCody Peter Mello /* lock1 is blocked for reading and writing */ 45890221f91SCody Peter Mello assert_write_locked_by(lock1, styleA == LSTYLE_POSIX ? pidA : -1); 45990221f91SCody Peter Mello assert_unlocked(lock2); 46090221f91SCody Peter Mello 46190221f91SCody Peter Mello /* Tell pidA to exit */ 46290221f91SCody Peter Mello if (kill_firstborn) { 46390221f91SCody Peter Mello flock_kill(pidA); 46490221f91SCody Peter Mello } else { 46590221f91SCody Peter Mello flock_alert(fdsA[0]); 46690221f91SCody Peter Mello } 46790221f91SCody Peter Mello flock_cleanup_child(pidA, fdsA); 46890221f91SCody Peter Mello 46990221f91SCody Peter Mello /* Wait for pidB to signal us */ 47090221f91SCody Peter Mello flock_block(fdsB[0]); 47190221f91SCody Peter Mello 47290221f91SCody Peter Mello /* lock1 is blocked for reading and writing */ 47390221f91SCody Peter Mello assert_write_locked_by(lock1, styleB == LSTYLE_POSIX ? pidB : -1); 47490221f91SCody Peter Mello assert_unlocked(lock2); 47590221f91SCody Peter Mello 47690221f91SCody Peter Mello /* Tell pidB to exit */ 47790221f91SCody Peter Mello flock_alert(fdsB[0]); 47890221f91SCody Peter Mello 47990221f91SCody Peter Mello flock_cleanup_child(pidB, fdsB); 48090221f91SCody Peter Mello 48190221f91SCody Peter Mello /* 48290221f91SCody Peter Mello * Tests after child has released lock 48390221f91SCody Peter Mello */ 48490221f91SCody Peter Mello assert_all_unlocked(); 48590221f91SCody Peter Mello 48690221f91SCody Peter Mello flock_log(" ok\n"); 48790221f91SCody Peter Mello } 48890221f91SCody Peter Mello 48990221f91SCody Peter Mello 49090221f91SCody Peter Mello static void 49190221f91SCody Peter Mello flock_test_shared(lock_style_t styleA, lock_style_t styleB, 49290221f91SCody Peter Mello lockinfo_t *lock1, lockinfo_t *lock2, boolean_t kill_firstborn) 49390221f91SCody Peter Mello { 49490221f91SCody Peter Mello pid_t pidA, pidB; 49590221f91SCody Peter Mello int fdsA[2], fdsB[2]; 49690221f91SCody Peter Mello 49790221f91SCody Peter Mello flock_log("Running %s + %s tests (%s)...", 49890221f91SCody Peter Mello flock_stylename(styleA), flock_stylename(styleB), 49990221f91SCody Peter Mello kill_firstborn ? "kill child" : "child exits"); 50090221f91SCody Peter Mello 50190221f91SCody Peter Mello /* Create children, and wait for it to acquire the lock */ 50290221f91SCody Peter Mello flock_run(styleB, B_FALSE, lock1, &pidB, fdsB); 50390221f91SCody Peter Mello flock_block(fdsB[0]); 50490221f91SCody Peter Mello flock_run(styleA, B_FALSE, lock1, &pidA, fdsA); 50590221f91SCody Peter Mello flock_block(fdsA[0]); 50690221f91SCody Peter Mello 50790221f91SCody Peter Mello /* testfileA is only blocked for writing */ 50890221f91SCody Peter Mello assert_read_locked_by(lock1, styleA == LSTYLE_POSIX ? pidA : -1); 50990221f91SCody Peter Mello assert_unlocked(lock2); 51090221f91SCody Peter Mello 51190221f91SCody Peter Mello /* Tell pidA to exit */ 51290221f91SCody Peter Mello if (kill_firstborn) { 51390221f91SCody Peter Mello flock_kill(pidA); 51490221f91SCody Peter Mello } else { 51590221f91SCody Peter Mello flock_alert(fdsA[0]); 51690221f91SCody Peter Mello } 51790221f91SCody Peter Mello flock_cleanup_child(pidA, fdsA); 51890221f91SCody Peter Mello 51990221f91SCody Peter Mello /* testfileA is still blocked for writing by pidB */ 52090221f91SCody Peter Mello assert_read_locked_by(lock1, styleB == LSTYLE_POSIX ? pidB : -1); 52190221f91SCody Peter Mello assert_unlocked(lock2); 52290221f91SCody Peter Mello 52390221f91SCody Peter Mello /* Tell pidB to exit */ 52490221f91SCody Peter Mello flock_alert(fdsB[0]); 52590221f91SCody Peter Mello flock_cleanup_child(pidB, fdsB); 52690221f91SCody Peter Mello 52790221f91SCody Peter Mello assert_all_unlocked(); 52890221f91SCody Peter Mello 52990221f91SCody Peter Mello flock_log(" ok\n"); 53090221f91SCody Peter Mello } 53190221f91SCody Peter Mello 53290221f91SCody Peter Mello 53390221f91SCody Peter Mello static void 53490221f91SCody Peter Mello flock_test_ofd_sameproc(void) 53590221f91SCody Peter Mello { 53690221f91SCody Peter Mello lockinfo_t afd1, afd2, afd3; 53790221f91SCody Peter Mello 53890221f91SCody Peter Mello VERIFY3S(flock_copyfil(&flock_fileA, &afd1), ==, 0); 53990221f91SCody Peter Mello VERIFY3S(flock_copyfil(&flock_fileA, &afd2), ==, 0); 54090221f91SCody Peter Mello VERIFY3S(flock_copyfil(&flock_fileA, &afd3), ==, 0); 54190221f91SCody Peter Mello 54290221f91SCody Peter Mello flock_log("Acquiring first two shared locks..."); 54390221f91SCody Peter Mello VERIFY3S(flock(afd1.lf_fd, LOCK_SH), ==, 0); 54490221f91SCody Peter Mello VERIFY3S(flock(afd2.lf_fd, LOCK_SH), ==, 0); 54590221f91SCody Peter Mello assert_read_locked_by(&flock_fileA, -1); 54690221f91SCody Peter Mello flock_log(" ok\n"); 54790221f91SCody Peter Mello 54890221f91SCody Peter Mello flock_log("Acquiring an exclusive lock should fail w/ EWOULDBLOCK..."); 54990221f91SCody Peter Mello VERIFY3S(flock(afd3.lf_fd, LOCK_EX|LOCK_NB), ==, -1); 55090221f91SCody Peter Mello VERIFY3U(errno, ==, EWOULDBLOCK); 55190221f91SCody Peter Mello flock_log(" ok\n"); 55290221f91SCody Peter Mello 55390221f91SCody Peter Mello flock_log("Releasing to acquire an exclusive lock..."); 55490221f91SCody Peter Mello VERIFY3S(flock(afd1.lf_fd, LOCK_UN), ==, 0); 55590221f91SCody Peter Mello VERIFY3S(flock(afd2.lf_fd, LOCK_UN), ==, 0); 55690221f91SCody Peter Mello flock_log(" ok\n"); 55790221f91SCody Peter Mello 55890221f91SCody Peter Mello flock_log("Acquiring an exclusive lock..."); 55990221f91SCody Peter Mello VERIFY3S(flock(afd3.lf_fd, LOCK_EX), ==, 0); 56090221f91SCody Peter Mello assert_write_locked_by(&flock_fileA, -1); 56190221f91SCody Peter Mello flock_log(" ok\n"); 56290221f91SCody Peter Mello 56390221f91SCody Peter Mello flock_log("Acquiring a shared lock should fail w/ EWOULDBLOCK..."); 56490221f91SCody Peter Mello VERIFY3S(flock(afd1.lf_fd, LOCK_EX|LOCK_NB), ==, -1); 56590221f91SCody Peter Mello VERIFY3U(errno, ==, EWOULDBLOCK); 56690221f91SCody Peter Mello VERIFY3S(flock(afd2.lf_fd, LOCK_EX|LOCK_NB), ==, -1); 56790221f91SCody Peter Mello VERIFY3U(errno, ==, EWOULDBLOCK); 56890221f91SCody Peter Mello flock_log(" ok\n"); 56990221f91SCody Peter Mello 57090221f91SCody Peter Mello flock_log("Releasing exclusive lock..."); 57190221f91SCody Peter Mello VERIFY3S(flock(afd3.lf_fd, LOCK_UN), ==, 0); 57290221f91SCody Peter Mello assert_all_unlocked(); 57390221f91SCody Peter Mello flock_log(" ok\n"); 57490221f91SCody Peter Mello 57590221f91SCody Peter Mello flock_rminfo(&afd1); 57690221f91SCody Peter Mello flock_rminfo(&afd2); 57790221f91SCody Peter Mello flock_rminfo(&afd3); 57890221f91SCody Peter Mello } 57990221f91SCody Peter Mello 58090221f91SCody Peter Mello 58190221f91SCody Peter Mello static void 58290221f91SCody Peter Mello flock_runtests(void) 58390221f91SCody Peter Mello { 58490221f91SCody Peter Mello lock_style_t first, second; 58590221f91SCody Peter Mello int i; 58690221f91SCody Peter Mello 58790221f91SCody Peter Mello flock_log("# Exclusive lock tests\n"); 58890221f91SCody Peter Mello for (first = (lock_style_t)0; first < LSTYLE_LAST; first++) { 58990221f91SCody Peter Mello for (second = (lock_style_t)0; second < LSTYLE_LAST; second++) { 59090221f91SCody Peter Mello flock_test_exclusive(first, second, 59190221f91SCody Peter Mello &flock_fileA, &flock_fileB, B_TRUE); 59290221f91SCody Peter Mello flock_test_exclusive(first, second, 59390221f91SCody Peter Mello &flock_fileA, &flock_fileB, B_FALSE); 59490221f91SCody Peter Mello } 59590221f91SCody Peter Mello } 59690221f91SCody Peter Mello 59790221f91SCody Peter Mello flock_log("# Shared lock tests\n"); 59890221f91SCody Peter Mello for (first = (lock_style_t)0; first < LSTYLE_LAST; first++) { 59990221f91SCody Peter Mello for (second = (lock_style_t)0; second < LSTYLE_LAST; second++) { 60090221f91SCody Peter Mello flock_test_shared(first, second, 60190221f91SCody Peter Mello &flock_fileA, &flock_fileB, B_TRUE); 60290221f91SCody Peter Mello flock_test_shared(first, second, 60390221f91SCody Peter Mello &flock_fileA, &flock_fileB, B_FALSE); 60490221f91SCody Peter Mello } 60590221f91SCody Peter Mello } 60690221f91SCody Peter Mello 60790221f91SCody Peter Mello flock_log("# flock(3C) directory lock tests\n"); 60890221f91SCody Peter Mello flock_test_exclusive(LSTYLE_FLOCK, LSTYLE_FLOCK, 60990221f91SCody Peter Mello &flock_dirA, &flock_dirB, B_TRUE); 61090221f91SCody Peter Mello flock_test_exclusive(LSTYLE_FLOCK, LSTYLE_FLOCK, 61190221f91SCody Peter Mello &flock_dirA, &flock_dirB, B_FALSE); 61290221f91SCody Peter Mello flock_test_shared(LSTYLE_FLOCK, LSTYLE_FLOCK, 61390221f91SCody Peter Mello &flock_dirA, &flock_dirB, B_TRUE); 61490221f91SCody Peter Mello flock_test_shared(LSTYLE_FLOCK, LSTYLE_FLOCK, 61590221f91SCody Peter Mello &flock_dirA, &flock_dirB, B_FALSE); 61690221f91SCody Peter Mello 61790221f91SCody Peter Mello 61890221f91SCody Peter Mello flock_log("# Invalid fcntl(2) parameters tests\n"); 61990221f91SCody Peter Mello for (i = 0; i < sizeof (cmds) / sizeof (short); i++) { 62090221f91SCody Peter Mello flock_test_invalid(&flock_fileA, cmds[i], 200, 0, 0, 0); 62190221f91SCody Peter Mello flock_test_invalid(&flock_fileA, cmds[i], -1, 0, 0, 0); 62290221f91SCody Peter Mello } 62390221f91SCody Peter Mello for (i = 3; i < sizeof (cmds) / sizeof (short); i++) { 62490221f91SCody Peter Mello flock_test_invalid(&flock_fileA, cmds[i], F_WRLCK, 1, 0, 0); 62590221f91SCody Peter Mello flock_test_invalid(&flock_fileA, cmds[i], F_WRLCK, 0, 1, 0); 62690221f91SCody Peter Mello flock_test_invalid(&flock_fileA, cmds[i], F_WRLCK, 0, 0, 1); 62790221f91SCody Peter Mello } 628*9c7f1ae0SJerry Jelinek for (i = 0; i < sizeof (cmds64) / sizeof (short); i++) { 629*9c7f1ae0SJerry Jelinek flock_test_invalid64(&flock_fileA, cmds64[i], F_WRLCK, 1, 0, 0); 630*9c7f1ae0SJerry Jelinek flock_test_invalid64(&flock_fileA, cmds64[i], F_WRLCK, 0, 1, 0); 631*9c7f1ae0SJerry Jelinek flock_test_invalid64(&flock_fileA, cmds64[i], F_WRLCK, 0, 0, 1); 632*9c7f1ae0SJerry Jelinek } 63390221f91SCody Peter Mello 63490221f91SCody Peter Mello flock_log("# Testing that multiple OFD locks work in a process\n"); 63590221f91SCody Peter Mello flock_test_ofd_sameproc(); 63690221f91SCody Peter Mello 63790221f91SCody Peter Mello flock_log("# Testing flock(3C) upgrade/downgrade tests\n"); 63890221f91SCody Peter Mello flock_test_upgrade_downgrade(); 63990221f91SCody Peter Mello } 64090221f91SCody Peter Mello 64190221f91SCody Peter Mello 64290221f91SCody Peter Mello int 64390221f91SCody Peter Mello main(int argc, char *argv[]) 64490221f91SCody Peter Mello { 64590221f91SCody Peter Mello char *basestr, *suffix, *dirstr, *dirpath; 64690221f91SCody Peter Mello pid_t testrunner; 64790221f91SCody Peter Mello int exval; 64890221f91SCody Peter Mello 64990221f91SCody Peter Mello LOG = B_TRUE; 65090221f91SCody Peter Mello 65190221f91SCody Peter Mello if (argc < 1) { 65290221f91SCody Peter Mello errx(EXIT_FAILURE, "Can't find program name!"); 65390221f91SCody Peter Mello } 65490221f91SCody Peter Mello 65590221f91SCody Peter Mello dirstr = strdup(argv[0]); 65690221f91SCody Peter Mello dirpath = dirname(dirstr); 65790221f91SCody Peter Mello basestr = strdup(argv[0]); 65890221f91SCody Peter Mello suffix = basename(basestr); 65990221f91SCody Peter Mello 66090221f91SCody Peter Mello while (*suffix != '.' && *suffix != '\0') { 66190221f91SCody Peter Mello suffix += 1; 66290221f91SCody Peter Mello } 66390221f91SCody Peter Mello 66490221f91SCody Peter Mello if (asprintf(&acqprog, "%s/acquire-lock%s", dirpath, suffix) < 0) { 66590221f91SCody Peter Mello errx(EXIT_FAILURE, 66690221f91SCody Peter Mello "Can't generate lock acquisition program name!"); 66790221f91SCody Peter Mello } 66890221f91SCody Peter Mello 66990221f91SCody Peter Mello if (access(acqprog, X_OK) != 0) { 67090221f91SCody Peter Mello err(EXIT_FAILURE, 67190221f91SCody Peter Mello "Can't run lock acquisition program %s", acqprog); 67290221f91SCody Peter Mello } 67390221f91SCody Peter Mello 67490221f91SCody Peter Mello /* Create several lockfiles for testing */ 67590221f91SCody Peter Mello if (flock_mkfil(&flock_fileA) != 0 || 67690221f91SCody Peter Mello flock_mkfil(&flock_fileB) != 0 || 67790221f91SCody Peter Mello flock_mkdir(&flock_dirA) != 0 || 67890221f91SCody Peter Mello flock_mkdir(&flock_dirB) != 0) { 67990221f91SCody Peter Mello exval = 1; 68090221f91SCody Peter Mello goto cleanup; 68190221f91SCody Peter Mello } 68290221f91SCody Peter Mello 68390221f91SCody Peter Mello /* 68490221f91SCody Peter Mello * We run the tests in a child process so that when tests fail 68590221f91SCody Peter Mello * we can still clean up our temporary files. 68690221f91SCody Peter Mello */ 68790221f91SCody Peter Mello testrunner = fork(); 68890221f91SCody Peter Mello if (testrunner == (pid_t)-1) { 68990221f91SCody Peter Mello err(EXIT_FAILURE, "Unable to fork to run tests"); 69090221f91SCody Peter Mello } else if (testrunner == (pid_t)0) { 69190221f91SCody Peter Mello flock_runtests(); 69290221f91SCody Peter Mello return (0); 69390221f91SCody Peter Mello } 69490221f91SCody Peter Mello 69590221f91SCody Peter Mello exval = flock_wait(testrunner); 69690221f91SCody Peter Mello 69790221f91SCody Peter Mello cleanup: 69890221f91SCody Peter Mello free(basestr); 69990221f91SCody Peter Mello free(dirstr); 70090221f91SCody Peter Mello flock_rminfo(&flock_fileA); 70190221f91SCody Peter Mello flock_rminfo(&flock_fileB); 70290221f91SCody Peter Mello flock_rminfo(&flock_dirA); 70390221f91SCody Peter Mello flock_rminfo(&flock_dirB); 70490221f91SCody Peter Mello return (exval); 70590221f91SCody Peter Mello } 706