From 425db842ff1155fcd3b40439fcd88248d45a5db7 Mon Sep 17 00:00:00 2001 From: Nikolaus Rath Date: Sun, 2 Oct 2016 20:52:33 -0700 Subject: [PATCH] Don't handle --help and --version in fuse_session_new(). Help and version messages can be generated using the new fuse_lowlevel_help(), fuse_lowlevel_version(), fuse_mount_help(), and fuse_mount_version() functions. The fuse_parse_cmdline() function has been made more powerful to do this automatically, and is now explicitly intended only for low-level API users. This is a code simplication patch. We don't have to parse for --help and --version in quite as many places, and we no longer have a low-level initialization function be responsible for the (super-high level) task of printing a program usage message. In the high-level API, we can now handle the command line parsing earlier and avoid running other initialization code if we're just going to abort later on. --- ChangeLog.rst | 20 ++-- example/fuse_lo-plus.c | 51 +++++---- example/hello_ll.c | 42 +++++--- include/fuse_common.h | 28 ----- include/fuse_lowlevel.h | 65 ++++++++++- lib/cuse_lowlevel.c | 23 ++-- lib/fuse.c | 74 ++++++------- lib/fuse_lowlevel.c | 67 +++++------- lib/fuse_versionscript | 4 + lib/helper.c | 233 ++++++++++++++++++++-------------------- 10 files changed, 317 insertions(+), 290 deletions(-) diff --git a/ChangeLog.rst b/ChangeLog.rst index a15b55a..9afc173 100644 --- a/ChangeLog.rst +++ b/ChangeLog.rst @@ -2,12 +2,20 @@ Unreleased Changes ================== * The `fuse_lowlevel_new` function has been renamed to - `fuse_session_new`. - -* There are now new `fuse_session_unmount` and `fuse_session_mount` - functions that should be used in the low-level API. The - `fuse_mount` and `fuse_unmount` functions should be used with the - high-level API only. + `fuse_session_new` and no longer interprets the --version or --help + options. To print help or version information, use the new + `fuse_lowlevel_help` and `fuse_lowlevel_version` functions. + +* There are new `fuse_session_unmount` and `fuse_session_mount` + functions that should be used in the low-level API. The `fuse_mount` + and `fuse_unmount` functions should be used with the high-level API + only. + +* Neither `fuse_mount` nor `fuse_session_mount` take struct fuse_opts + parameters anymore. Mount options are parsed by `fuse_new` (for the + high-level API) and `fuse_session_new` (for the low-level API) + instead. To print help or version information, use the new + `fuse_mount_help` and `fuse_mount_version` functions. * The ``fuse_lowlevel_notify_*`` functions now all take a `struct fuse_session` parameter instead of a `struct fuse_chan`. diff --git a/example/fuse_lo-plus.c b/example/fuse_lo-plus.c index 4171d3e..1aa97b0 100644 --- a/example/fuse_lo-plus.c +++ b/example/fuse_lo-plus.c @@ -442,55 +442,54 @@ static struct fuse_lowlevel_ops lo_oper = { .read = lo_read, }; -#define LO_OPT(t, p, v) { t, offsetof(struct lo_data, p), v } - -static const struct fuse_opt lo_opts[] = { - FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP), - FUSE_OPT_KEY("-d", FUSE_OPT_KEY_KEEP), - LO_OPT("debug", debug, 1), - LO_OPT("-d", debug, 1), - FUSE_OPT_END -}; - int main(int argc, char *argv[]) { struct fuse_args args = FUSE_ARGS_INIT(argc, argv); struct fuse_session *se; - char *mountpoint; - int ret = -1; + struct fuse_cmdline_opts opts; struct lo_data lo = { .debug = 0 }; + int ret = -1; - if (fuse_opt_parse(&args, &lo, lo_opts, NULL) == -1) - exit(1); + if (fuse_parse_cmdline(&args, &opts) != 0) + return 1; + if (opts.show_help || opts.show_version) { + ret = 1; + goto err_out1; + } + if (!opts.foreground) + fprintf(stderr, "Warning: background operation " + "is not supported\n"); + if (!opts.singlethread) + fprintf(stderr, "Warning: multithreading is not " + "supported\n"); + + lo.debug = opts.debug; lo.root.next = lo.root.prev = &lo.root; lo.root.fd = open("/", O_PATH); lo.root.nlookup = 2; if (lo.root.fd == -1) err(1, "open(\"/\", O_PATH)"); - if (fuse_parse_cmdline(&args, &mountpoint, NULL, NULL) != 0) - goto err_out; - se = fuse_session_new(&args, &lo_oper, sizeof(lo_oper), &lo); - fuse_opt_free_args(&args); if (se == NULL) - goto err_out; - - if (fuse_set_signal_handlers(se) != 0) goto err_out1; - if (fuse_session_mount(se, mountpoint) != 0) + if (fuse_set_signal_handlers(se) != 0) goto err_out2; + if (fuse_session_mount(se, opts.mountpoint) != 0) + goto err_out3; + ret = fuse_session_loop(se); fuse_session_unmount(se); -err_out2: +err_out3: fuse_remove_signal_handlers(se); -err_out1: +err_out2: fuse_session_destroy(se); -err_out: - free(mountpoint); +err_out1: + free(opts.mountpoint); + fuse_opt_free_args(&args); while (lo.root.next != &lo.root) lo_free(lo.root.next); diff --git a/example/hello_ll.c b/example/hello_ll.c index 07529d1..b7e77cd 100644 --- a/example/hello_ll.c +++ b/example/hello_ll.c @@ -187,35 +187,45 @@ int main(int argc, char *argv[]) { struct fuse_args args = FUSE_ARGS_INIT(argc, argv); struct fuse_session *se; - char *mountpoint; - int err = -1; - - if (fuse_parse_cmdline(&args, &mountpoint, NULL, NULL) != 0) - goto err_out; + struct fuse_cmdline_opts opts; + int ret = -1; + + if (fuse_parse_cmdline(&args, &opts) != 0) + return 1; + if (opts.show_help || opts.show_version) { + ret = 1; + goto err_out1; + } + if (!opts.foreground) + fprintf(stderr, "Warning: background operation " + "is not supported\n"); + if (!opts.singlethread) + fprintf(stderr, "Warning: multithreading is not " + "supported\n"); se = fuse_session_new(&args, &hello_ll_oper, sizeof(hello_ll_oper), NULL); - fuse_opt_free_args(&args); if (se == NULL) - goto err_out; - - if (fuse_set_signal_handlers(se) != 0) goto err_out1; - if (fuse_session_mount(se, mountpoint) != 0) + if (fuse_set_signal_handlers(se) != 0) goto err_out2; + if (fuse_session_mount(se, opts.mountpoint) != 0) + goto err_out3; + /* Block until ctrl+c or fusermount -u */ - err = fuse_session_loop(se); + ret = fuse_session_loop(se); fuse_session_unmount(se); -err_out2: +err_out3: fuse_remove_signal_handlers(se); -err_out1: +err_out2: fuse_session_destroy(se); -err_out: - free(mountpoint); +err_out1: + free(opts.mountpoint); + fuse_opt_free_args(&args); - return err ? 1 : 0; + return ret ? 1 : 0; } /*! [doxygen_fuse_lowlevel_usage] */ diff --git a/include/fuse_common.h b/include/fuse_common.h index f39dab3..f32c872 100644 --- a/include/fuse_common.h +++ b/include/fuse_common.h @@ -208,34 +208,6 @@ struct fuse_conn_info { struct fuse_session; struct fuse_pollhandle; -/** - * Utility functions for simple file systems to parse common options. - * - * The following options are parsed: - * - * '-f' foreground - * '-d' '-odebug' foreground, but keep the debug option - * '-s' single threaded - * '-h' '--help' help - * '-ho' help without header - * '-ofsname=..' file system name, if not present, then set to the program - * name - * - * Unknown parameters in `args` are passed through unchanged. Known - * parameters (with the exception of --help and --version) are removed. - * - * All parameters may be NULL (in which case they may still - * be specified on the command line, but will not be set). - * - * @param args argument vector - * @param mountpoint the returned mountpoint, should be freed after use - * @param multithreaded set to 1 unless the '-s' option is present - * @param foreground set to 1 if one of the relevant options is present - * @return 0 on success, -1 on failure - */ -int fuse_parse_cmdline(struct fuse_args *args, char **mountpoint, - int *multithreaded, int *foreground); - /** * Go into the background * diff --git a/include/fuse_lowlevel.h b/include/fuse_lowlevel.h index f90a052..0822e51 100644 --- a/include/fuse_lowlevel.h +++ b/include/fuse_lowlevel.h @@ -1560,10 +1560,72 @@ void fuse_req_interrupt_func(fuse_req_t req, fuse_interrupt_func_t func, */ int fuse_req_interrupted(fuse_req_t req); + +/* ----------------------------------------------------------- * + * Inquiry functions * + * ----------------------------------------------------------- */ + +/** + * Print FUSE library version to stdout. + */ +void fuse_lowlevel_version(void); + +/** + * Print FUSE mount (fusermount) version stdout. + */ +void fuse_mount_version(void); + +/** + * Print available low-level options to stdout. + * These options may be passed to `fuse_session_new()` + */ +void fuse_lowlevel_help(void); + +/** + * Print available mount options to stdout. + * These options may be passed to `fuse_session_new()` + */ +void fuse_mount_help(void); + /* ----------------------------------------------------------- * * Filesystem setup & teardown * * ----------------------------------------------------------- */ +struct fuse_cmdline_opts { + int singlethread; + int foreground; + int debug; + int nodefault_subtype; + char *mountpoint; + int show_version; + int show_help; +}; + +/** + * Utility function to parse common options for simple file systems + * using the low-level API. Available options are listed in `struct + * fuse_opt fuse_helper_opts[]`. A single non-option argument is + * treated as the mountpoint. Multiple (or no) non-option arguments + * will result in an error. + * + * Unknown options are passed through unchanged. Known options (other + * than --debug, which is preserved) and the mountpoint argument are + * removed from *args*. + * + * If --help or --version is specified, the appropriate information is + * printed to stdout and the function proceeds normally. + * + * If neither -o subtype= or -o fsname= options are given, the subtype + * is set to the basename of the program (the fsname defaults to + * "fuse"). + * + * @param args argument vector (input+output) + * @param opts output argument for parsed options + * @return 0 on success, -1 on failure + */ +int fuse_parse_cmdline(struct fuse_args *args, + struct fuse_cmdline_opts *opts); + /** * Create a low level session. * @@ -1574,9 +1636,6 @@ int fuse_req_interrupted(fuse_req_t req); * `struct fuse_opt fuse_mount_opts[]`. If not all options are known, * an error message is written to stderr and the function returns NULL. * - * If the --help or --version parameters are specified, the function - * prints the requsted information to stdout and returns NULL. - * * @param args argument vector * @param op the (low-level) filesystem operations * @param op_size sizeof(struct fuse_lowlevel_ops) diff --git a/lib/cuse_lowlevel.c b/lib/cuse_lowlevel.c index 3dd79d8..8f596cb 100644 --- a/lib/cuse_lowlevel.c +++ b/lib/cuse_lowlevel.c @@ -276,21 +276,18 @@ struct fuse_session *cuse_lowlevel_setup(int argc, char *argv[], struct fuse_args args = FUSE_ARGS_INIT(argc, argv); struct fuse_session *se; struct fuse_chan *ch; + struct fuse_cmdline_opts opts; int fd; - int foreground; int res; - res = fuse_parse_cmdline(&args, NULL, multithreaded, &foreground); - if (res == -1) { - fuse_opt_free_args(&args); + if (fuse_parse_cmdline(&args, &opts) == -1) return NULL; - } + *multithreaded = !opts.singlethread; + /* Remove subtype= option */ res = fuse_opt_parse(&args, NULL, kill_subtype_opts, NULL); - if (res == -1) { - fuse_opt_free_args(&args); - return NULL; - } + if (res == -1) + goto out1; /* * Make sure file descriptors 0, 1 and 2 are open, otherwise chaos @@ -303,9 +300,8 @@ struct fuse_session *cuse_lowlevel_setup(int argc, char *argv[], } while (fd >= 0 && fd <= 2); se = cuse_lowlevel_new(&args, ci, clop, userdata); - fuse_opt_free_args(&args); if (se == NULL) - return NULL; + goto out1; fd = open(devname, O_RDWR); if (fd == -1) { @@ -329,7 +325,7 @@ struct fuse_session *cuse_lowlevel_setup(int argc, char *argv[], if (res == -1) goto err_se; - res = fuse_daemonize(foreground); + res = fuse_daemonize(opts.foreground); if (res == -1) goto err_sig; @@ -339,6 +335,9 @@ err_sig: fuse_remove_signal_handlers(se); err_se: fuse_session_destroy(se); +out1: + free(opts.mountpoint); + fuse_opt_free_args(&args); return NULL; } diff --git a/lib/fuse.c b/lib/fuse.c index d5cc678..0414f6b 100644 --- a/lib/fuse.c +++ b/lib/fuse.c @@ -77,7 +77,7 @@ struct fuse_config { int auto_cache; int intr; int intr_signal; - int help; + int show_help; char *modules; }; @@ -4410,15 +4410,11 @@ int fuse_interrupted(void) return 0; } -enum { - KEY_HELP, -}; - #define FUSE_LIB_OPT(t, p, v) { t, offsetof(struct fuse_config, p), v } static const struct fuse_opt fuse_lib_opts[] = { - FUSE_OPT_KEY("-h", KEY_HELP), - FUSE_OPT_KEY("--help", KEY_HELP), + FUSE_LIB_OPT("-h", show_help, 1), + FUSE_LIB_OPT("--help", show_help, 1), FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP), FUSE_OPT_KEY("-d", FUSE_OPT_KEY_KEEP), FUSE_LIB_OPT("debug", debug, 1), @@ -4499,14 +4495,9 @@ static void fuse_lib_help_modules(void) static int fuse_lib_opt_proc(void *data, const char *arg, int key, struct fuse_args *outargs) { - (void) arg; (void) outargs; - - if (key == KEY_HELP) { - struct fuse_config *conf = (struct fuse_config *) data; - fuse_lib_help(); - conf->help = 1; - } + (void) arg; (void) outargs; (void) data; (void) key; + /* Pass through unknown options */ return 1; } @@ -4641,6 +4632,25 @@ struct fuse *fuse_new(struct fuse_args *args, struct fuse_fs *fs; struct fuse_lowlevel_ops llop = fuse_path_ops; + f = (struct fuse *) calloc(1, sizeof(struct fuse)); + if (f == NULL) { + fprintf(stderr, "fuse: failed to allocate fuse object\n"); + goto out; + } + + /* Parse options */ + if (fuse_opt_parse(args, &f->conf, fuse_lib_opts, + fuse_lib_opt_proc) == -1) + goto out_free; + + if (f->conf.show_help) { + fuse_lib_help(); + fuse_lowlevel_help(); + fuse_mount_help(); + /* Defer printing module help until modules + have been loaded */ + } + pthread_mutex_lock(&fuse_context_lock); static int builtin_modules_registered = 0; /* Have the builtin modules already been registered? */ @@ -4652,19 +4662,12 @@ struct fuse *fuse_new(struct fuse_args *args, } pthread_mutex_unlock(&fuse_context_lock); - if (fuse_create_context_key() == -1) - goto out; - - f = (struct fuse *) calloc(1, sizeof(struct fuse)); - if (f == NULL) { - fprintf(stderr, "fuse: failed to allocate fuse object\n"); - goto out_delete_context_key; - } + goto out_free; fs = fuse_fs_new(op, op_size, user_data); if (!fs) - goto out_free; + goto out_delete_context_key; f->fs = fs; f->conf.nopath = fs->op.flag_nopath; @@ -4685,13 +4688,6 @@ struct fuse *fuse_new(struct fuse_args *args, init_list_head(&f->full_slabs); init_list_head(&f->lru_table); - /* When --help or --version are specified, we print messages - to stderr but continue for now (and keep the arguments in - `args` for use below */ - if (fuse_opt_parse(args, &f->conf, fuse_lib_opts, - fuse_lib_opt_proc) == -1) - goto out_free_fs; - if (f->conf.modules) { char *module; char *next; @@ -4707,6 +4703,11 @@ struct fuse *fuse_new(struct fuse_args *args, } } + if(f->conf.show_help) { + fuse_lib_help_modules(); + goto out_free_fs; + } + if (!f->conf.ac_attr_timeout_set) f->conf.ac_attr_timeout = f->conf.attr_timeout; @@ -4718,16 +4719,9 @@ struct fuse *fuse_new(struct fuse_args *args, f->conf.readdir_ino = 1; #endif - /* This function will return NULL if there is an --help - or --version argument in `args` */ f->se = fuse_session_new(args, &llop, sizeof(llop), f); - if (f->se == NULL) { - /* If we've printed help before, add module help at - * the end */ - if (f->conf.help) - fuse_lib_help_modules(); + if (f->se == NULL) goto out_free_fs; - } if (f->conf.debug) { fprintf(stderr, "nopath: %i\n", f->conf.nopath); @@ -4783,10 +4777,10 @@ out_free_fs: fuse_put_module(f->fs->m); free(f->fs); free(f->conf.modules); -out_free: - free(f); out_delete_context_key: fuse_delete_context_key(); +out_free: + free(f); out: return NULL; } diff --git a/lib/fuse_lowlevel.c b/lib/fuse_lowlevel.c index 1d843d1..2597c39 100755 --- a/lib/fuse_lowlevel.c +++ b/lib/fuse_lowlevel.c @@ -2581,11 +2581,6 @@ clear_pipe: goto out_free; } -enum { - KEY_HELP, - KEY_VERSION, -}; - static const struct fuse_opt fuse_ll_opts[] = { { "debug", offsetof(struct fuse_ll, debug), 1 }, { "-d", offsetof(struct fuse_ll, debug), 1 }, @@ -2622,20 +2617,16 @@ static const struct fuse_opt fuse_ll_opts[] = { { "no_writeback_cache", offsetof(struct fuse_ll, no_writeback_cache), 1}, { "time_gran=%u", offsetof(struct fuse_ll, conn.time_gran), 0 }, { "clone_fd", offsetof(struct fuse_ll, clone_fd), 1 }, - FUSE_OPT_KEY("-h", KEY_HELP), - FUSE_OPT_KEY("--help", KEY_HELP), - FUSE_OPT_KEY("-V", KEY_VERSION), - FUSE_OPT_KEY("--version", KEY_VERSION), FUSE_OPT_END }; -static void fuse_ll_version(void) +void fuse_lowlevel_version(void) { printf("using FUSE kernel interface version %i.%i\n", FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION); } -static void fuse_ll_help(void) +void fuse_lowlevel_help(void) { printf( "Low-level options\n" @@ -2664,25 +2655,10 @@ static void fuse_ll_help(void) static int fuse_ll_opt_proc(void *data, const char *arg, int key, struct fuse_args *outargs) { - (void) data; (void) outargs; (void) arg; - - switch (key) { - case KEY_HELP: - fuse_ll_help(); - fuse_mount_help(); - break; - - case KEY_VERSION: - fuse_ll_version(); - fuse_mount_version(); - break; + (void) data; (void) outargs; (void) key; (void) arg; - default: - fprintf(stderr, "fuse: unknown option `%s'\n", arg); - } - - /* Fail */ - return -1; + /* Passthrough unknown options */ + return 1; } static void fuse_ll_destroy(struct fuse_ll *f) @@ -2888,15 +2864,23 @@ struct fuse_session *fuse_session_new(struct fuse_args *args, f = (struct fuse_ll *) calloc(1, sizeof(struct fuse_ll)); if (f == NULL) { fprintf(stderr, "fuse: failed to allocate fuse object\n"); - goto out; + goto out1; } /* Parse options */ mo = parse_mount_opts(args); if (mo == NULL) - goto out_free0; - if (fuse_opt_parse(args, f, fuse_ll_opts, fuse_ll_opt_proc) == -1) - goto out_free; + goto out2; + if(fuse_opt_parse(args, f, fuse_ll_opts, fuse_ll_opt_proc) == -1) + goto out3; + if (args->argc != 1) { + int i; + fprintf(stderr, "fuse: unknown option(s): `"); + for(i = 1; i < args->argc-1; i++) + fprintf(stderr, "%s ", args->argv[i]); + fprintf(stderr, "%s'\n", args->argv[i]); + goto out4; + } if (f->debug) fprintf(stderr, "FUSE library version: %s\n", PACKAGE_VERSION); @@ -2918,7 +2902,7 @@ struct fuse_session *fuse_session_new(struct fuse_args *args, if (err) { fprintf(stderr, "fuse: failed to create thread specific key: %s\n", strerror(err)); - goto out_free; + goto out5; } memcpy(&f->op, op, op_size); @@ -2928,21 +2912,24 @@ struct fuse_session *fuse_session_new(struct fuse_args *args, se = (struct fuse_session *) malloc(sizeof(*se)); if (se == NULL) { fprintf(stderr, "fuse: failed to allocate session\n"); - goto out_key_destroy; + goto out6; } memset(se, 0, sizeof(*se)); se->f = f; se->mo = mo; return se; -out_key_destroy: +out6: pthread_key_delete(f->pipe_key); -out_free: - free(mo); -out_free0: +out5: pthread_mutex_destroy(&f->lock); +out4: + fuse_opt_free_args(args); +out3: + free(mo); +out2: free(f); -out: +out1: return NULL; } diff --git a/lib/fuse_versionscript b/lib/fuse_versionscript index ee9c9d7..4327429 100644 --- a/lib/fuse_versionscript +++ b/lib/fuse_versionscript @@ -122,6 +122,10 @@ FUSE_3.0 { fuse_lowlevel_notify_delete; fuse_fs_flock; fuse_fs_fallocate; + fuse_lowlevel_help; + fuse_lowlevel_version; + fuse_mount_help; + fuse_mount_version; local: *; diff --git a/lib/helper.c b/lib/helper.c index 309c096..63f26c2 100644 --- a/lib/helper.c +++ b/lib/helper.c @@ -21,36 +21,24 @@ #include #include -enum { - KEY_HELP, - KEY_HELP_NOHEADER, - KEY_VERSION, -}; - -struct helper_opts { - int singlethread; - int foreground; - int nodefault_subtype; - char *mountpoint; -}; - -#define FUSE_HELPER_OPT(t, p) { t, offsetof(struct helper_opts, p), 1 } +#define FUSE_HELPER_OPT(t, p) \ + { t, offsetof(struct fuse_cmdline_opts, p), 1 } static const struct fuse_opt fuse_helper_opts[] = { + FUSE_HELPER_OPT("-h", show_help), + FUSE_HELPER_OPT("--help", show_help), + FUSE_HELPER_OPT("-V", show_version), + FUSE_HELPER_OPT("--version", show_version), + FUSE_HELPER_OPT("-d", debug), + FUSE_HELPER_OPT("debug", debug), FUSE_HELPER_OPT("-d", foreground), FUSE_HELPER_OPT("debug", foreground), + FUSE_OPT_KEY("-d", FUSE_OPT_KEY_KEEP), + FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP), FUSE_HELPER_OPT("-f", foreground), FUSE_HELPER_OPT("-s", singlethread), FUSE_HELPER_OPT("fsname=", nodefault_subtype), FUSE_HELPER_OPT("subtype=", nodefault_subtype), - - FUSE_OPT_KEY("-h", KEY_HELP), - FUSE_OPT_KEY("--help", KEY_HELP), - FUSE_OPT_KEY("-ho", KEY_HELP_NOHEADER), - FUSE_OPT_KEY("-V", KEY_VERSION), - FUSE_OPT_KEY("--version", KEY_VERSION), - FUSE_OPT_KEY("-d", FUSE_OPT_KEY_KEEP), - FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP), FUSE_OPT_KEY("fsname=", FUSE_OPT_KEY_KEEP), FUSE_OPT_KEY("subtype=", FUSE_OPT_KEY_KEEP), FUSE_OPT_END @@ -80,23 +68,12 @@ static void helper_version(void) static int fuse_helper_opt_proc(void *data, const char *arg, int key, struct fuse_args *outargs) { - struct helper_opts *hopts = data; + (void) outargs; + struct fuse_cmdline_opts *opts = data; switch (key) { - case KEY_HELP: - usage(outargs->argv[0]); - /* fall through */ - - case KEY_HELP_NOHEADER: - helper_help(); - return fuse_opt_add_arg(outargs, "-h"); - - case KEY_VERSION: - helper_version(); - return 1; - case FUSE_OPT_KEY_NONOPT: - if (!hopts->mountpoint) { + if (!opts->mountpoint) { char mountpoint[PATH_MAX]; if (realpath(arg, mountpoint) == NULL) { fprintf(stderr, @@ -104,7 +81,7 @@ static int fuse_helper_opt_proc(void *data, const char *arg, int key, arg, strerror(errno)); return -1; } - return fuse_opt_add_opt(&hopts->mountpoint, mountpoint); + return fuse_opt_add_opt(&opts->mountpoint, mountpoint); } else { fprintf(stderr, "fuse: invalid argument `%s'\n", arg); return -1; @@ -137,39 +114,45 @@ static int add_default_subtype(const char *progname, struct fuse_args *args) return res; } -int fuse_parse_cmdline(struct fuse_args *args, char **mountpoint, - int *multithreaded, int *foreground) +int fuse_parse_cmdline(struct fuse_args *args, + struct fuse_cmdline_opts *opts) { - int res; - struct helper_opts hopts; + memset(opts, 0, sizeof(struct fuse_cmdline_opts)); + if (fuse_opt_parse(args, opts, fuse_helper_opts, + fuse_helper_opt_proc) == -1) + return -1; + + if (opts->show_version) { + helper_version(); + fuse_lowlevel_version(); + fuse_mount_version(); + return -1; + } - memset(&hopts, 0, sizeof(hopts)); - res = fuse_opt_parse(args, &hopts, fuse_helper_opts, - fuse_helper_opt_proc); - if (res == -1) + if (opts->show_help) { + usage(args->argv[0]); + helper_help(); + fuse_lowlevel_help(); + fuse_mount_help(); return -1; + } - if (!hopts.nodefault_subtype) { - res = add_default_subtype(args->argv[0], args); - if (res == -1) - goto err; + if (!opts->mountpoint) { + fprintf(stderr, "error: no mountpoint specified\n"); + usage(args->argv[0]); + return -1; } - if (mountpoint) - *mountpoint = hopts.mountpoint; - else - free(hopts.mountpoint); - if (multithreaded) - *multithreaded = !hopts.singlethread; - if (foreground) - *foreground = hopts.foreground; - return 0; + /* If neither -o subtype nor -o fsname are specified, + set subtype to program's basename */ + if (!opts->nodefault_subtype) + if (add_default_subtype(args->argv[0], args) == -1) + return -1; -err: - free(hopts.mountpoint); - return -1; + return 0; } + int fuse_daemonize(int foreground) { if (!foreground) { @@ -224,81 +207,93 @@ int fuse_daemonize(int foreground) return 0; } - -static struct fuse *fuse_setup(int argc, char *argv[], - const struct fuse_operations *op, size_t op_size, - int *multithreaded, void *user_data) +int fuse_main_real(int argc, char *argv[], const struct fuse_operations *op, + size_t op_size, void *user_data) { struct fuse_args args = FUSE_ARGS_INIT(argc, argv); struct fuse *fuse; - char *mountpoint; - int foreground; + struct fuse_cmdline_opts opts; int res; - res = fuse_parse_cmdline(&args, &mountpoint, multithreaded, &foreground); - if (res == -1) - return NULL; + memset(&opts, 0, sizeof(opts)); + if (fuse_opt_parse(&args, &opts, fuse_helper_opts, + fuse_helper_opt_proc) == -1) + return 1; - fuse = fuse_new(&args, op, op_size, user_data); - if (fuse == NULL) { - fuse_opt_free_args(&args); - free(mountpoint); - return NULL; + if (opts.show_version) { + helper_version(); + fuse_lowlevel_version(); + fuse_mount_version(); + res = 0; + goto out1; } - res = fuse_mount(fuse, mountpoint); - free(mountpoint); - if (res != 0) - goto err_out1; - - res = fuse_daemonize(foreground); - if (res == -1) - goto err_unmount; + /* Re-add --help for later processing by fuse_new() + (that way we also get help for modules options) */ + if (opts.show_help) { + helper_help(); + if (fuse_opt_add_arg(&args, "--help") == -1) { + res = 1; + goto out1; + } + } - res = fuse_set_signal_handlers(fuse_get_session(fuse)); - if (res == -1) - goto err_unmount; + if (!opts.show_help && + !opts.mountpoint) { + fprintf(stderr, "error: no mountpoint specified\n"); + usage(args.argv[0]); + res = 1; + goto out1; + } - return fuse; + /* If neither -o subtype nor -o fsname are specified, + set subtype to program's basename */ + if (!opts.nodefault_subtype) { + if (add_default_subtype(args.argv[0], &args) == -1) { + res = 1; + goto out1; + } + } -err_unmount: - fuse_unmount(fuse); -err_out1: - fuse_destroy(fuse); - fuse_opt_free_args(&args); - return NULL; -} + /* --help is processed here and will result in NULL */ + fuse = fuse_new(&args, op, op_size, user_data); + if (fuse == NULL) { + res = opts.show_help ? 0 : 1; + goto out1; + } -static void fuse_teardown(struct fuse *fuse) -{ - struct fuse_session *se = fuse_get_session(fuse); - fuse_remove_signal_handlers(se); - fuse_unmount(fuse); - fuse_destroy(fuse); -} + if (fuse_mount(fuse,opts.mountpoint) != 0) { + res = 1; + goto out2; + } -int fuse_main_real(int argc, char *argv[], const struct fuse_operations *op, - size_t op_size, void *user_data) -{ - struct fuse *fuse; - int multithreaded; - int res; + if (fuse_daemonize(opts.foreground) != 0) { + res = 1; + goto out3; + } - fuse = fuse_setup(argc, argv, op, op_size, - &multithreaded, user_data); - if (fuse == NULL) - return 1; + struct fuse_session *se = fuse_get_session(fuse); + if (fuse_set_signal_handlers(se) != 0) { + res = 1; + goto out3; + } - if (multithreaded) - res = fuse_loop_mt(fuse); - else + if (opts.singlethread) res = fuse_loop(fuse); + else + res = fuse_loop_mt(fuse); + if (res) + res = 1; - fuse_teardown(fuse); - if (res == -1) - return 1; - - return 0; + fuse_remove_signal_handlers(se); +out3: + fuse_unmount(fuse); +out2: + fuse_destroy(fuse); +out1: + free(opts.mountpoint); + fuse_opt_free_args(&args); + return res; } int fuse_version(void) -- 2.30.2