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