2012-11-02 06:07:19 +04:00
|
|
|
/* $NetBSD: flock.c,v 1.4 2012/11/02 02:07:19 wiz Exp $ */
|
2012-11-02 03:30:19 +04:00
|
|
|
|
|
|
|
/*-
|
|
|
|
* Copyright (c) 2012 The NetBSD Foundation, Inc.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* This code is derived from software contributed to The NetBSD Foundation
|
|
|
|
* by Christos Zoulas.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
* from this software without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
|
|
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
|
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
|
|
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <sys/cdefs.h>
|
2012-11-02 06:07:19 +04:00
|
|
|
__RCSID("$NetBSD: flock.c,v 1.4 2012/11/02 02:07:19 wiz Exp $");
|
2012-11-02 03:30:19 +04:00
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <signal.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <err.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <getopt.h>
|
|
|
|
#include <paths.h>
|
|
|
|
|
|
|
|
struct option flock_longopts[] = {
|
|
|
|
{ "debug", no_argument, 0, 'd' },
|
|
|
|
{ "help", no_argument, 0, 'h' },
|
|
|
|
{ "nonblock", no_argument, 0, 'n' },
|
|
|
|
{ "nb", no_argument, 0, 'n' },
|
|
|
|
{ "close", no_argument, 0, 'o' },
|
|
|
|
{ "shared", no_argument, 0, 's' },
|
|
|
|
{ "exclusive", no_argument, 0, 'x' },
|
|
|
|
{ "unlock", no_argument, 0, 'u' },
|
|
|
|
{ "verbose", no_argument, 0, 'v' },
|
|
|
|
{ "command", required_argument, 0, 'c' },
|
|
|
|
{ "wait", required_argument, 0, 'w' },
|
|
|
|
{ "timeout", required_argument, 0, 'w' },
|
|
|
|
{ NULL, 0, 0, 0 },
|
|
|
|
};
|
|
|
|
|
|
|
|
static int verbose = 0;
|
2012-11-02 05:30:46 +04:00
|
|
|
static sig_atomic_t timeout_expired;
|
2012-11-02 03:30:19 +04:00
|
|
|
|
|
|
|
static __dead void usage(void)
|
|
|
|
{
|
2012-11-02 06:07:19 +04:00
|
|
|
fprintf(stderr, "Usage: %s [-dnosvx] [-w timeout] lockfile|lockdir [-c command]| "
|
|
|
|
"command ...\n\t%s [-dnsuvx] [-w timeout] lockfd\n", getprogname(),
|
2012-11-02 03:30:19 +04:00
|
|
|
getprogname());
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
|
|
|
|
static __dead void
|
|
|
|
sigalrm(int sig)
|
|
|
|
{
|
2012-11-02 05:30:46 +04:00
|
|
|
timeout_expired++;
|
2012-11-02 03:30:19 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static const char *
|
|
|
|
lock2name(int l)
|
|
|
|
{
|
|
|
|
static char buf[1024];
|
|
|
|
int nb = l & LOCK_NB;
|
|
|
|
|
|
|
|
l &= ~LOCK_NB;
|
|
|
|
if (nb)
|
|
|
|
strlcpy(buf, "LOCK_NB|", sizeof(buf));
|
|
|
|
else
|
|
|
|
buf[0] = '\0';
|
|
|
|
|
|
|
|
switch (l) {
|
|
|
|
case LOCK_SH:
|
|
|
|
strlcat(buf, "LOCK_SH", sizeof(buf));
|
|
|
|
return buf;
|
|
|
|
case LOCK_EX:
|
|
|
|
strlcat(buf, "LOCK_EX", sizeof(buf));
|
|
|
|
return buf;
|
|
|
|
case LOCK_UN:
|
|
|
|
strlcat(buf, "LOCK_UN", sizeof(buf));
|
|
|
|
return buf;
|
|
|
|
default:
|
|
|
|
snprintf(buf, sizeof(buf), "*%d*", l | nb);
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
main(int argc, char *argv[])
|
|
|
|
{
|
|
|
|
int c;
|
2012-11-02 05:30:46 +04:00
|
|
|
int lock = LOCK_EX;
|
2012-11-02 03:30:19 +04:00
|
|
|
double timeout = 0;
|
|
|
|
int cls = 0;
|
|
|
|
int fd = -1;
|
|
|
|
int debug = 0;
|
2012-11-02 05:30:46 +04:00
|
|
|
char *mcargv[] = {
|
|
|
|
__UNCONST(_PATH_BSHELL), __UNCONST("-c"), NULL, NULL
|
|
|
|
};
|
|
|
|
char **cmdargv = NULL;
|
2012-11-02 03:30:19 +04:00
|
|
|
|
|
|
|
setprogname(argv[0]);
|
|
|
|
|
2012-11-02 06:03:18 +04:00
|
|
|
while ((c = getopt_long(argc, argv, "+dnosuw:x", flock_longopts, NULL))
|
2012-11-02 03:30:19 +04:00
|
|
|
!= -1)
|
|
|
|
switch (c) {
|
|
|
|
case 'd':
|
|
|
|
debug++;
|
|
|
|
break;
|
|
|
|
case 'x':
|
2012-11-02 05:30:46 +04:00
|
|
|
lock = LOCK_EX | (lock & ~LOCK_NB);
|
2012-11-02 03:30:19 +04:00
|
|
|
break;
|
|
|
|
case 'n':
|
|
|
|
lock |= LOCK_NB;
|
|
|
|
break;
|
|
|
|
case 's':
|
2012-11-02 05:30:46 +04:00
|
|
|
lock = LOCK_SH | (lock & ~LOCK_NB);
|
2012-11-02 03:30:19 +04:00
|
|
|
break;
|
|
|
|
case 'u':
|
2012-11-02 05:30:46 +04:00
|
|
|
lock = LOCK_UN | (lock & ~LOCK_NB);
|
2012-11-02 03:30:19 +04:00
|
|
|
break;
|
|
|
|
case 'w':
|
|
|
|
timeout = strtod(optarg, NULL);
|
|
|
|
break;
|
|
|
|
case 'v':
|
|
|
|
verbose = 1;
|
|
|
|
break;
|
|
|
|
case 'o':
|
|
|
|
cls = 1;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
usage();
|
|
|
|
}
|
|
|
|
|
|
|
|
argc -= optind;
|
|
|
|
argv += optind;
|
|
|
|
|
2012-11-02 05:30:46 +04:00
|
|
|
switch (argc) {
|
|
|
|
case 0:
|
|
|
|
usage();
|
|
|
|
case 1:
|
|
|
|
if (cls)
|
|
|
|
usage();
|
|
|
|
fd = strtol(argv[0], NULL, 0); // XXX: error checking
|
|
|
|
if (debug)
|
|
|
|
fprintf(stderr, "descriptor %s lock %s\n",
|
|
|
|
argv[0], lock2name(lock));
|
2012-11-02 03:30:19 +04:00
|
|
|
if (lock == LOCK_UN)
|
|
|
|
usage();
|
2012-11-02 05:30:46 +04:00
|
|
|
default:
|
|
|
|
if (strcmp(argv[1], "-c") == 0 ||
|
|
|
|
strcmp(argv[1], "--command") == 0) {
|
|
|
|
if (argc == 2)
|
|
|
|
usage();
|
|
|
|
mcargv[2] = argv[2];
|
|
|
|
cmdargv = mcargv;
|
|
|
|
} else
|
|
|
|
cmdargv = argv + 1;
|
|
|
|
|
2012-11-02 03:30:19 +04:00
|
|
|
if ((fd = open(argv[0], O_RDONLY)) == -1) {
|
|
|
|
if (errno != ENOENT ||
|
|
|
|
(fd = open(argv[0], O_RDWR|O_CREAT, 0600)) == -1)
|
|
|
|
err(EXIT_FAILURE, "Cannot open `%s'", argv[0]);
|
|
|
|
}
|
|
|
|
if (debug)
|
2012-11-02 05:30:46 +04:00
|
|
|
fprintf(stderr, "file %s lock %s command %s ...\n",
|
|
|
|
argv[0], lock2name(lock), cmdargv[0]);
|
|
|
|
break;
|
2012-11-02 03:30:19 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (timeout) {
|
|
|
|
signal(SIGALRM, sigalrm);
|
|
|
|
alarm((int)timeout); // XXX: User timer_create()
|
|
|
|
if (debug)
|
|
|
|
fprintf(stderr, "alarm %d\n", (int)timeout);
|
|
|
|
}
|
|
|
|
|
2012-11-02 05:30:46 +04:00
|
|
|
while (flock(fd, lock) == -1) {
|
|
|
|
if (errno == EINTR && timeout_expired == 0)
|
|
|
|
continue;
|
2012-11-02 03:30:19 +04:00
|
|
|
if (verbose)
|
|
|
|
err(EXIT_FAILURE, "flock(%d, %s)", fd, lock2name(lock));
|
|
|
|
else
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (timeout)
|
|
|
|
alarm(0);
|
|
|
|
|
|
|
|
if (cls)
|
|
|
|
(void)close(fd);
|
|
|
|
|
2012-11-02 05:30:46 +04:00
|
|
|
if (cmdargv != NULL) {
|
|
|
|
execvp(cmdargv[0], cmdargv);
|
|
|
|
err(EXIT_FAILURE, "execvp '%s'", cmdargv[0]);
|
|
|
|
}
|
2012-11-02 03:30:19 +04:00
|
|
|
return 0;
|
|
|
|
}
|