summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhelg <helg@cvs.openbsd.org>2017-11-16 12:56:59 +0000
committerhelg <helg@cvs.openbsd.org>2017-11-16 12:56:59 +0000
commit62c104a44777cfc7f985e86a02ba0bcece9f2250 (patch)
tree967ba12383c483986e4301e75190632436e470b6
parent2cc18429c6e0c7e9607b079668fd2535ad6b78ac (diff)
Add support for:
multiple options after -o. arguments that require options e.g. -p 22 %s, %lu, %u option templates ok mpi@
-rw-r--r--lib/libfuse/fuse_opt.c146
1 files changed, 101 insertions, 45 deletions
diff --git a/lib/libfuse/fuse_opt.c b/lib/libfuse/fuse_opt.c
index e1c065ea703..873b3380399 100644
--- a/lib/libfuse/fuse_opt.c
+++ b/lib/libfuse/fuse_opt.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: fuse_opt.c,v 1.18 2017/01/04 12:01:22 stsp Exp $ */
+/* $OpenBSD: fuse_opt.c,v 1.19 2017/11/16 12:56:58 helg Exp $ */
/*
* Copyright (c) 2013 Sylvestre Gallon <ccna.syl@gmail.com>
* Copyright (c) 2013 Stefan Sperling <stsp@openbsd.org>
@@ -25,6 +25,10 @@
#include "fuse_opt.h"
#include "fuse_private.h"
+#define IFUSE_OPT_DISCARD 0
+#define IFUSE_OPT_KEEP 1
+#define IFUSE_OPT_NEED_ANOTHER_ARG 2
+
static void
free_argv(char **argv, int argc)
{
@@ -222,57 +226,66 @@ 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;
+ if (o == NULL)
+ return IFUSE_OPT_KEEP;
- /* check if it is a key=value entry */
- idx = strcspn(val, "=");
- if (idx != strlen(val)) {
- idx++;
- keyval = 1;
- }
+ 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 IFUSE_OPT_NEED_ANOTHER_ARG;
+ } else if (strchr(o->templ, '%') != NULL) {
+ val = &val[idx];
+ }
+ }
+
if (o->val == FUSE_OPT_KEY_DISCARD)
- return (1);
+ return (IFUSE_OPT_DISCARD);
+
+ if (o->val == FUSE_OPT_KEY_KEEP)
+ return (IFUSE_OPT_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 IFUSE_OPT_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 (IFUSE_OPT_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 (IFUSE_OPT_KEEP);
}
/*
@@ -287,11 +300,12 @@ fuse_opt_parse(struct fuse_args *args, void *data,
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,68 @@ fuse_opt_parse(struct fuse_args *args, void *data,
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 = IFUSE_OPT_KEEP;
+ else
+ ret = f(data, arg, FUSE_OPT_KEY_NONOPT, &outargs);
- if (ret == 1)
+ if (ret == IFUSE_OPT_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 == IFUSE_OPT_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 == IFUSE_OPT_KEEP)
+ fuse_opt_add_arg(&outargs, arg);
+ else if (ret == IFUSE_OPT_NEED_ANOTHER_ARG) {
+ /* arg needs a value */
+ if (++i >= args->argc) {
+ fprintf(stderr, "fuse: missing argument after %s\n", arg);
+ goto err;
+ }
+
+ if (asprintf(&tofree, "%s%s", arg,
+ args->argv[i]) == -1)
+ goto err;
+
+ ret = parse_opt(opt, tofree, data, f, &outargs);
+ if (ret == IFUSE_OPT_KEEP)
+ fuse_opt_add_arg(&outargs, tofree);
+ free(tofree);
+ }
+
if (ret == -1)
goto err;
}
@@ -333,6 +387,8 @@ err:
args->allocated = outargs.allocated;
args->argc = outargs.argc;
args->argv = outargs.argv;
+ if (ret != 0)
+ ret = -1;
return (ret);
}