From 58efe7d1290f4586999d130dd7672a41515c1364 Mon Sep 17 00:00:00 2001 From: helg Date: Mon, 18 Dec 2017 11:41:41 +0000 Subject: [PATCH] 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@ --- lib/libfuse/fuse.c | 229 +++++++++++++++++++++++++------------ lib/libfuse/fuse_private.h | 13 ++- 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 * @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -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 * @@ -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; -- 2.20.1