summaryrefslogtreecommitdiff
path: root/lib/libfuse
diff options
context:
space:
mode:
authorhelg <helg@cvs.openbsd.org>2017-12-18 11:41:42 +0000
committerhelg <helg@cvs.openbsd.org>2017-12-18 11:41:42 +0000
commitad5c46e07a2a909bd57428057f0606290fb179a8 (patch)
tree1842ec5ca4da3e33f890237bfc6c120019aa8b0b /lib/libfuse
parentaf48e56db754e01980c40e4ed72c36f524eb814d (diff)
Refactor libfuse option processing to better support options in the
future. Immediate benefits are that gid, uid and umask are now supported and max_read is now honoured for all file systems. Mounting read_only is now possible but requires more thorough testing. ok mpi@
Diffstat (limited to 'lib/libfuse')
-rw-r--r--lib/libfuse/fuse.c229
-rw-r--r--lib/libfuse/fuse_private.h13
2 files changed, 169 insertions, 73 deletions
diff --git a/lib/libfuse/fuse.c b/lib/libfuse/fuse.c
index 2b9f9e58172..cd7773b4c42 100644
--- a/lib/libfuse/fuse.c
+++ b/lib/libfuse/fuse.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: fuse.c,v 1.41 2017/12/15 16:40:33 jca Exp $ */
+/* $OpenBSD: fuse.c,v 1.42 2017/12/18 11:41:41 helg Exp $ */
/*
* Copyright (c) 2013 Sylvestre Gallon <ccna.syl@gmail.com>
*
@@ -23,6 +23,7 @@
#include <errno.h>
#include <signal.h>
+#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
@@ -34,7 +35,6 @@
static volatile sig_atomic_t sigraised = 0;
static volatile sig_atomic_t signum = 0;
static struct fuse_context *ictx = NULL;
-static int max_read = FUSEBUFMAXSIZE;
enum {
KEY_DEBUG,
@@ -46,21 +46,72 @@ enum {
KEY_STUB
};
+/* options supported by fuse_parse_cmdline */
static struct fuse_opt fuse_core_opts[] = {
+ FUSE_OPT_KEY("-d", KEY_DEBUG),
+ FUSE_OPT_KEY("debug", KEY_DEBUG),
+ FUSE_OPT_KEY("-f", KEY_FOREGROUND),
FUSE_OPT_KEY("-h", KEY_HELP),
FUSE_OPT_KEY("--help", KEY_HELP),
FUSE_OPT_KEY("-ho", KEY_HELP_WITHOUT_HEADER),
+ FUSE_OPT_KEY("-s", KEY_STUB),
FUSE_OPT_KEY("-V", KEY_VERSION),
FUSE_OPT_KEY("--version", KEY_VERSION),
- FUSE_OPT_KEY("max_read=", KEY_MAXREAD),
+ FUSE_OPT_END
+};
+
+/* options supported by fuse_new */
+#define FUSE_LIB_OPT(o, m) {o, offsetof(struct fuse_config, m), 1}
+static struct fuse_opt fuse_lib_opts[] = {
+ FUSE_OPT_KEY("ac_attr_timeout=", KEY_STUB),
+ FUSE_OPT_KEY("allow_other", KEY_STUB),
+ FUSE_OPT_KEY("allow_root", KEY_STUB),
+ FUSE_OPT_KEY("attr_timeout=", KEY_STUB),
+ FUSE_OPT_KEY("auto_cache", KEY_STUB),
+ FUSE_OPT_KEY("noauto_cache", KEY_STUB),
+ FUSE_OPT_KEY("big_writes", 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("entry_timeout=", KEY_STUB),
+ FUSE_LIB_OPT("gid=", set_gid),
+ FUSE_LIB_OPT("gid=%u", gid),
+ FUSE_OPT_KEY("hard_remove", KEY_STUB),
+ FUSE_OPT_KEY("intr_signal", KEY_STUB),
+ FUSE_OPT_KEY("kernel_cache", KEY_STUB),
+ FUSE_OPT_KEY("large_read", KEY_STUB),
+ FUSE_OPT_KEY("modules=", KEY_STUB),
+ FUSE_OPT_KEY("negative_timeout=", KEY_STUB),
+ FUSE_OPT_KEY("readdir_ino", KEY_STUB),
+ FUSE_OPT_KEY("relatime", KEY_STUB),
+ FUSE_OPT_KEY("subtype=", KEY_STUB),
+ FUSE_LIB_OPT("uid=", set_uid),
+ FUSE_LIB_OPT("uid=%u", uid),
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("dmask=%o", KEY_STUB),
+ FUSE_OPT_KEY("fmask=%o", KEY_STUB),
+ FUSE_LIB_OPT("umask=", set_mode),
+ FUSE_LIB_OPT("umask=%o", umask),
+ FUSE_OPT_END
+};
+
+/* options supported by fuse_mount */
+#define FUSE_MOUNT_OPT(o, m) {o, offsetof(struct fuse_mount_opts, m), 1}
+static struct fuse_opt fuse_mount_opts[] = {
+ FUSE_OPT_KEY("async_read", KEY_STUB),
+ FUSE_OPT_KEY("blkdev", KEY_STUB),
+ FUSE_OPT_KEY("blksize=", KEY_STUB),
+ FUSE_MOUNT_OPT("default_permissions", def_perms),
+ FUSE_OPT_KEY("direct_io", KEY_STUB),
+ FUSE_MOUNT_OPT("fsname=%s", fsname),
+ FUSE_MOUNT_OPT("max_read=%u", max_read),
+ FUSE_OPT_KEY("max_readahead", KEY_STUB),
+ FUSE_OPT_KEY("max_write", KEY_STUB),
+ FUSE_MOUNT_OPT("noatime", noatime),
+ FUSE_MOUNT_OPT("nonempty", nonempty),
+ FUSE_MOUNT_OPT("-r", rdonly),
+ FUSE_MOUNT_OPT("ro", rdonly),
+ FUSE_OPT_KEY("ro_fallback", KEY_STUB),
+ FUSE_OPT_KEY("sync_read", KEY_STUB),
FUSE_OPT_END
};
@@ -221,11 +272,13 @@ fuse_loop(struct fuse *fuse)
DEF(fuse_loop);
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_mount_opts opts;
struct fuse_chan *fc;
const char *errcause;
+ int mnt_flags;
if (dir == NULL)
return (NULL);
@@ -243,9 +296,27 @@ fuse_mount(const char *dir, unused struct fuse_args *args)
goto bad;
}
+ bzero(&opts, sizeof(opts));
+ if (fuse_opt_parse(args, &opts, fuse_mount_opts, NULL) == -1)
+ goto bad;
+
+ mnt_flags = 0;
+ if (opts.rdonly)
+ mnt_flags |= MNT_RDONLY;
+ if (opts.noatime)
+ mnt_flags |= MNT_NOATIME;
+
+ if (opts.max_read > FUSEBUFMAXSIZE) {
+ fprintf(stderr, "fuse: invalid max_read (%d > %d)\n",
+ opts.max_read, FUSEBUFMAXSIZE);
+ goto bad;
+ }
+
+ bzero(&fargs, sizeof(fargs));
fargs.fd = fc->fd;
- fargs.max_read = max_read;
- if (mount(MOUNT_FUSEFS, fc->dir, 0, &fargs)) {
+ fargs.max_read = opts.max_read;
+
+ if (mount(MOUNT_FUSEFS, fc->dir, mnt_flags, &fargs)) {
switch (errno) {
case EMFILE:
errcause = "mount table full";
@@ -285,7 +356,7 @@ DEF(fuse_unmount);
int
fuse_is_lib_option(const char *opt)
{
- return (fuse_opt_match(fuse_core_opts, opt));
+ return (fuse_opt_match(fuse_lib_opts, opt));
}
int
@@ -310,8 +381,27 @@ fuse_loop_mt(unused struct fuse *fuse)
return (-1);
}
+static int
+ifuse_lib_opt_proc(void *data, const char *arg, int key,
+ unused struct fuse_args *args)
+{
+ switch (key) {
+ case KEY_STUB:
+ return (0);
+ case KEY_DEBUG:
+ ifuse_debug_init();
+ break;
+ default:
+ fprintf(stderr, "fuse: unrecognised option %s\n", arg);
+ return (-1);
+ }
+
+ /* Keep unknown options. */
+ return (1);
+}
+
struct fuse *
-fuse_new(struct fuse_chan *fc, unused struct fuse_args *args,
+fuse_new(struct fuse_chan *fc, struct fuse_args *args,
const struct fuse_operations *ops, unused size_t size,
void *userdata)
{
@@ -327,6 +417,12 @@ fuse_new(struct fuse_chan *fc, unused struct fuse_args *args,
/* copy fuse ops to their own structure */
memcpy(&fuse->op, ops, sizeof(fuse->op));
+ if (fuse_opt_parse(args, &fuse->conf, fuse_lib_opts,
+ ifuse_lib_opt_proc) == -1) {
+ free(fuse);
+ return (NULL);
+ }
+
fuse->fc = fc;
fuse->max_ino = FUSE_ROOT_INO;
fuse->se.args = fuse;
@@ -354,7 +450,7 @@ fuse_daemonize(int foreground)
if (foreground)
return (0);
- return (daemon(0,0));
+ return (daemon(0, 0));
}
DEF(fuse_daemonize);
@@ -402,7 +498,7 @@ dump_help(void)
fprintf(stderr, "FUSE options:\n"
" -d -o debug enable debug output (implies -f)\n"
" -f run in foreground\n"
- " -V print fuse version\n"
+ " -V --version print fuse version\n"
"\n");
}
@@ -417,74 +513,59 @@ static int
ifuse_process_opt(void *data, const char *arg, int key,
unused struct fuse_args *args)
{
- struct fuse_core_opt *opt = data;
+ struct fuse_core_opts *opt = data;
struct stat st;
- const char *err;
int res;
switch (key) {
- case KEY_STUB:
- return (0);
- case KEY_DEBUG:
- ifuse_debug_init();
- /* falls through */
- case KEY_FOREGROUND:
- opt->foreground = 1;
- return (0);
- case KEY_HELP:
- case KEY_HELP_WITHOUT_HEADER:
- dump_help();
- return (-1);
- case KEY_VERSION:
- dump_version();
- return (-1);
- case KEY_MAXREAD:
- res = strtonum(arg, 0, FUSEBUFMAXSIZE, &err);
- if (err) {
- fprintf(stderr, "fuse: max_read %s\n", err);
+ case KEY_STUB:
+ return (0);
+ case KEY_DEBUG:
+ ifuse_debug_init();
+ /* falls through */
+ case KEY_FOREGROUND:
+ opt->foreground = 1;
+ return (0);
+ case KEY_HELP:
+ case KEY_HELP_WITHOUT_HEADER:
+ dump_help();
+ return (-1);
+ case KEY_VERSION:
+ dump_version();
+ return (-1);
+ case FUSE_OPT_KEY_NONOPT:
+ if (opt->mp == NULL) {
+ opt->mp = realpath(arg, opt->mp);
+ if (opt->mp == NULL) {
+ fprintf(stderr, "fuse: realpath: "
+ "%s : %s\n", arg, strerror(errno));
return (-1);
}
- max_read = res;
- break;
- case FUSE_OPT_KEY_NONOPT:
- if (opt->mp == NULL) {
- opt->mp = realpath(arg, opt->mp);
- if (opt->mp == NULL) {
- fprintf(stderr, "fuse: realpath: "
- "%s : %s\n", arg, strerror(errno));
- return (-1);
- }
- res = stat(opt->mp, &st);
- if (res == -1) {
- fprintf(stderr, "fuse: bad mount point "
- "%s : %s\n", arg, strerror(errno));
- return (-1);
- }
+ res = stat(opt->mp, &st);
+ if (res == -1) {
+ fprintf(stderr, "fuse: bad mount point "
+ "%s : %s\n", arg, strerror(errno));
+ return (-1);
+ }
- if (!S_ISDIR(st.st_mode)) {
- fprintf(stderr, "fuse: bad mount point "
- "%s : %s\n", arg,
- strerror(ENOTDIR));
- return (-1);
- }
- } else {
- fprintf(stderr, "fuse: invalid argument %s\n",
- arg);
+ if (!S_ISDIR(st.st_mode)) {
+ fprintf(stderr, "fuse: bad mount point "
+ "%s : %s\n", arg, strerror(ENOTDIR));
return (-1);
}
- break;
- default:
- fprintf(stderr, "fuse: unknown option %s\n", arg);
- return (-1);
+ }
+ return (0);
}
- return (0);
+
+ /* Pass through unknown options. */
+ return (1);
}
int
fuse_parse_cmdline(struct fuse_args *args, char **mp, int *mt, int *fg)
{
- struct fuse_core_opt opt;
+ struct fuse_core_opts opt;
bzero(&opt, sizeof(opt));
if (fuse_opt_parse(args, &opt, fuse_core_opts, ifuse_process_opt) == -1)
@@ -556,10 +637,10 @@ fuse_setup(int argc, char **argv, const struct fuse_operations *ops,
fuse_daemonize(fg);
- if ((fc = fuse_mount(dir, NULL)) == NULL)
+ if ((fc = fuse_mount(dir, &args)) == NULL)
goto err;
- if ((fuse = fuse_new(fc, NULL, ops, size, data)) == NULL) {
+ if ((fuse = fuse_new(fc, &args, ops, size, data)) == NULL) {
fuse_unmount(dir, fc);
close(fc->fd);
free(fc->dir);
@@ -567,13 +648,19 @@ fuse_setup(int argc, char **argv, const struct fuse_operations *ops,
goto err;
}
+ /* args are no longer needed */
+ fuse_opt_free_args(&args);
+
if (fuse_set_signal_handlers(fuse_get_session(fuse)) == -1) {
fuse_unmount(dir, fc);
fuse_destroy(fuse);
goto err;
}
- if (mp != NULL)
+ /* the caller frees dir, but we do it if the caller doesn't want it */
+ if (mp == NULL)
+ free(dir);
+ else
*mp = dir;
return (fuse);
@@ -589,7 +676,7 @@ fuse_main(int argc, char **argv, const struct fuse_operations *ops, void *data)
struct fuse *fuse;
fuse = fuse_setup(argc, argv, ops, sizeof(*ops), NULL, NULL, data);
- if (!fuse)
+ if (fuse == NULL)
return (-1);
return (fuse_loop(fuse));
diff --git a/lib/libfuse/fuse_private.h b/lib/libfuse/fuse_private.h
index 4fac3754f6d..53f1400966a 100644
--- a/lib/libfuse/fuse_private.h
+++ b/lib/libfuse/fuse_private.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: fuse_private.h,v 1.16 2017/12/15 16:40:33 jca Exp $ */
+/* $OpenBSD: fuse_private.h,v 1.17 2017/12/18 11:41:41 helg Exp $ */
/*
* Copyright (c) 2013 Sylvestre Gallon <ccna.syl@gmail.com>
*
@@ -73,11 +73,20 @@ struct fuse_config {
int set_gid;
};
-struct fuse_core_opt {
+struct fuse_core_opts {
char *mp;
int foreground;
};
+struct fuse_mount_opts {
+ char *fsname;
+ int def_perms;
+ int max_read;
+ int noatime;
+ int nonempty;
+ int rdonly;
+};
+
struct fuse {
struct fuse_chan *fc;
struct fuse_operations op;