refuse_opt.c revision 1.3 1 /* $NetBSD: refuse_opt.c,v 1.3 2007/03/13 20:50:47 agc Exp $ */
2
3 /*-
4 * Copyright (c) 2007 Juan Romero Pardines.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the company nor the name of the author may be used to
16 * endorse or promote products derived from this software without
17 * specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 /*
32 * TODO:
33 * * -oblah,foo... works, but the options are not enabled.
34 * * -ofoo=%s (accepts a string) or -ofoo=%u (int) is not
35 * supported for now.
36 * * void *data: how is it used? I think it's used to enable
37 * options or pass values for the matching options.
38 */
39
40 #include "defs.h"
41 #include "fuse.h"
42 #include "fuse_opt.h"
43
44 #ifdef FUSE_OPT_DEBUG
45 #define DPRINTF(x) do { printf x; } while ( /* CONSTCOND */ 0)
46 #else
47 #define DPRINTF(x)
48 #endif
49
50 enum {
51 KEY_HELP,
52 KEY_VERBOSE,
53 KEY_VERSION
54 };
55
56 struct fuse_opt_option {
57 const struct fuse_opt *fop;
58 char *option;
59 int key;
60 void *data;
61 };
62
63 static int fuse_opt_popt(struct fuse_opt_option *, const struct fuse_opt *);
64
65 /*
66 * Public API.
67 *
68 * The following functions always return 0:
69 *
70 * int fuse_opt_add_arg(struct fuse_args *, const char *);
71 * int fuse_opt_add_opt(char **, const char *);
72 * void fuse_opt_free_args(struct fuse_args *);
73 * int fuse_opt_insert_arg(struct fuse_args *, const char *);
74 *
75 * We implement the next ones:
76 *
77 * int fuse_opt_match(const struct fuse_opt *, const char *);
78 * int fuse_opt_parse(struct fuse_args *, void *,
79 * const struct fuse_opt *, fuse_opt_proc_t);
80 *
81 */
82
83 #define ARGS_CHUNK 32
84
85 static int
86 growargs(struct fuse_args *args, const char *func)
87 {
88 if (args->allocated == 0) {
89 NEWARRAY(char *, args->argv, ARGS_CHUNK,
90 func, return 0);
91 args->allocated = ARGS_CHUNK;
92 } else if (args->argc % ARGS_CHUNK == 0) {
93 args->allocated += ARGS_CHUNK;
94 RENEW(char *, args->argv, args->allocated,
95 func, return 0);
96 }
97 return 1;
98 }
99
100 int
101 fuse_opt_add_arg(struct fuse_args *args, const char *arg)
102 {
103 DPRINTF(("%s: arguments passed: [arg:%s]\n", __func__, arg));
104 if (!growargs(args, "fuse_opt_add_arg")) {
105 return 1;
106 }
107 args->argv[args->argc++] = strdup(arg);
108 return 0;
109 }
110
111 void
112 fuse_opt_free_args(struct fuse_args *args)
113 {
114 int i;
115
116 for (i = 0 ; i < args->allocated ; i++) {
117 (void) free(args->argv[i]);
118 }
119 if (args->allocated > 0) {
120 FREE(args->argv);
121 }
122 (void) memset(args, 0x0, sizeof(*args));
123 }
124
125 int
126 fuse_opt_insert_arg(struct fuse_args *args, int pos, const char *arg)
127 {
128 int i;
129
130 __fuse_pargs("fuse_opt_insert_arg1", args->argc, args->argv);
131 if (!growargs(args, "fuse_opt_insert_arg")) {
132 return 1;
133 }
134 for (i = args->argc++ ; i > pos ; --i) {
135 args->argv[i] = args->argv[i - 1];
136 }
137 args->argv[pos] = strdup(arg);
138 __fuse_pargs("fuse_opt_insert_arg2", args->argc, args->argv);
139 return 0;
140 }
141
142 /* ARGSUSED */
143 int fuse_opt_add_opt(char **opts, const char *opt)
144 {
145 DPRINTF(("%s: arguments passed: [opts=%s] [opt=%s]\n",
146 __func__, *opts, opt));
147 return 0;
148 }
149
150 /*
151 * Returns 0 if opt was matched with any option from opts,
152 * otherwise returns 1.
153 */
154 int
155 fuse_opt_match(const struct fuse_opt *opts, const char *opt)
156 {
157 while (opts++) {
158 if (strcmp(opt, opts->templ) == 0)
159 return 0;
160 }
161
162 return 1;
163 }
164
165 /*
166 * Returns 0 if foo->option was matched with any option from opts,
167 * and sets the following on match:
168 *
169 * * foo->key is set to the foo->fop->value if offset == -1.
170 * * foo->fop points to the matched struct opts.
171 *
172 * otherwise returns 1.
173 */
174 static int
175 fuse_opt_popt(struct fuse_opt_option *foo, const struct fuse_opt *opts)
176 {
177 int i, found = 0;
178 char *match;
179
180 if (!foo->option) {
181 (void)fprintf(stderr, "fuse: missing argument after -o\n");
182 return 1;
183 }
184 /*
185 * iterate over argv and opts to see
186 * if there's a match with any template.
187 */
188 for (match = strtok(foo->option, ",");
189 match; match = strtok(NULL, ",")) {
190
191 DPRINTF(("%s: specified option='%s'\n", __func__, match));
192 found = 0;
193
194 for (i = 0; opts && opts->templ; opts++, i++) {
195
196 DPRINTF(("%s: opts->templ='%s' opts->offset=%d "
197 "opts->value=%d\n", __func__, opts->templ,
198 opts->offset, opts->value));
199
200 /* option is ok */
201 if (strcmp(match, opts->templ) == 0) {
202 DPRINTF(("%s: option matched='%s'\n",
203 __func__, match));
204 found++;
205 /*
206 * our fop pointer now points
207 * to the matched struct opts.
208 */
209 foo->fop = opts;
210 /*
211 * assign default key value, necessary for
212 * KEY_HELP, KEY_VERSION and KEY_VERBOSE.
213 */
214 if (foo->fop->offset == -1)
215 foo->key = foo->fop->value;
216 /* reset counter */
217 opts -= i;
218 break;
219 }
220 }
221 /* invalid option */
222 if (!found) {
223 (void)fprintf(stderr, "fuse: '%s' is not a "
224 "valid option\n", match);
225 return 1;
226 }
227 }
228
229 return 0;
230 }
231
232 /* ARGSUSED1 */
233 int
234 fuse_opt_parse(struct fuse_args *args, void *data,
235 const struct fuse_opt *opts, fuse_opt_proc_t proc)
236 {
237 struct fuse_opt_option foo;
238 char *buf;
239 int i, rv = 0;
240
241 if (!args || !args->argv || !args->argc || !proc) {
242 if (__fuse_debug(0)) {
243 printf("fuse_opt_parse: null args\n");
244 }
245 return 0;
246 }
247
248 if (__fuse_debug(0)) {
249 __fuse_pargs("fuse_opt_parse", args->argc, args->argv);
250 }
251
252 if (args->argc == 1)
253 return proc(foo.data, *args->argv, FUSE_OPT_KEY_OPT, args);
254
255 /* the real loop to process the arguments */
256 for (i = 1; i < args->argc; i++) {
257
258 /* assign current argv string */
259 foo.option = buf = args->argv[i];
260
261 /* argvn != -foo... */
262 if (buf[0] != '-') {
263
264 foo.key = FUSE_OPT_KEY_NONOPT;
265 rv = proc(foo.data, foo.option, foo.key, args);
266 if (rv != 0)
267 break;
268
269 /* -o was specified... */
270 } else if (buf[0] == '-' && buf[1] == 'o') {
271
272 /* -oblah,foo... */
273 if (buf[2]) {
274 /* skip -o */
275 foo.option = args->argv[i] + 2;
276 /* -o blah,foo... */
277 } else {
278 /*
279 * skip current argv and pass to the
280 * next one to parse the options.
281 */
282 ++i;
283 foo.option = args->argv[i];
284 }
285
286 rv = fuse_opt_popt(&foo, opts);
287 if (rv != 0)
288 break;
289
290 /* help/version/verbose argument */
291 } else if (buf[0] == '-' && buf[1] != 'o') {
292 /*
293 * check if the argument matches
294 * with any template in opts.
295 */
296 rv = fuse_opt_popt(&foo, opts);
297 if (rv != 0) {
298 break;
299 } else {
300 DPRINTF(("%s: foo.fop->templ='%s' "
301 "foo.fop->offset: %d "
302 "foo.fop->value: %d\n",
303 __func__, foo.fop->templ,
304 foo.fop->offset, foo.fop->value));
305
306 /* argument needs to be discarded */
307 if (foo.key == FUSE_OPT_KEY_DISCARD) {
308 rv = 1;
309 break;
310 }
311
312 /* process help/version argument */
313 if (foo.key != KEY_VERBOSE &&
314 foo.key != FUSE_OPT_KEY_KEEP) {
315 rv = proc(foo.data, foo.option,
316 foo.key, args);
317 break;
318 } else {
319 /* process verbose argument */
320 rv = proc(foo.data, foo.option,
321 foo.key, args);
322 if (rv != 0)
323 break;
324 }
325 }
326 /* unknown option, how could that happen? */
327 } else {
328 DPRINTF(("%s: unknown option\n", __func__));
329 rv = 1;
330 break;
331 }
332 }
333
334 return rv;
335 }
336