Fri Nov 2 17:03:16 2012 UTC ()
- better usage messages
- verbose can be local
- add static


(christos)
diff -r1.5 -r1.6 src/usr.bin/flock/flock.c

cvs diff -r1.5 -r1.6 src/usr.bin/flock/flock.c (expand / switch to unified diff)

--- src/usr.bin/flock/flock.c 2012/11/02 12:47:23 1.5
+++ src/usr.bin/flock/flock.c 2012/11/02 17:03:16 1.6
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: flock.c,v 1.5 2012/11/02 12:47:23 christos Exp $ */ 1/* $NetBSD: flock.c,v 1.6 2012/11/02 17:03:16 christos Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 2012 The NetBSD Foundation, Inc. 4 * Copyright (c) 2012 The NetBSD Foundation, Inc.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to The NetBSD Foundation 7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Christos Zoulas. 8 * by Christos Zoulas.
9 * 9 *
10 * Redistribution and use in source and binary forms, with or without 10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions 11 * modification, are permitted provided that the following conditions
12 * are met: 12 * are met:
13 * 1. Redistributions of source code must retain the above copyright 13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer. 14 * notice, this list of conditions and the following disclaimer.
@@ -21,68 +21,77 @@ @@ -21,68 +21,77 @@
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 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 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 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 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE. 30 * POSSIBILITY OF SUCH DAMAGE.
31 */ 31 */
32 32
33#include <sys/cdefs.h> 33#include <sys/cdefs.h>
34__RCSID("$NetBSD: flock.c,v 1.5 2012/11/02 12:47:23 christos Exp $"); 34__RCSID("$NetBSD: flock.c,v 1.6 2012/11/02 17:03:16 christos Exp $");
35 35
36#include <stdio.h> 36#include <stdio.h>
37#include <string.h> 37#include <string.h>
38#include <fcntl.h> 38#include <fcntl.h>
39#include <stdlib.h> 39#include <stdlib.h>
40#include <signal.h> 40#include <signal.h>
41#include <unistd.h> 41#include <unistd.h>
42#include <err.h> 42#include <err.h>
43#include <errno.h> 43#include <errno.h>
44#include <getopt.h> 44#include <getopt.h>
45#include <paths.h> 45#include <paths.h>
46#include <time.h> 46#include <time.h>
47 47
48struct option flock_longopts[] = { 48static struct option flock_longopts[] = {
49 { "debug", no_argument, 0, 'd' }, 49 { "debug", no_argument, 0, 'd' },
50 { "help", no_argument, 0, 'h' }, 50 { "help", no_argument, 0, 'h' },
51 { "nonblock", no_argument, 0, 'n' }, 51 { "nonblock", no_argument, 0, 'n' },
52 { "nb", no_argument, 0, 'n' }, 52 { "nb", no_argument, 0, 'n' },
53 { "close", no_argument, 0, 'o' }, 53 { "close", no_argument, 0, 'o' },
54 { "shared", no_argument, 0, 's' }, 54 { "shared", no_argument, 0, 's' },
55 { "exclusive", no_argument, 0, 'x' }, 55 { "exclusive", no_argument, 0, 'x' },
56 { "unlock", no_argument, 0, 'u' }, 56 { "unlock", no_argument, 0, 'u' },
57 { "verbose", no_argument, 0, 'v' }, 57 { "verbose", no_argument, 0, 'v' },
58 { "command", required_argument, 0, 'c' }, 58 { "command", required_argument, 0, 'c' },
59 { "wait", required_argument, 0, 'w' }, 59 { "wait", required_argument, 0, 'w' },
60 { "timeout", required_argument, 0, 'w' }, 60 { "timeout", required_argument, 0, 'w' },
61 { NULL, 0, 0, 0 }, 61 { NULL, 0, 0, 0 },
62}; 62};
63 63
64static int verbose = 0; 
65static sig_atomic_t timeout_expired; 64static sig_atomic_t timeout_expired;
66 65
67static __dead void usage(void)  66static __dead void
 67usage(const char *fmt, ...)
68{ 68{
 69 if (fmt) {
 70 va_list ap;
 71 va_start(ap, fmt);
 72 fprintf(stderr, "%s: ", getprogname());
 73 vfprintf(stderr, fmt, ap);
 74 fputc('\n', stderr);
 75 va_end(ap);
 76 }
 77
69 fprintf(stderr, "Usage: %s [-dnosvx] [-w timeout] lockfile|lockdir " 78 fprintf(stderr, "Usage: %s [-dnosvx] [-w timeout] lockfile|lockdir "
70 "[-c command]|command ...\n\t%s [-dnsuvx] [-w timeout] lockfd\n", 79 "[-c command]|command ...\n\t%s [-dnsuvx] [-w timeout] lockfd\n",
71 getprogname(), getprogname()); 80 getprogname(), getprogname());
72 exit(EXIT_FAILURE); 81 exit(EXIT_FAILURE);
73} 82}
74 83
75static __dead void 84static void
76sigalrm(int sig) 85sigalrm(int sig)
77{ 86{
78 timeout_expired++; 87 timeout_expired++;
79} 88}
80 89
81static const char * 90static const char *
82lock2name(int l) 91lock2name(int l)
83{ 92{
84 static char buf[1024]; 93 static char buf[1024];
85 int nb = l & LOCK_NB; 94 int nb = l & LOCK_NB;
86 95
87 l &= ~LOCK_NB; 96 l &= ~LOCK_NB;
88 if (nb) 97 if (nb)
@@ -96,109 +105,134 @@ lock2name(int l) @@ -96,109 +105,134 @@ lock2name(int l)
96 return buf; 105 return buf;
97 case LOCK_EX: 106 case LOCK_EX:
98 strlcat(buf, "LOCK_EX", sizeof(buf)); 107 strlcat(buf, "LOCK_EX", sizeof(buf));
99 return buf; 108 return buf;
100 case LOCK_UN: 109 case LOCK_UN:
101 strlcat(buf, "LOCK_UN", sizeof(buf)); 110 strlcat(buf, "LOCK_UN", sizeof(buf));
102 return buf; 111 return buf;
103 default: 112 default:
104 snprintf(buf, sizeof(buf), "*%d*", l | nb); 113 snprintf(buf, sizeof(buf), "*%d*", l | nb);
105 return buf; 114 return buf;
106 } 115 }
107} 116}
108 117
 118static char
 119lockchar(int l)
 120{
 121 switch (l & ~LOCK_NB) {
 122 case LOCK_SH:
 123 return 's';
 124 case LOCK_EX:
 125 return 'x';
 126 case LOCK_UN:
 127 return 'u';
 128 default:
 129 return '*';
 130 }
 131}
 132
109static char * 133static char *
110cmdline(char **av) 134cmdline(char **av)
111{ 135{
112 char *v = NULL; 136 char *v = NULL;
113 while (*av) 137 while (*av)
114 if (v) { 138 if (v) {
115 if (asprintf(&v, "%s %s", v, *av++) < 0) 139 if (asprintf(&v, "%s %s", v, *av++) < 0)
116 err(EXIT_FAILURE, "malloc"); 140 err(EXIT_FAILURE, "malloc");
117 } else { 141 } else {
118 if ((v = strdup(*av++)) == NULL) 142 if ((v = strdup(*av++)) == NULL)
119 err(EXIT_FAILURE, "strdup"); 143 err(EXIT_FAILURE, "strdup");
120 } 144 }
121 return v; 145 return v;
122} 146}
123 147
124int 148int
125main(int argc, char *argv[]) 149main(int argc, char *argv[])
126{ 150{
127 int c; 151 int c;
128 int lock = LOCK_EX; 152 int lock = LOCK_EX;
129 double timeout = 0; 153 double timeout = 0;
130 int cls = 0; 154 int cls = 0;
131 int fd = -1; 155 int fd = -1;
132 int debug = 0; 156 int debug = 0;
 157 int verbose = 0;
133 char *mcargv[] = { 158 char *mcargv[] = {
134 __UNCONST(_PATH_BSHELL), __UNCONST("-c"), NULL, NULL 159 __UNCONST(_PATH_BSHELL), __UNCONST("-c"), NULL, NULL
135 }; 160 };
136 char **cmdargv = NULL, *v; 161 char **cmdargv = NULL, *v;
137 timer_t tm; 162 timer_t tm;
138 163
139 setprogname(argv[0]); 164 setprogname(argv[0]);
140 165
141 while ((c = getopt_long(argc, argv, "+dnosuvw:x", flock_longopts, NULL)) 166 while ((c = getopt_long(argc, argv, "+dnosuvw:x", flock_longopts, NULL))
142 != -1) 167 != -1)
143 switch (c) { 168 switch (c) {
144 case 'd': 169 case 'd':
145 debug++; 170 debug++;
146 break; 171 break;
147 case 'x': 172 case 'x':
148 lock = LOCK_EX | (lock & ~LOCK_NB); 173 if (lock & ~LOCK_NB)
 174 goto badlock;
 175 lock |= LOCK_EX;
149 break; 176 break;
150 case 'n': 177 case 'n':
151 lock |= LOCK_NB; 178 lock |= LOCK_NB;
152 break; 179 break;
153 case 's': 180 case 's':
154 lock = LOCK_SH | (lock & ~LOCK_NB); 181 if (lock & ~LOCK_NB)
 182 goto badlock;
 183 lock |= LOCK_SH;
155 break; 184 break;
156 case 'u': 185 case 'u':
157 lock = LOCK_UN | (lock & ~LOCK_NB); 186 if (lock & ~LOCK_NB)
 187 goto badlock;
 188 lock |= LOCK_UN;
158 break; 189 break;
159 case 'w': 190 case 'w':
160 timeout = strtod(optarg, NULL); 191 timeout = strtod(optarg, NULL);
161 break; 192 break;
162 case 'v': 193 case 'v':
163 verbose = 1; 194 verbose = 1;
164 break; 195 break;
165 case 'o': 196 case 'o':
166 cls = 1; 197 cls = 1;
167 break; 198 break;
168 default: 199 default:
169 usage(); 200 usage("Invalid option '%c'", c);
 201 badlock:
 202 usage("-%c can't be used with -%c", c, lockchar(lock));
170 } 203 }
171 204
172 argc -= optind; 205 argc -= optind;
173 argv += optind; 206 argv += optind;
174 207
175 switch (argc) { 208 switch (argc) {
176 case 0: 209 case 0:
177 usage(); 210 usage("Missing lock file argument");
178 case 1: 211 case 1:
179 if (cls) 212 if (cls)
180 usage(); 213 usage("Close is valid only for descriptors");
181 fd = strtol(argv[0], NULL, 0); // XXX: error checking 214 fd = strtol(argv[0], NULL, 0); // XXX: error checking
182 if (debug) 215 if (debug)
183 fprintf(stderr, "descriptor %s lock %s\n", 216 fprintf(stderr, "descriptor %s lock %s\n",
184 argv[0], lock2name(lock)); 217 argv[0], lock2name(lock));
185 if (lock == LOCK_UN) 
186 usage(); 
187 default: 218 default:
 219 if ((lock & LOCK_NB) == LOCK_UN)
 220 usage("Unlock is only valid for descriptors");
188 if (strcmp(argv[1], "-c") == 0 || 221 if (strcmp(argv[1], "-c") == 0 ||
189 strcmp(argv[1], "--command") == 0) { 222 strcmp(argv[1], "--command") == 0) {
190 if (argc == 2) 223 if (argc == 2)
191 usage(); 224 usage("Missing argument to %s", strcmp(argv[1],
 225 "-c") == 0 ? "-c" : "--command");
192 mcargv[2] = argv[2]; 226 mcargv[2] = argv[2];
193 cmdargv = mcargv; 227 cmdargv = mcargv;
194 } else 228 } else
195 cmdargv = argv + 1; 229 cmdargv = argv + 1;
196  230
197 if ((fd = open(argv[0], O_RDONLY)) == -1) { 231 if ((fd = open(argv[0], O_RDONLY)) == -1) {
198 if (errno != ENOENT ||  232 if (errno != ENOENT ||
199 (fd = open(argv[0], O_RDWR|O_CREAT, 0600)) == -1) 233 (fd = open(argv[0], O_RDWR|O_CREAT, 0600)) == -1)
200 err(EXIT_FAILURE, "Cannot open `%s'", argv[0]); 234 err(EXIT_FAILURE, "Cannot open `%s'", argv[0]);
201 } 235 }
202 if (debug) { 236 if (debug) {
203 fprintf(stderr, "file %s lock %s command %s ...\n", 237 fprintf(stderr, "file %s lock %s command %s ...\n",
204 argv[0], lock2name(lock), v = cmdline(cmdargv)); 238 argv[0], lock2name(lock), v = cmdline(cmdargv));