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); }