vm: fix a null dereference on out-of-memory
[minix.git] / lib / librefuse / refuse_opt.c
blob828dbe2c57655da4c014cf04edf31d465f62608a
1 /* $NetBSD: refuse_opt.c,v 1.14 2009/01/19 09:56:06 lukem Exp $ */
3 /*-
4 * Copyright (c) 2007 Juan Romero Pardines.
5 * All rights reserved.
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.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 * TODO:
30 * * -oblah,foo... works, but the options are not enabled.
31 * * -ofoo=%s (accepts a string) or -ofoo=%u (int) is not
32 * supported for now.
33 * * void *data: how is it used? I think it's used to enable
34 * options or pass values for the matching options.
37 #include <sys/types.h>
39 #include <err.h>
40 #include <fuse.h>
41 #include <fuse_opt.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
46 #ifdef FUSE_OPT_DEBUG
47 #define DPRINTF(x) do { printf x; } while ( /* CONSTCOND */ 0)
48 #else
49 #define DPRINTF(x)
50 #endif
52 enum {
53 KEY_HELP,
54 KEY_VERBOSE,
55 KEY_VERSION
58 struct fuse_opt_option {
59 const struct fuse_opt *fop;
60 char *option;
61 int key;
62 void *data;
65 static int fuse_opt_popt(struct fuse_opt_option *, const struct fuse_opt *);
67 /*
68 * Public API.
70 * The following functions always return 0:
72 * int fuse_opt_add_opt(char **, const char *);
74 * We implement the next ones:
76 * int fuse_opt_add_arg(struct fuse_args *, const char *);
77 * void fuse_opt_free_args(struct fuse_args *);
78 * int fuse_opt_insert_arg(struct fuse_args *, const char *);
79 * int fuse_opt_match(const struct fuse_opt *, const char *);
80 * int fuse_opt_parse(struct fuse_args *, void *,
81 * const struct fuse_opt *, fuse_opt_proc_t);
85 /* ARGSUSED */
86 int
87 fuse_opt_add_arg(struct fuse_args *args, const char *arg)
89 struct fuse_args *ap;
91 if (args->allocated == 0) {
92 ap = fuse_opt_deep_copy_args(args->argc, args->argv);
93 args->argv = ap->argv;
94 args->argc = ap->argc;
95 args->allocated = ap->allocated;
96 (void) free(ap);
97 } else if (args->allocated == args->argc) {
98 void *a;
99 int na = args->allocated + 10;
101 if ((a = realloc(args->argv, na * sizeof(*args->argv))) == NULL)
102 return -1;
104 args->argv = a;
105 args->allocated = na;
107 DPRINTF(("%s: arguments passed: [arg:%s]\n", __func__, arg));
108 if ((args->argv[args->argc++] = strdup(arg)) == NULL)
109 err(1, "fuse_opt_add_arg");
110 args->argv[args->argc] = NULL;
111 return 0;
114 struct fuse_args *
115 fuse_opt_deep_copy_args(int argc, char **argv)
117 struct fuse_args *ap;
118 int i;
120 if ((ap = malloc(sizeof(*ap))) == NULL)
121 err(1, "_fuse_deep_copy_args");
122 /* deep copy args structure into channel args */
123 ap->allocated = ((argc / 10) + 1) * 10;
125 if ((ap->argv = calloc((size_t)ap->allocated,
126 sizeof(*ap->argv))) == NULL)
127 err(1, "_fuse_deep_copy_args");
129 for (i = 0; i < argc; i++) {
130 if ((ap->argv[i] = strdup(argv[i])) == NULL)
131 err(1, "_fuse_deep_copy_args");
133 ap->argv[ap->argc = i] = NULL;
134 return ap;
137 void
138 fuse_opt_free_args(struct fuse_args *ap)
140 int i;
142 for (i = 0; i < ap->argc; i++) {
143 free(ap->argv[i]);
145 free(ap->argv);
146 ap->argv = NULL;
147 ap->allocated = ap->argc = 0;
150 /* ARGSUSED */
152 fuse_opt_insert_arg(struct fuse_args *args, int pos, const char *arg)
154 int i;
155 int na;
156 void *a;
158 DPRINTF(("%s: arguments passed: [pos=%d] [arg=%s]\n",
159 __func__, pos, arg));
160 if (args->argv == NULL) {
161 na = 10;
162 a = malloc(na * sizeof(*args->argv));
163 } else {
164 na = args->allocated + 10;
165 a = realloc(args->argv, na * sizeof(*args->argv));
167 if (a == NULL) {
168 warn("fuse_opt_insert_arg");
169 return -1;
171 args->argv = a;
172 args->allocated = na;
174 for (i = args->argc++; i > pos; --i) {
175 args->argv[i] = args->argv[i - 1];
177 if ((args->argv[pos] = strdup(arg)) == NULL)
178 err(1, "fuse_opt_insert_arg");
179 args->argv[args->argc] = NULL;
180 return 0;
183 /* ARGSUSED */
184 int fuse_opt_add_opt(char **opts, const char *opt)
186 DPRINTF(("%s: arguments passed: [opts=%s] [opt=%s]\n",
187 __func__, *opts, opt));
188 return 0;
192 * Returns 0 if opt was matched with any option from opts,
193 * otherwise returns 1.
196 fuse_opt_match(const struct fuse_opt *opts, const char *opt)
198 while (opts++) {
199 if (strcmp(opt, opts->templ) == 0)
200 return 0;
203 return 1;
207 * Returns 0 if foo->option was matched with any option from opts,
208 * and sets the following on match:
210 * * foo->key is set to the foo->fop->value if offset == -1.
211 * * foo->fop points to the matched struct opts.
213 * otherwise returns 1.
215 static int
216 fuse_opt_popt(struct fuse_opt_option *foo, const struct fuse_opt *opts)
218 int i, found = 0;
219 char *match;
221 if (!foo->option) {
222 (void)fprintf(stderr, "fuse: missing argument after -o\n");
223 return 1;
226 * iterate over argv and opts to see
227 * if there's a match with any template.
229 for (match = strtok(foo->option, ",");
230 match; match = strtok(NULL, ",")) {
232 DPRINTF(("%s: specified option='%s'\n", __func__, match));
233 found = 0;
235 for (i = 0; opts && opts->templ; opts++, i++) {
237 DPRINTF(("%s: opts->templ='%s' opts->offset=%d "
238 "opts->value=%d\n", __func__, opts->templ,
239 opts->offset, opts->value));
241 /* option is ok */
242 if (strcmp(match, opts->templ) == 0) {
243 DPRINTF(("%s: option matched='%s'\n",
244 __func__, match));
245 found++;
247 * our fop pointer now points
248 * to the matched struct opts.
250 foo->fop = opts;
252 * assign default key value, necessary for
253 * KEY_HELP, KEY_VERSION and KEY_VERBOSE.
255 if (foo->fop->offset == -1)
256 foo->key = foo->fop->value;
257 /* reset counter */
258 opts -= i;
259 break;
262 /* invalid option */
263 if (!found) {
264 (void)fprintf(stderr, "fuse: '%s' is not a "
265 "valid option\n", match);
266 return 1;
270 return 0;
273 /* ARGSUSED1 */
275 fuse_opt_parse(struct fuse_args *args, void *data,
276 const struct fuse_opt *opts, fuse_opt_proc_t proc)
278 struct fuse_opt_option foo;
279 char *buf;
280 int i, rv = 0;
282 memset(&foo, '\0', sizeof(foo));
284 if (!args || !args->argv || !args->argc || !proc)
285 return 0;
287 if (args->argc == 1)
288 return proc(foo.data, *args->argv, FUSE_OPT_KEY_OPT, args);
290 /* the real loop to process the arguments */
291 for (i = 1; i < args->argc; i++) {
293 /* assign current argv string */
294 foo.option = buf = args->argv[i];
296 /* argvn != -foo... */
297 if (buf[0] != '-') {
299 foo.key = FUSE_OPT_KEY_NONOPT;
300 rv = proc(foo.data, foo.option, foo.key, args);
301 if (rv != 0)
302 break;
304 /* -o was specified... */
305 } else if (buf[0] == '-' && buf[1] == 'o') {
307 /* -oblah,foo... */
308 if (buf[2]) {
309 /* skip -o */
310 foo.option = args->argv[i] + 2;
311 /* -o blah,foo... */
312 } else {
314 * skip current argv and pass to the
315 * next one to parse the options.
317 ++i;
318 foo.option = args->argv[i];
321 rv = fuse_opt_popt(&foo, opts);
322 if (rv != 0)
323 break;
325 /* help/version/verbose argument */
326 } else if (buf[0] == '-' && buf[1] != 'o') {
328 * check if the argument matches
329 * with any template in opts.
331 rv = fuse_opt_popt(&foo, opts);
332 if (rv != 0) {
333 break;
334 } else {
335 DPRINTF(("%s: foo.fop->templ='%s' "
336 "foo.fop->offset: %d "
337 "foo.fop->value: %d\n",
338 __func__, foo.fop->templ,
339 foo.fop->offset, foo.fop->value));
341 /* argument needs to be discarded */
342 if (foo.key == FUSE_OPT_KEY_DISCARD) {
343 rv = 1;
344 break;
347 /* process help/version argument */
348 if (foo.key != KEY_VERBOSE &&
349 foo.key != FUSE_OPT_KEY_KEEP) {
350 rv = proc(foo.data, foo.option,
351 foo.key, args);
352 break;
353 } else {
354 /* process verbose argument */
355 rv = proc(foo.data, foo.option,
356 foo.key, args);
357 if (rv != 0)
358 break;
361 /* unknown option, how could that happen? */
362 } else {
363 DPRINTF(("%s: unknown option\n", __func__));
364 rv = 1;
365 break;
369 return rv;