On Mon, 16 Oct 2017 15:33:45 +0200
Martin Pieuchot <m...@openbsd.org> wrote:

> On 14/10/17(Sat) 01:23, Helg Bredow wrote:
> > The attached patch vastly improves fuse argument and option parsing. For 
> > example, all sshfs options will now be parsed successfully. It's a 
> > substantial patch and can't be easily broken down further.
> > 
> > In addition, this also adds support for the -d and -odebug options.
> > 
> > I've also included a regression test that confirms it's working as intended.
> > 
> > The only contentious part of the patch is that fuse no longer fails if it 
> > doesn't recognise an argument or option, it only prints a message to 
> > stdout. This is because fuse file systems can pass additional options to 
> > fuse and most are not supported and/or recognised yet and this would 
> > prevent those file systems from running.
> > 
> > I'm happy to take feedback and recommendations.
> 
> Your diffs are good but it would be easier if you could submit one diff
> per issue.
> 
> For example, split the debug part, the foreground part, the options and
> the regress.  This will allow us to integrate some non contentious part
> of your diff then discuss the rest.
> 
> You also want to have a look at /usr/lib/check_sym since you're adding
> new symbols to the library.

I've split the patch. This one improves argument and option parsing so that 
almost all sshfs arguments and options will now parse. It won't recognise 
-ocache=no since fuse_opt_match() is incorrect (fuse will treat it the same as 
-ocache=yes). I'll submit a patch for that some other time.

Running check_sym tells me:

No dynamic export changes
External reference changes:
added:
        atoi
        strchr
        strsep
        strstr
        strtoul

I take that to mean that there is no need to bump the major or minor version 
for this patch. Is that correct?

Index: fuse_opt.c
===================================================================
RCS file: /cvs/src/lib/libfuse/fuse_opt.c,v
retrieving revision 1.18
diff -u -p -u -p -r1.18 fuse_opt.c
--- fuse_opt.c  4 Jan 2017 12:01:22 -0000       1.18
+++ fuse_opt.c  17 Oct 2017 13:57:35 -0000
@@ -222,57 +222,70 @@ static int
 parse_opt(const struct fuse_opt *o, const char *val, void *data,
     fuse_opt_proc_t f, struct fuse_args *arg)
 {
-       int found, ret, keyval;
+       int keyval;
        size_t idx;
 
-       ret = 0;
-       found = 0;
-       keyval = 0;
+#define DISCARD 0
+#define KEEP 1
+#define NEED_ANOTHER_ARG 2
 
-       /* check if it is a key=value entry */
-       idx = strcspn(val, "=");
-       if (idx != strlen(val)) {
-               idx++;
-               keyval = 1;
-       }
+       if (o == NULL)
+               return KEEP;
+
+       keyval = 0;
 
        for(; o->templ; o++) {
-               if ((keyval && strncmp(val, o->templ, idx) == 0) ||
-                   (!keyval && strcmp(val, o->templ) == 0)) {
+               /* check key=value or -p n */
+               idx = strcspn(o->templ, "= ");
+
+               if (strncmp(val, o->templ, idx) == 0) {
+                       if (o->templ[idx] == '=') {
+                               keyval = 1;
+                               val = &val[idx + 1];
+                       } else if (o->templ[idx] == ' ') {
+                               keyval = 1;
+                               if (idx == strlen(val)) {
+                                       /* ask for next arg to be included */
+                                       return NEED_ANOTHER_ARG;
+                               } else if (strchr(o->templ, '%') != NULL) {
+                                       val = &val[idx];
+                               }
+                       }
+
                        if (o->val == FUSE_OPT_KEY_DISCARD)
-                               return (1);
+                               return (DISCARD);
+
+                       if (o->val == FUSE_OPT_KEY_KEEP)
+                               return (KEEP);
 
                        if (FUSE_OPT_IS_OPT_KEY(o)) {
-                               if (keyval)
-                                       ret = f(data, &val[idx], o->val, arg);
-                               else
-                                       ret = f(data, val, o->val, arg);
-                       }
+                               if (f == NULL)
+                                       return KEEP;
 
-                       if (o->off != ULONG_MAX && data && o->val >= 0) {
-                               ret = f(data, val, o->val, arg);
-                               int *addr = (int *)(data + o->off);
-                               *addr = o->val;
-                               ret = 0;
+                               return f(data, val, o->val, arg);
+                       } else if (data == NULL) {
+                               return -1;
+                       } else if (strchr(o->templ, '%') == NULL) {
+                               *((int *)(data + o->off)) = o->val;
+                       } else if (strstr(o->templ, "%u") != NULL) {
+                               *((unsigned int*)(data + o->off)) = atoi(val);
+                       } else if (strstr(o->templ, "%lu") != NULL) {
+                               *((unsigned long*)(data + o->off)) =
+                                   strtoul(val, NULL, 0);
+                       } else if (strstr(o->templ, "%s") != NULL) {
+                               *((char **)(data + o->off)) = strdup(val);
+                       } else {
+                               /* TODO other parameterised templates */
                        }
 
-                       if (ret == -1)
-                               return (ret);
-                       if (ret == 1)
-                               fuse_opt_add_arg(arg, val);
-                       found++;
-                       break;
+                       return DISCARD;
                }
        }
 
-       if (!found) {
-               ret = f(data, val, FUSE_OPT_KEY_OPT, arg);
-               if (ret == 1)
-                       fuse_opt_add_arg(arg, val);
-               return (ret);
-       }
+       if (f != NULL)
+               return f(data, val, FUSE_OPT_KEY_OPT, arg);
 
-       return (ret);
+       return (KEEP);
 }
 
 /*
@@ -287,11 +300,12 @@ fuse_opt_parse(struct fuse_args *args, v
     const struct fuse_opt *opt, fuse_opt_proc_t f)
 {
        struct fuse_args outargs;
-       const char *arg;
-       int ret = 0;
+       const char *arg, *ap;
+       char *optlist, *tofree;
+       int ret;
        int i;
 
-       if (!f || !args || !args->argc || !args->argv)
+       if (!args || !args->argc || !args->argv)
                return (0);
 
        bzero(&outargs, sizeof(outargs));
@@ -299,28 +313,66 @@ fuse_opt_parse(struct fuse_args *args, v
 
        for (i = 1; i < args->argc; i++) {
                arg = args->argv[i];
+               ret = 0;
 
                /* not - and not -- */
                if (arg[0] != '-') {
-                       ret = f(data, arg, FUSE_OPT_KEY_NONOPT, &outargs);
+                       if (f == NULL)
+                               ret = KEEP;
+                       else
+                               ret = f(data, arg, FUSE_OPT_KEY_NONOPT, 
&outargs);
 
-                       if (ret == 1)
+                       if (ret == KEEP)
                                fuse_opt_add_arg(&outargs, arg);
                        if (ret == -1)
                                goto err;
                } else if (arg[1] == 'o') {
                        if (arg[2])
                                arg += 2;       /* -ofoo,bar */
-                       else
-                               arg = args->argv[++i];
+                       else {
+                               if (++i >= args->argc)
+                                       goto err;
 
-                       ret = parse_opt(opt, arg, data, f, &outargs);
+                               arg = args->argv[i];
+                       }
+
+                       tofree = optlist = strdup(arg);
+                       if (optlist == NULL)
+                               goto err;
+
+                       while ((ap = strsep(&optlist, ",")) != NULL &&
+                           ret != -1) {
+                               ret = parse_opt(opt, ap, data, f, &outargs);
+                               if (ret == KEEP) {
+                                       fuse_opt_add_arg(&outargs, "-o");
+                                       fuse_opt_add_arg(&outargs, ap);
+                               }
+                       }
+
+                       free(tofree);
 
                        if (ret == -1)
                                goto err;
                } else {
                        ret = parse_opt(opt, arg, data, f, &outargs);
 
+                       if (ret == KEEP)
+                               fuse_opt_add_arg(&outargs, arg);
+                       else if (ret == NEED_ANOTHER_ARG) {
+                               /* arg needs a value */
+                               if (++i >= args->argc)
+                                       goto err;
+
+                               if (asprintf(&tofree, "%s%s", arg,
+                                   args->argv[i]) == -1)
+                                       goto err;
+
+                               ret = parse_opt(opt, tofree, data, f, &outargs);
+                               if (ret == KEEP)
+                                       fuse_opt_add_arg(&outargs, tofree);
+                               free(tofree);
+                       }
+
                        if (ret == -1)
                                goto err;
                }
@@ -333,6 +385,8 @@ err:
        args->allocated = outargs.allocated;
        args->argc = outargs.argc;
        args->argv = outargs.argv;
+       if (ret != 0)
+               ret = -1;
 
        return (ret);
 }

Reply via email to