The fuse_opt_match(3) library function does not match options correctly.
authorhelg <helg@openbsd.org>
Mon, 11 Dec 2017 12:01:55 +0000 (12:01 +0000)
committerhelg <helg@openbsd.org>
Mon, 11 Dec 2017 12:01:55 +0000 (12:01 +0000)
libfuse supports option templates of the following form that can be used
to automatically parse arguments supplied on the command line.

"-p "       argument that takes an option e.g -p 22 or -p22
"-p %x"     argument that takes an option parsed like sscanf(3)
"cache=yes" matches -ocache=yes or -o cache=yes
"cache=%s"  matches -ocache=<string> or -o cache=<string>
"cache="    matches same as above but value is passed to option proc
"noatime"   matches -onoatime or -o atime

For example, it does not match options of the form "-p 22" or
"cache=yes" to the corresponding templates "-p " and "cache=yes".  This
patch fixes that and updates the regression tests accordingly.

ok mpi@

lib/libfuse/fuse_opt.c
regress/lib/libfuse/fuse-opt-match.c

index 873b338..0b026cc 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: fuse_opt.c,v 1.19 2017/11/16 12:56:58 helg Exp $ */
+/* $OpenBSD: fuse_opt.c,v 1.20 2017/12/11 12:01:55 helg Exp $ */
 /*
  * Copyright (c) 2013 Sylvestre Gallon <ccna.syl@gmail.com>
  * Copyright (c) 2013 Stefan Sperling <stsp@openbsd.org>
@@ -67,73 +67,35 @@ alloc_argv(struct fuse_args *args)
        return (0);
 }
 
-static int
+/*
+ * Returns the number of characters that matched for bounds checking later.
+ */
+static size_t
 match_opt(const char *templ, const char *opt)
 {
-       const char *o, *t;
-       char *arg;
-
-       arg = strpbrk(templ, " =");
-
-       /* verify template */
-       t = templ;
-       if (*t == '-') {
-               t++;
-               if (*t == '-')
-                       t++;
-               if (*t == 'o' || *t == '\0')
-                       return (0);
-       }
+       size_t sep, len;
 
-       /* skip leading -, -o, and -- in option name */
-       o = opt;
-       if (*o == '-') {
-               o++;
-               if (*o == 'o' || *o == '-')
-                       o++;
-       }
+       len = strlen(templ);
+       sep = strcspn(templ, "=");
 
-       /* empty option name is invalid */
-       if (*o == '\0')
-               return (0);
+       if (sep == len)
+               sep = strcspn(templ, " ");
 
-       /* match option name */
-       while (*t && *o) {
-               if (*t++ != *o++)
+       /* key=, key=%, "-k ", -k % */
+       if (sep < len && (templ[sep + 1] == '\0' || templ[sep + 1] == '%')) {
+               if (strncmp(opt, templ, sep) == 0)
+                       return (sep);
+               else
                        return (0);
-               if (arg && t == arg) {
-                       if (*o != ' ' && *o != '=')
-                               return (0);
-                       o++; /* o now points at argument */
-                       if (*o == '\0')
-                               return (0);
-                       break;
-               }
        }
 
-       /* match argument */
-       if (arg) {
-               if (t != arg)
-                       return (0);
-               t++;
-               /* does template have an argument? */
-               if (*t != '%' && *t != '\0')
-                       return (0);
-               if (*t == '%' && t[1] == '\0')
-                       return (0);
-               /* yes it does, consume argument in opt */
-               while (*o && *o != ' ')
-                       o++;
-       } else if (*t != '\0')
-               return (0);
+       if (strcmp(opt, templ) == 0)
+               return (len);
 
-       /* we should have consumed entire opt string */
-       if (*o != '\0')
-               return (0);
-
-       return (1);
+       return (0);
 }
 
+
 static int
 add_opt(char **opts, const char *opt)
 {
index 71daa02..830f456 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) Sylvestre Gallon <ccna.syl@gmail.com>
+ * Copyright (c) 2017 Helg Bredow <xx404@msn.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <string.h>
+#include <assert.h>
+#include <stddef.h>
 #include <fuse_opt.h>
 
-const struct fuse_opt nullopts[] = {
+static const struct fuse_opt emptyopts[] = {
        FUSE_OPT_END
 };
 
-const int nullresults[] = {
-       0, 0, 0, 0, 0, 0
-};
-
-const struct fuse_opt badopts[] = {
-       FUSE_OPT_KEY("-p ", 0),
-       FUSE_OPT_KEY("-C", 1),
-       FUSE_OPT_KEY("-V", 3),
-       FUSE_OPT_KEY("--version", 3),
-       FUSE_OPT_KEY("-h", 2),
+static const struct fuse_opt opts[] = {
+       FUSE_OPT_KEY("-p ",             FUSE_OPT_KEY_DISCARD),
+       FUSE_OPT_KEY("-C",              FUSE_OPT_KEY_DISCARD),
+       FUSE_OPT_KEY("-V",              FUSE_OPT_KEY_DISCARD),
+       FUSE_OPT_KEY("--version",       FUSE_OPT_KEY_DISCARD),
+       FUSE_OPT_KEY("-h",              FUSE_OPT_KEY_DISCARD),
+       FUSE_OPT_KEY("const=false",     FUSE_OPT_KEY_DISCARD),
+       FUSE_OPT_KEY("cache=no",        FUSE_OPT_KEY_DISCARD),
+       FUSE_OPT_KEY("cache=yes",       FUSE_OPT_KEY_DISCARD),
+       FUSE_OPT_KEY("debug",           FUSE_OPT_KEY_DISCARD),
+       FUSE_OPT_KEY("ro",              FUSE_OPT_KEY_DISCARD),
+       FUSE_OPT_KEY("--foo=",          FUSE_OPT_KEY_DISCARD),
+       FUSE_OPT_KEY("bars=%s",         FUSE_OPT_KEY_DISCARD),
+       FUSE_OPT_KEY("--fool=%lu",      FUSE_OPT_KEY_DISCARD),
+       FUSE_OPT_KEY("-x ",             FUSE_OPT_KEY_DISCARD),
+       FUSE_OPT_KEY("-n %u",           FUSE_OPT_KEY_DISCARD),
+       FUSE_OPT_KEY("-P",              FUSE_OPT_KEY_DISCARD),
        FUSE_OPT_END
 };
 
-static int
-match_opts(const struct fuse_opt *opts, const int *results)
+int
+main(void)
 {
-       if (fuse_opt_match(opts, NULL) != 0)
-               return (1);
+       assert(fuse_opt_match(emptyopts, "debug")       ==      0);
 
-       if (fuse_opt_match(opts, "bar=") != results[0])
-               return (3);
-       if (fuse_opt_match(opts, "--foo=") != results[1])
-               return (4);
-       if (fuse_opt_match(opts, "bar=%s") != results[2])
-               return (5);
-       if (fuse_opt_match(opts, "--foo=%lu") != results[3])
-               return (6);
-       if (fuse_opt_match(opts, "-x ") != results[4])
-               return (7);
-       if (fuse_opt_match(opts, "-x %s") != results[5])
-               return (8);
+       assert(fuse_opt_match(opts, NULL)               ==      0);
+       assert(fuse_opt_match(opts, "-p ")              ==      1);
+       assert(fuse_opt_match(opts, "-C")               ==      1);
+       assert(fuse_opt_match(opts, "-c")               ==      0);
+       assert(fuse_opt_match(opts, "-V")               ==      1);
+       assert(fuse_opt_match(opts, "--version")        ==      1);
+       assert(fuse_opt_match(opts, "-h")               ==      1);
+       assert(fuse_opt_match(opts, "const=false")      ==      1);
+       assert(fuse_opt_match(opts, "const=falsefalse") ==      0);
+       assert(fuse_opt_match(opts, "cache=no")         ==      1);
+       assert(fuse_opt_match(opts, "cache=yes")        ==      1);
+       assert(fuse_opt_match(opts, "debug")            ==      1);
+       assert(fuse_opt_match(opts, "ro")               ==      1);
+       assert(fuse_opt_match(opts, "ro_fallback")      ==      0);
+       assert(fuse_opt_match(opts, "--foo=bar")        ==      1);
+       assert(fuse_opt_match(opts, "bars=foo")         ==      1);
+       assert(fuse_opt_match(opts, "--fool=bool")      ==      1);
+       assert(fuse_opt_match(opts, "--fool=1")         ==      1);
+       assert(fuse_opt_match(opts, "-x bar")           ==      1);
+       assert(fuse_opt_match(opts, "-xbar")            ==      1);
+       assert(fuse_opt_match(opts, "-n 100")           ==      1);
+       assert(fuse_opt_match(opts, "-n100")            ==      1);
+       assert(fuse_opt_match(opts, "-P")               ==      1);
 
        return (0);
 }
-
-int
-main(int ac, char **av)
-{
-       if (match_opts(nullopts, nullresults) != 0)
-               return (1);
-       if (match_opts(badopts, nullresults) != 0)
-               return (1);
-       return (0);
-}
-