/* $NetBSD: flock.c,v 1.1 2012/11/01 23:30:19 christos Exp $ */ /*- * 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 __RCSID("$NetBSD: flock.c,v 1.1 2012/11/01 23:30:19 christos Exp $"); #include #include #include #include #include #include #include #include #include #include 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; static __dead void usage(void) { fprintf(stderr, "Usage: %s [-dnosxv] [-w ] file|directory [-c] " "\n\t%s [-dnusxv] [-w ] fd\n", getprogname(), getprogname()); exit(EXIT_FAILURE); } static __dead void sigalrm(int sig) { if (verbose) { errno = ETIMEDOUT; errx(EXIT_FAILURE, ""); } else exit(EXIT_FAILURE); } 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; int lock = 0; double timeout = 0; int cls = 0; int fd = -1; int debug = 0; char *command = NULL; setprogname(argv[0]); while ((c = getopt_long(argc, argv, "c:dnosxuw:", flock_longopts, NULL)) != -1) switch (c) { case 'c': command = optarg; break; case 'd': debug++; break; case 'e': case 'x': lock |= LOCK_EX; break; case 'n': lock |= LOCK_NB; break; case 's': lock |= LOCK_SH; break; case 'u': lock |= LOCK_UN; break; case 'w': timeout = strtod(optarg, NULL); break; case 'v': verbose = 1; break; case 'o': cls = 1; break; default: usage(); } argc -= optind; argv += optind; if (command) { if (lock == LOCK_UN) usage(); 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) fprintf(stderr, "file %s lock %s command %s\n", argv[0], lock2name(lock), command); } else { 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)); } if (timeout) { signal(SIGALRM, sigalrm); alarm((int)timeout); // XXX: User timer_create() if (debug) fprintf(stderr, "alarm %d\n", (int)timeout); } if (flock(fd, lock) == -1) { if (verbose) err(EXIT_FAILURE, "flock(%d, %s)", fd, lock2name(lock)); else return EXIT_FAILURE; } if (timeout) alarm(0); if (cls) (void)close(fd); if (command == NULL) return 0; if (debug) fprintf(stderr, "execute %s -c '%s'\n", _PATH_BSHELL, command); execlp(_PATH_BSHELL, "sh", "-c", command, NULL); err(EXIT_FAILURE, "exec %s -c '%s'", _PATH_BSHELL, command); return 0; }