1 /* $NetBSD: flock.c,v 1.11 2014/08/18 09:16:35 christos Exp $ */
4 * Copyright (c) 2012 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * from this software without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
33 #include <sys/cdefs.h>
34 __RCSID("$NetBSD: flock.c,v 1.11 2014/08/18 09:16:35 christos Exp $");
49 static struct option flock_longopts
[] = {
50 { "debug", no_argument
, 0, 'd' },
51 { "help", no_argument
, 0, 'h' },
52 { "nonblock", no_argument
, 0, 'n' },
53 { "nb", no_argument
, 0, 'n' },
54 { "close", no_argument
, 0, 'o' },
55 { "shared", no_argument
, 0, 's' },
56 { "exclusive", no_argument
, 0, 'x' },
57 { "unlock", no_argument
, 0, 'u' },
58 { "verbose", no_argument
, 0, 'v' },
59 { "command", required_argument
, 0, 'c' },
60 { "wait", required_argument
, 0, 'w' },
61 { "timeout", required_argument
, 0, 'w' },
65 static sig_atomic_t timeout_expired
;
67 static __dead
__printflike(1, 2) void
68 usage(const char *fmt
, ...)
73 fprintf(stderr
, "%s: ", getprogname());
74 vfprintf(stderr
, fmt
, ap
);
79 fprintf(stderr
, "Usage: %s [-dnosvx] [-w timeout] lockfile|lockdir "
80 "[-c command]|command ...\n\t%s [-dnsuvx] [-w timeout] lockfd\n",
81 getprogname(), getprogname());
94 static char buf
[1024];
99 strlcpy(buf
, "LOCK_NB|", sizeof(buf
));
105 strlcat(buf
, "LOCK_SH", sizeof(buf
));
108 strlcat(buf
, "LOCK_EX", sizeof(buf
));
111 strlcat(buf
, "LOCK_UN", sizeof(buf
));
114 snprintf(buf
, sizeof(buf
), "*%d*", l
| nb
);
122 switch (l
& ~LOCK_NB
) {
140 if (asprintf(&v
, "%s %s", v
, *av
++) < 0)
141 err(EXIT_FAILURE
, "malloc");
143 if ((v
= strdup(*av
++)) == NULL
)
144 err(EXIT_FAILURE
, "strdup");
150 main(int argc
, char *argv
[])
161 __UNCONST(_PATH_BSHELL
), __UNCONST("-c"), NULL
, NULL
163 char **cmdargv
= NULL
, *v
;
164 #if !defined(__minix)
168 #endif /* !defined(__minix) */
170 setprogname(argv
[0]);
172 while ((c
= getopt_long(argc
, argv
, "+dnosuvw:x", flock_longopts
, NULL
))
179 #define T(l) (lock & ~LOCK_NB) != (l) && (lock & ~LOCK_NB) != 0
198 timeout
= strtod(optarg
, NULL
);
207 usage("Invalid option '%c'", c
);
209 usage("-%c can't be used with -%c", c
, lockchar(lock
));
215 if ((lock
& ~LOCK_NB
) == 0)
216 lock
|= LOCK_EX
; /* default to exclusive like linux */
220 usage("Missing lock file argument");
223 usage("Close is not valid for descriptors");
225 l
= strtol(argv
[0], &v
, 0);
226 if ((l
== LONG_MIN
|| l
== LONG_MAX
) && errno
== ERANGE
)
227 err(EXIT_FAILURE
, "Bad file descriptor `%s'", argv
[0]);
228 if (l
> INT_MAX
|| l
< 0 || *v
)
229 errx(EXIT_FAILURE
, "Bad file descriptor `%s'", argv
[0]);
232 fprintf(stderr
, "descriptor %s lock %s\n",
233 argv
[0], lock2name(lock
));
238 if ((lock
& LOCK_NB
) == LOCK_UN
)
239 usage("Unlock is only valid for descriptors");
240 if (strcmp(argv
[1], "-c") == 0 ||
241 strcmp(argv
[1], "--command") == 0) {
243 usage("Missing argument to %s", strcmp(argv
[1],
244 "-c") == 0 ? "-c" : "--command");
250 if ((fd
= open(argv
[0], O_RDONLY
)) == -1) {
251 if (errno
!= ENOENT
||
252 (fd
= open(argv
[0], O_RDWR
|O_CREAT
, 0600)) == -1)
253 err(EXIT_FAILURE
, "Cannot open `%s'", argv
[0]);
256 fprintf(stderr
, "file %s lock %s command %s ...\n",
257 argv
[0], lock2name(lock
), v
= cmdline(cmdargv
));
264 #if !defined(__minix)
266 struct itimerspec it
;
267 #endif /* !defined(__minix) */
270 #if !defined(__minix)
271 timespecclear(&it
.it_interval
);
272 it
.it_value
.tv_sec
= timeout
;
273 it
.it_value
.tv_nsec
= (timeout
- it
.it_value
.tv_sec
) *
276 memset(&ev
, 0, sizeof(ev
));
277 ev
.sigev_notify
= SIGEV_SIGNAL
;
278 ev
.sigev_signo
= SIGALRM
;
280 if (timer_create(CLOCK_REALTIME
, &ev
, &tm
) == -1)
281 err(EXIT_FAILURE
, "timer_create");
283 if (timer_settime(tm
, TIMER_RELTIME
, &it
, NULL
) == -1)
284 err(EXIT_FAILURE
, "timer_settime");
286 memset(&it
.it_interval
, 0, sizeof(it
.it_interval
));
287 it
.it_value
.tv_sec
= timeout
;
288 it
.it_value
.tv_usec
= (timeout
- it
.it_value
.tv_sec
) * 1000000;
290 if (setitimer(ITIMER_REAL
, &it
, NULL
) == -1)
291 err(EXIT_FAILURE
, "setitimer");
293 memset(&it
, 0, sizeof(it
)); /* for the reset later */
294 #endif /* !defined(__minix) */
296 memset(&sa
, 0, sizeof(sa
));
297 sa
.sa_handler
= sigalrm
;
298 sigemptyset(&sa
.sa_mask
);
300 if (sigaction(SIGALRM
, &sa
, NULL
) == -1)
301 err(EXIT_FAILURE
, "sigaction");
304 fprintf(stderr
, "alarm %g\n", timeout
);
307 while (flock(fd
, lock
) == -1) {
308 if (errno
== EINTR
&& timeout_expired
== 0)
311 err(EXIT_FAILURE
, "flock(%d, %s)", fd
, lock2name(lock
));
317 #if !defined(__minix)
320 setitimer(ITIMER_REAL
, &it
, NULL
);
321 #endif /* !defined(__minix) */
326 if (cmdargv
!= NULL
) {
327 execvp(cmdargv
[0], cmdargv
);
328 err(EXIT_FAILURE
, "execvp '%s'", v
= cmdline(cmdargv
));