flock.c revision 1.1
1/* $NetBSD: flock.c,v 1.1 2012/11/01 23:30:19 christos Exp $ */ 2 3/*- 4 * Copyright (c) 2012 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Christos Zoulas. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 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. 19 * 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. 31 */ 32 33#include <sys/cdefs.h> 34__RCSID("$NetBSD: flock.c,v 1.1 2012/11/01 23:30:19 christos Exp $"); 35 36#include <stdio.h> 37#include <string.h> 38#include <fcntl.h> 39#include <stdlib.h> 40#include <signal.h> 41#include <unistd.h> 42#include <err.h> 43#include <errno.h> 44#include <getopt.h> 45#include <paths.h> 46 47struct option flock_longopts[] = { 48 { "debug", no_argument, 0, 'd' }, 49 { "help", no_argument, 0, 'h' }, 50 { "nonblock", no_argument, 0, 'n' }, 51 { "nb", no_argument, 0, 'n' }, 52 { "close", no_argument, 0, 'o' }, 53 { "shared", no_argument, 0, 's' }, 54 { "exclusive", no_argument, 0, 'x' }, 55 { "unlock", no_argument, 0, 'u' }, 56 { "verbose", no_argument, 0, 'v' }, 57 { "command", required_argument, 0, 'c' }, 58 { "wait", required_argument, 0, 'w' }, 59 { "timeout", required_argument, 0, 'w' }, 60 { NULL, 0, 0, 0 }, 61}; 62 63static int verbose = 0; 64 65static __dead void usage(void) 66{ 67 fprintf(stderr, "Usage: %s [-dnosxv] [-w <timeout>] file|directory [-c] " 68 "<command>\n\t%s [-dnusxv] [-w <timeout>] fd\n", getprogname(), 69 getprogname()); 70 exit(EXIT_FAILURE); 71} 72 73static __dead void 74sigalrm(int sig) 75{ 76 if (verbose) { 77 errno = ETIMEDOUT; 78 errx(EXIT_FAILURE, ""); 79 } else 80 exit(EXIT_FAILURE); 81} 82 83static const char * 84lock2name(int l) 85{ 86 static char buf[1024]; 87 int nb = l & LOCK_NB; 88 89 l &= ~LOCK_NB; 90 if (nb) 91 strlcpy(buf, "LOCK_NB|", sizeof(buf)); 92 else 93 buf[0] = '\0'; 94 95 switch (l) { 96 case LOCK_SH: 97 strlcat(buf, "LOCK_SH", sizeof(buf)); 98 return buf; 99 case LOCK_EX: 100 strlcat(buf, "LOCK_EX", sizeof(buf)); 101 return buf; 102 case LOCK_UN: 103 strlcat(buf, "LOCK_UN", sizeof(buf)); 104 return buf; 105 default: 106 snprintf(buf, sizeof(buf), "*%d*", l | nb); 107 return buf; 108 } 109} 110 111int 112main(int argc, char *argv[]) 113{ 114 int c; 115 int lock = 0; 116 double timeout = 0; 117 int cls = 0; 118 int fd = -1; 119 int debug = 0; 120 char *command = NULL; 121 122 setprogname(argv[0]); 123 124 while ((c = getopt_long(argc, argv, "c:dnosxuw:", flock_longopts, NULL)) 125 != -1) 126 switch (c) { 127 case 'c': 128 command = optarg; 129 break; 130 case 'd': 131 debug++; 132 break; 133 case 'e': 134 case 'x': 135 lock |= LOCK_EX; 136 break; 137 case 'n': 138 lock |= LOCK_NB; 139 break; 140 case 's': 141 lock |= LOCK_SH; 142 break; 143 case 'u': 144 lock |= LOCK_UN; 145 break; 146 case 'w': 147 timeout = strtod(optarg, NULL); 148 break; 149 case 'v': 150 verbose = 1; 151 break; 152 case 'o': 153 cls = 1; 154 break; 155 default: 156 usage(); 157 } 158 159 argc -= optind; 160 argv += optind; 161 162 if (command) { 163 if (lock == LOCK_UN) 164 usage(); 165 if ((fd = open(argv[0], O_RDONLY)) == -1) { 166 if (errno != ENOENT || 167 (fd = open(argv[0], O_RDWR|O_CREAT, 0600)) == -1) 168 err(EXIT_FAILURE, "Cannot open `%s'", argv[0]); 169 } 170 if (debug) 171 fprintf(stderr, "file %s lock %s command %s\n", 172 argv[0], lock2name(lock), command); 173 174 175 } else { 176 if (cls) 177 usage(); 178 fd = strtol(argv[0], NULL, 0); // XXX: error checking 179 if (debug) 180 fprintf(stderr, "descriptor %s lock %s\n", 181 argv[0], lock2name(lock)); 182 } 183 184 if (timeout) { 185 signal(SIGALRM, sigalrm); 186 alarm((int)timeout); // XXX: User timer_create() 187 if (debug) 188 fprintf(stderr, "alarm %d\n", (int)timeout); 189 } 190 191 if (flock(fd, lock) == -1) { 192 if (verbose) 193 err(EXIT_FAILURE, "flock(%d, %s)", fd, lock2name(lock)); 194 else 195 return EXIT_FAILURE; 196 } 197 198 if (timeout) 199 alarm(0); 200 201 if (cls) 202 (void)close(fd); 203 204 if (command == NULL) 205 return 0; 206 if (debug) 207 fprintf(stderr, "execute %s -c '%s'\n", _PATH_BSHELL, command); 208 execlp(_PATH_BSHELL, "sh", "-c", command, NULL); 209 err(EXIT_FAILURE, "exec %s -c '%s'", _PATH_BSHELL, command); 210 return 0; 211} 212