1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2016 Joyent, Inc. 14 */ 15 16 /* 17 * Acquire the specified kind of lock with the specified parameters. After 18 * acquiring the lock, a byte will be written to stdout. The program will 19 * then wait for a byte to be written to stdin before exiting. 20 * 21 * Usage: <posix|ofd|flock> <shared|exclusive> <path> 22 */ 23 24 #include "util.h" 25 #include <err.h> 26 #include <errno.h> 27 #include <fcntl.h> 28 #include <stdio.h> 29 #include <stdlib.h> 30 #include <strings.h> 31 #include <sys/file.h> 32 #include <unistd.h> 33 34 35 static void acq_fcntl(int, int, int); 36 static void acq_flock(int fd, int mode); 37 static void acq_run(int, lock_style_t, boolean_t); 38 39 40 static void 41 acq_fcntl(int fd, int cmd, int mode) 42 { 43 struct flock fl; 44 int ret, i; 45 46 /* 47 * Acquire the lock, and then try reacquiring it several times. Once we 48 * have acquired the lock, trying to acquire it again should succeed, 49 * and shouldn't upgrade, downgrade or free the lock. 50 */ 51 for (i = 0; i < 3; i++) { 52 flock_reinit(&fl, mode); 53 flock_log("Acquiring lock (fcntl)...\n"); 54 ret = fcntl(fd, cmd, &fl); 55 if (ret == -1) { 56 err(EXIT_FAILURE, "fcntl failed"); 57 } 58 } 59 60 61 /* Let the parent know we have the lock and wait */ 62 flock_log("Waiting (fcntl)...\n"); 63 flock_alert(1); 64 flock_block(0); 65 66 /* Now unlock */ 67 flock_reinit(&fl, F_UNLCK); 68 flock_log("Releasing lock (fcntl)...\n"); 69 ret = fcntl(fd, cmd, &fl); 70 if (ret == -1) { 71 err(EXIT_FAILURE, "fcntl failed"); 72 } 73 } 74 75 76 static void 77 acq_flock(int fd, int mode) 78 { 79 int ret, i; 80 81 /* 82 * Acquire the lock, and then try reacquiring it several times. Once we 83 * have acquired the lock, trying to acquire it again should succeed, 84 * and shouldn't upgrade, downgrade or free the lock. 85 */ 86 for (i = 0; i < 3; i++) { 87 flock_log("Acquiring lock (flock)...\n"); 88 ret = flock(fd, mode); 89 if (ret == -1) { 90 err(EXIT_FAILURE, "flock failed"); 91 } 92 } 93 94 /* Wait to be okayed to unlock */ 95 flock_log("Waiting (flock)...\n"); 96 flock_alert(1); 97 flock_block(0); 98 99 /* Release lock */ 100 flock_log("Releasing lock (flock)...\n"); 101 ret = flock(fd, LOCK_UN); 102 if (ret == -1) { 103 err(EXIT_FAILURE, "flock failed"); 104 } 105 } 106 107 108 static void 109 acq_run(int fd, lock_style_t style, boolean_t is_exclusive) 110 { 111 switch (style) { 112 case LSTYLE_POSIX: 113 acq_fcntl(fd, F_SETLKW, is_exclusive ? F_WRLCK : F_RDLCK); 114 break; 115 case LSTYLE_OFD: 116 acq_fcntl(fd, F_OFD_SETLKW, is_exclusive ? F_WRLCK : F_RDLCK); 117 break; 118 case LSTYLE_FLOCK: 119 acq_flock(fd, is_exclusive ? LOCK_EX : LOCK_SH); 120 break; 121 default: 122 abort(); 123 } 124 } 125 126 127 int 128 main(int argc, char *argv[]) 129 { 130 char *modestr, *path; 131 lock_style_t style; 132 boolean_t is_exclusive; 133 int fd; 134 135 if (argc < 4) { 136 errx(EXIT_FAILURE, BAD_ARGS_MESSAGE, argc - 1); 137 } 138 139 modestr = argv[2]; 140 path = argv[3]; 141 142 style = flock_styleenum(argv[1]); 143 144 if (strcmp(modestr, "shared") == 0) { 145 is_exclusive = B_FALSE; 146 } else if (strcmp(modestr, "exclusive") == 0) { 147 is_exclusive = B_TRUE; 148 } else { 149 errx(EXIT_FAILURE, BAD_MODE_MESSAGE); 150 } 151 152 boolean_t rdonly = style == LSTYLE_FLOCK || !is_exclusive; 153 fd = open(path, rdonly ? O_RDONLY : O_WRONLY); 154 if (fd == -1) { 155 err(EXIT_FAILURE, "Failed to open %s", path); 156 } 157 158 acq_run(fd, style, is_exclusive); 159 160 return (0); 161 } 162