Index: debug.c
===================================================================
RCS file: /cvs/src/lib/libfuse/debug.c,v
retrieving revision 1.1
diff -u -p -u -p -r1.1 debug.c
--- debug.c	3 Jun 2013 16:00:50 -0000	1.1
+++ debug.c	14 Oct 2017 01:08:55 -0000
@@ -20,21 +20,10 @@
 
 #include "debug.h"
 
-#ifdef DEBUG
-/*
- * debug level, -1 means uninitialized
- */
-int ifuse_debug = -1;
+int ifuse_debug = 0;
 
 void
 ifuse_debug_init(void)
 {
-	char *dbg;
-
-	if (ifuse_debug < 0) {
-		dbg = issetugid() ? NULL : getenv("FUSE_DEBUG");
-		if (!dbg || sscanf(dbg, "%u", &ifuse_debug) != 1)
-			ifuse_debug = 0;
-	}
+	ifuse_debug = 1;
 }
-#endif
Index: debug.h
===================================================================
RCS file: /cvs/src/lib/libfuse/debug.h,v
retrieving revision 1.1
diff -u -p -u -p -r1.1 debug.h
--- debug.h	3 Jun 2013 16:00:50 -0000	1.1
+++ debug.h	14 Oct 2017 01:08:55 -0000
@@ -17,32 +17,25 @@
 #ifndef _DEBUG_H_
 #define _DEBUG_H_
 
-#ifdef DEBUG
 #include <stdio.h>
 
-#define DPRINTFN(n, ...)					\
-	do {							\
-		if (ifuse_debug >= (n))				\
-			fprintf(stderr, __VA_ARGS__);		\
-	} while(0)
-
 #define DPRINTF(...)						\
 	do {							\
-		if (ifuse_debug > 0)				\
+		if (ifuse_debug)				\
 			fprintf(stderr, __VA_ARGS__);		\
 	} while(0)
 
+
+void ifuse_debug_init(void);
+extern int ifuse_debug;
+
+#ifdef DEBUG
 #define DPERROR(s)						\
 	do {							\
-		if (ifuse_debug > 0)				\
+		if (ifuse_debug)				\
 			perror(s);				\
 	} while(0)
-
-void ifuse_debug_init(void);
-extern int ifuse_debug;
 #else
-#define DPRINTF(...) do {} while(0)
-#define DPRINTFN(...) do {} while(0)
 #define DPERROR(s) do {} while(0)
 #endif
 
Index: fuse.c
===================================================================
RCS file: /cvs/src/lib/libfuse/fuse.c,v
retrieving revision 1.29
diff -u -p -u -p -r1.29 fuse.c
--- fuse.c	21 Aug 2017 21:41:13 -0000	1.29
+++ fuse.c	14 Oct 2017 01:08:55 -0000
@@ -40,6 +40,8 @@ enum {
 	KEY_HELP_WITHOUT_HEADER,
 	KEY_VERSION,
 	KEY_MAXREAD,
+	KEY_DEBUG,
+	KEY_FOREGROUND,
 	KEY_STUB
 };
 
@@ -50,17 +52,35 @@ static struct fuse_opt fuse_core_opts[] 
 	FUSE_OPT_KEY("-V",			KEY_VERSION),
 	FUSE_OPT_KEY("--version",		KEY_VERSION),
 	FUSE_OPT_KEY("max_read=",		KEY_MAXREAD),
-	FUSE_OPT_KEY("debug",			KEY_STUB),
-	FUSE_OPT_KEY("-d",			KEY_STUB),
-	FUSE_OPT_KEY("-f",			KEY_STUB),
+	FUSE_OPT_KEY("debug",			KEY_DEBUG),
+	FUSE_OPT_KEY("-d",			KEY_DEBUG),
+	FUSE_OPT_KEY("-f",			KEY_FOREGROUND),
 	FUSE_OPT_KEY("-s",			KEY_STUB),
 	FUSE_OPT_KEY("use_ino",			KEY_STUB),
 	FUSE_OPT_KEY("big_writes",		KEY_STUB),
 	FUSE_OPT_KEY("default_permissions",	KEY_STUB),
 	FUSE_OPT_KEY("fsname=",			KEY_STUB),
+	FUSE_OPT_KEY("-r",			KEY_STUB),
+	FUSE_OPT_KEY("ro",			KEY_STUB),
+	FUSE_OPT_KEY("ro_fallback",		KEY_STUB),
+	FUSE_OPT_KEY("kernel_cache",		KEY_STUB),
+	FUSE_OPT_KEY("attr_timeout=",		KEY_STUB),
+	FUSE_OPT_KEY("allow_other",		KEY_STUB),
+	FUSE_OPT_KEY("blkdev",			KEY_STUB),
+	FUSE_OPT_KEY("uid=",			KEY_STUB),
+	FUSE_OPT_KEY("gid=",			KEY_STUB),
+	FUSE_OPT_KEY("fmask=",			KEY_STUB),
+	FUSE_OPT_KEY("dmask=",			KEY_STUB),
+	FUSE_OPT_KEY("umask=",			KEY_STUB),
+	FUSE_OPT_KEY("blksize=",		KEY_STUB),
+	FUSE_OPT_KEY("noatime",			KEY_STUB),
+	FUSE_OPT_KEY("relatime",		KEY_STUB),
+	FUSE_OPT_KEY("nonempty",		KEY_STUB),
 	FUSE_OPT_END
 };
 
+static int ifuse_process_opt(void *, const char *, int, struct fuse_args *);
+
 int
 fuse_loop(struct fuse *fuse)
 {
@@ -150,11 +170,17 @@ fuse_loop(struct fuse *fuse)
 }
 
 struct fuse_chan *
-fuse_mount(const char *dir, unused struct fuse_args *args)
+fuse_mount(const char *dir, struct fuse_args *args)
 {
 	struct fusefs_args fargs;
 	struct fuse_chan *fc;
 	const char *errcause;
+	struct fuse_core_opt opt;
+
+	/* configuration passed by clients */
+	bzero(&opt, sizeof(opt));
+	if (fuse_opt_parse(args, &opt, fuse_core_opts, ifuse_process_opt) == -1)
+		return (NULL);
 
 	fc = calloc(1, sizeof(*fc));
 	if (fc == NULL)
@@ -207,7 +233,7 @@ fuse_unmount(const char *dir, unused str
 }
 
 int
-fuse_is_lib_option(unused const char *opt)
+fuse_is_lib_option(const char *opt)
 {
 	return (fuse_opt_match(fuse_core_opts, opt));
 }
@@ -237,6 +263,7 @@ fuse_new(struct fuse_chan *fc, unused st
 {
 	struct fuse *fuse;
 	struct fuse_vnode *root;
+	struct fuse_core_opt opt;
 
 	if ((fuse = calloc(1, sizeof(*fuse))) == NULL)
 		return (NULL);
@@ -249,6 +276,11 @@ fuse_new(struct fuse_chan *fc, unused st
 	fuse->se.args = fuse;
 	fuse->private_data = userdata;
 
+	/* configuration passed by clients */
+	bzero(&opt, sizeof(opt));
+	if (fuse_opt_parse(args, &opt, fuse_core_opts, ifuse_process_opt) == -1)
+		return (NULL);
+
 	if ((root = alloc_vn(fuse, "/", FUSE_ROOT_INO, 0)) == NULL) {
 		free(fuse);
 		return (NULL);
@@ -265,17 +297,16 @@ fuse_new(struct fuse_chan *fc, unused st
 }
 
 int
-fuse_daemonize(unused int foreground)
+fuse_daemonize(int foreground)
 {
-#ifdef DEBUG
-	return (daemon(0,1));
-#else
-	return (daemon(0,0));
-#endif
+	if (foreground)
+		return (0);
+
+	return (daemon(0, 0));
 }
 
 void
-fuse_destroy(unused struct fuse *f)
+fuse_destroy(struct fuse *f)
 {
 	close(f->fc->fd);
 	free(f->fc->dir);
@@ -374,6 +405,12 @@ ifuse_process_opt(void *data, const char
 			}
 			max_read = res;
 			break;
+		case KEY_DEBUG:
+			ifuse_debug_init();
+			/* falls through */
+		case KEY_FOREGROUND:
+			opt->foreground = 1;
+			break;
 		case FUSE_OPT_KEY_NONOPT:
 			if (opt->mp == NULL) {
 				opt->mp = realpath(arg, opt->mp);
@@ -404,19 +441,18 @@ ifuse_process_opt(void *data, const char
 			break;
 		default:
 			fprintf(stderr, "fuse: unknown option %s\n", arg);
-			return (-1);
+			/* Treat as a warning for now otherwise some clients
+			   won't work. */
+			/* return (-1); */
 	}
 	return (0);
 }
 
 int
-fuse_parse_cmdline(struct fuse_args *args, char **mp, int *mt, unused int *fg)
+fuse_parse_cmdline(struct fuse_args *args, char **mp, int *mt, int *fg)
 {
 	struct fuse_core_opt opt;
 
-#ifdef DEBUG
-	ifuse_debug_init();
-#endif
 	bzero(&opt, sizeof(opt));
 	if (fuse_opt_parse(args, &opt, fuse_core_opts, ifuse_process_opt) == -1)
 		return (-1);
@@ -430,6 +466,9 @@ fuse_parse_cmdline(struct fuse_args *arg
 	if (*mp == NULL)
 		return (-1);
 	*mt = 0;
+	*fg = opt.foreground;
+
+	free(opt.mp);
 
 	return (0);
 }
@@ -468,10 +507,11 @@ fuse_setup(int argc, char **argv, const 
 	struct fuse *fuse;
 	int fg;
 
+	*mp = NULL;
 	if (fuse_parse_cmdline(&args, mp, mt, &fg))
 		goto err;
 
-	fuse_daemonize(0);
+	fuse_daemonize(fg);
 
 	if ((fc = fuse_mount(*mp, NULL)) == NULL)
 		goto err;
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	14 Oct 2017 01:08:56 -0000
@@ -222,57 +222,71 @@ 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 +301,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 +314,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 +386,8 @@ err:
 	args->allocated = outargs.allocated;
 	args->argc = outargs.argc;
 	args->argv = outargs.argv;
+	if (ret != 0)
+		ret = -1;
 
 	return (ret);
 }
Index: fuse_private.h
===================================================================
RCS file: /cvs/src/lib/libfuse/fuse_private.h,v
retrieving revision 1.14
diff -u -p -u -p -r1.14 fuse_private.h
--- fuse_private.h	7 Sep 2016 17:53:35 -0000	1.14
+++ fuse_private.h	14 Oct 2017 01:08:56 -0000
@@ -74,7 +74,8 @@ struct fuse_config {
 };
 
 struct fuse_core_opt {
-	char *mp;
+	char			*mp;
+	int			foreground;
 };
 
 struct fuse {
