diff options
-rw-r--r-- | ChangeLog.rst | 67 | ||||
-rw-r--r-- | doc/developer-notes.rst | 28 | ||||
-rw-r--r-- | example/fuse_lo-plus.c | 40 | ||||
-rwxr-xr-x | example/hello_ll.c | 46 | ||||
-rw-r--r-- | include/fuse.h | 43 | ||||
-rw-r--r-- | include/fuse_common.h | 1 | ||||
-rw-r--r-- | include/fuse_lowlevel.h | 99 | ||||
-rw-r--r-- | lib/fuse.c | 17 | ||||
-rw-r--r-- | lib/fuse_i.h | 59 | ||||
-rwxr-xr-x | lib/fuse_lowlevel.c | 72 | ||||
-rw-r--r-- | lib/fuse_versionscript | 5 | ||||
-rw-r--r-- | lib/helper.c | 44 | ||||
-rw-r--r-- | lib/mount.c | 98 | ||||
-rw-r--r-- | lib/mount_bsd.c | 71 |
14 files changed, 363 insertions, 327 deletions
diff --git a/ChangeLog.rst b/ChangeLog.rst index 23c606e..a15b55a 100644 --- a/ChangeLog.rst +++ b/ChangeLog.rst @@ -12,9 +12,70 @@ Unreleased Changes * The ``fuse_lowlevel_notify_*`` functions now all take a `struct fuse_session` parameter instead of a `struct fuse_chan`. -* The channel interface (``fuse_chan_*`` functions) has been - made private. The `struct fuse_chan_ops` data structure is now - opaque. +* The channel interface (``fuse_chan_*`` functions) has been made + private. As a result, the typical initialization sequence of a + low-level file system has changed from :: + + ch = fuse_mount(mountpoint, &args); + se = fuse_lowlevel_new(&args, &lo_oper, sizeof(lo_oper), &lo); + fuse_set_signal_handlers(se); + fuse_session_add_chan(se, ch); + fuse_daemonize(fg); + if (mt) + fuse_session_loop_mt(se); + else + fuse_session_loop(se); + fuse_remove_signal_handlers(se); + fuse_session_remove_chan(ch); + fuse_session_destroy(se); + fuse_unmount(mountpoint, ch); + + to :: + + se = fuse_session_new(&args, &ll_ops, sizeof(ll_ops), NULL); + fuse_set_signal_handlers(se); + fuse_session_mount(se, mountpoint); + fuse_daemonize(fg); + if (mt) + fuse_session_loop_mt(se); + else + fuse_session_loop(se); + fuse_remove_signal_handlers(se); + fuse_session_unmount(se); + fuse_lowlevel_destroy(se); + + The typical high-level setup has changed from :: + + ch = fuse_mount(*mountpoint, &args); + fuse = fuse_new(ch, &args, op, op_size, user_data); + se = fuse_get_session(fuse); + fuse_set_signal_handlers(se); + fuse_daemonize(fg); + if (mt) + fuse_loop_mt(fuse); + else + fuse_loop(fuse); + fuse_remove_signal_handlers(se); + fuse_unmount(mountpoint, ch); + fuse_destroy(fuse); + + to :: + + fuse = fuse_new(&args, op, op_size, user_data); + se = fuse_get_session(fuse); + fuse_set_signal_handlers(se); + fuse_mount(se, mountpoint); + fuse_daemonize(fg); + if (mt) + fuse_loop_mt(fuse); + else + fuse_loop(fuse); + fuse_remove_signal_handlers(se); + fuse_unmount(se); + fuse_destroy(fuse); + + File systems that use `fuse_main` are not affected by this change. + * Added *clone_fd* option. This creates a separate device file descriptor for each processing thread, which might improve diff --git a/doc/developer-notes.rst b/doc/developer-notes.rst index 4e9b31a..1df082a 100644 --- a/doc/developer-notes.rst +++ b/doc/developer-notes.rst @@ -5,31 +5,3 @@ If you are working on libfuse itself (rather than using it for a different project) this file should be of interest to you. Otherwise you should ignore it entirely. - -Channel Interface -================= - -From the API, it may appear as if every fuse session (`struct -fuse_session`) is associated with a single fuse channel (`struct -fuse_chan`) that is created by `fuse_mount()` and assigned to the -session in `fuse_session_add_chan()`. Therefore, one may wonder why -there are two separate structs in the first place, and why the channel -structure has a reference counter and mutex. - -The answer is that when using the multi-threaded session loop with the -*clone_fd* option enabled, there are actually multiple channel objects -per session. The session only holds a reference to the first one, and -the additional channel objects don't actually hold references to the -session object -- but they still exist. The additional channels are -created by duplicating the fd (in `fuse_clone_chan()`, called by -`fuse_loop_start_thread`). When processing a request, -`fuse_session_process_buf()` records the active channel in the request -object (`struct fuse_req`) so that it can be retrieved by e.g. the -``fuse_reply_*`` functions. Since the request object can potentially -live longer than the worker thread that created it, we need to keep a -reference count for the channel. - -The reason for not having references to the session object from the -extra channels is not clear, but with the current implementation this -would not work because `fuse_session_remove_chan` always attempts to -remove the channel from the session. diff --git a/example/fuse_lo-plus.c b/example/fuse_lo-plus.c index e79c727..4171d3e 100644 --- a/example/fuse_lo-plus.c +++ b/example/fuse_lo-plus.c @@ -455,7 +455,7 @@ static const struct fuse_opt lo_opts[] = { int main(int argc, char *argv[]) { struct fuse_args args = FUSE_ARGS_INIT(argc, argv); - struct fuse_chan *ch; + struct fuse_session *se; char *mountpoint; int ret = -1; struct lo_data lo = { .debug = 0 }; @@ -468,23 +468,29 @@ int main(int argc, char *argv[]) if (lo.root.fd == -1) err(1, "open(\"/\", O_PATH)"); - if (fuse_parse_cmdline(&args, &mountpoint, NULL, NULL) != -1 && - (ch = fuse_session_mount(mountpoint, &args)) != NULL) { - struct fuse_session *se; - se = fuse_session_new(&args, &lo_oper, sizeof(lo_oper), &lo); - if (se != NULL) { - if (fuse_set_signal_handlers(se) != -1) { - fuse_session_add_chan(se, ch); - ret = fuse_session_loop(se); - fuse_remove_signal_handlers(se); - fuse_session_remove_chan(ch); - } - fuse_session_destroy(se); - } - fuse_session_unmount(mountpoint, ch); - free(mountpoint); - } + 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) + goto err_out2; + + ret = fuse_session_loop(se); + + fuse_session_unmount(se); +err_out2: + fuse_remove_signal_handlers(se); +err_out1: + fuse_session_destroy(se); +err_out: + free(mountpoint); while (lo.root.next != &lo.root) lo_free(lo.root.next); diff --git a/example/hello_ll.c b/example/hello_ll.c index 528b216..07529d1 100755 --- a/example/hello_ll.c +++ b/example/hello_ll.c @@ -186,31 +186,35 @@ static struct fuse_lowlevel_ops hello_ll_oper = { int main(int argc, char *argv[]) { struct fuse_args args = FUSE_ARGS_INIT(argc, argv); - struct fuse_chan *ch; + struct fuse_session *se; char *mountpoint; int err = -1; - if (fuse_parse_cmdline(&args, &mountpoint, NULL, NULL) != -1 && - (ch = fuse_session_mount(mountpoint, &args)) != NULL) { - struct fuse_session *se; - - se = fuse_session_new(&args, &hello_ll_oper, - sizeof(hello_ll_oper), NULL); - if (se != NULL) { - if (fuse_set_signal_handlers(se) != -1) { - fuse_session_add_chan(se, ch); - - /* Block until ctrl+c or fusermount -u */ - err = fuse_session_loop(se); - - fuse_remove_signal_handlers(se); - fuse_session_remove_chan(ch); - } - fuse_session_destroy(se); - } - fuse_session_unmount(mountpoint, ch); - } + if (fuse_parse_cmdline(&args, &mountpoint, NULL, NULL) != 0) + goto err_out; + + 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) + goto err_out2; + + /* Block until ctrl+c or fusermount -u */ + err = fuse_session_loop(se); + + fuse_session_unmount(se); +err_out2: + fuse_remove_signal_handlers(se); +err_out1: + fuse_session_destroy(se); +err_out: + free(mountpoint); return err ? 1 : 0; } diff --git a/include/fuse.h b/include/fuse.h index 948442c..c3fea2d 100644 --- a/include/fuse.h +++ b/include/fuse.h @@ -640,55 +640,44 @@ struct fuse_context { /** * Create a new FUSE filesystem. * - * Known parameters in `args` are removed. If there are any unknown - * arguments, an error is printed to stderr and the function returns + * Known arguments are defined in `struct fuse_opt fuse_lib_opts[]`, + * `struct fuse_opt fuse_mount_opts[]`, and `struct fuse_opt + * fuse_ll_opts[]`. If there are any unknown arguments, an error + * message will be printed to stderr and the function will return * NULL. * * If the --help or --version parameters are specified, the function * prints the requested information to stdout and returns NULL. * - * @param ch the communication channel * @param args argument vector * @param op the filesystem operations * @param op_size the size of the fuse_operations structure * @param user_data user data supplied in the context during the init() method * @return the created FUSE handle */ -struct fuse *fuse_new(struct fuse_chan *ch, struct fuse_args *args, - const struct fuse_operations *op, size_t op_size, - void *user_data); +struct fuse *fuse_new(struct fuse_args *args, const struct fuse_operations *op, + size_t op_size, void *user_data); /** - * Create a FUSE mountpoint - * - * Returns a control file descriptor suitable for passing to - * fuse_new(). Unknown parameters in `args` are passed through - * unchanged. Known parameters (with the exception of --help and - * --version) are removed from `args`. - * - * If the --help or --version parameters are specified, the function - * prints the requested information to stdout and returns a valid - * pointer. However, it does not actually perform the mount. + * Mount a FUSE file system. * * @param mountpoint the mount point path - * @param args argument vector - * @return the communication channel on success, NULL on failure - */ -struct fuse_chan *fuse_mount(const char *mountpoint, struct fuse_args *args); + * @param f the FUSE handle + * + * @return 0 on success, -1 on failure. + **/ +int fuse_mount(struct fuse *f, const char *mountpoint); /** - * Umount a FUSE mountpoint + * Unmount a FUSE file system. * - * @param mountpoint the mount point path - * @param ch the communication channel - */ -void fuse_unmount(const char *mountpoint, struct fuse_chan *ch); + * @param f the FUSE handle + **/ +void fuse_unmount(struct fuse *f); /** * Destroy the FUSE handle. * - * The communication channel attached to the handle is also destroyed. - * * NOTE: This function does not unmount the filesystem. If this is * needed, call fuse_unmount() before calling this function. * diff --git a/include/fuse_common.h b/include/fuse_common.h index bab2a5b..f39dab3 100644 --- a/include/fuse_common.h +++ b/include/fuse_common.h @@ -206,7 +206,6 @@ struct fuse_conn_info { }; struct fuse_session; -struct fuse_chan; struct fuse_pollhandle; /** diff --git a/include/fuse_lowlevel.h b/include/fuse_lowlevel.h index 9656c98..f0f0e0b 100644 --- a/include/fuse_lowlevel.h +++ b/include/fuse_lowlevel.h @@ -56,14 +56,6 @@ typedef struct fuse_req *fuse_req_t; */ struct fuse_session; -/** - * Channel - * - * A communication channel, providing hooks for sending and receiving - * messages - */ -struct fuse_chan; - /** Directory entry parameters supplied to fuse_reply_entry() */ struct fuse_entry_param { /** Unique inode number @@ -1573,30 +1565,15 @@ int fuse_req_interrupted(fuse_req_t req); * ----------------------------------------------------------- */ /** - * Create a FUSE mountpoint - * - * Returns a control file descriptor suitable for passing to - * fuse_new(). Unknown parameters in `args` are passed through - * unchanged. Known parameters (with the exception of --help and - * --version) are removed from `args`. + * Create a low level session. * - * If the --help or --version parameters are specified, the function - * prints the requested information to stdout and returns a valid - * pointer. However, it does not actually perform the mount. - * - * @param mountpoint the mount point path - * @param args argument vector - * @return the communication channel on success, NULL on failure - */ -struct fuse_chan *fuse_session_mount(const char *mountpoint, - struct fuse_args *args); - -/** - * Create a low level session + * Returns a session structure suitable for passing to + * fuse_session_mount() and fuse_session_loop(). * - * Known parameters in `args` are removed. If there are any unknown - * arguments, an error is printed to stderr and the function returns - * NULL. + * Known arguments are defined in `struct fuse_opt fuse_ll_opts[]` and + * `struct fuse_opt fuse_mount_opts[]`. If there are any unknown + * arguments, an error message will be printed to stderr and the + * function will return NULL. * * If the --help or --version parameters are specified, the function * prints the requsted information to stdout and returns NULL. @@ -1616,14 +1593,14 @@ struct fuse_session *fuse_session_new(struct fuse_args *args, size_t op_size, void *userdata); /** - * Assign a channel to a session + * Mount a FUSE file system. * - * If a session is destroyed, the assigned channel is also destroyed + * @param mountpoint the mount point path + * @param se session object * - * @param se the session - * @param ch the channel - */ -void fuse_session_add_chan(struct fuse_session *se, struct fuse_chan *ch); + * @return 0 on success, -1 on failure. + **/ +int fuse_session_mount(struct fuse_session *se, const char *mountpoint); /** * Enter a single threaded, blocking event loop. @@ -1672,13 +1649,11 @@ void fuse_session_reset(struct fuse_session *se); int fuse_session_exited(struct fuse_session *se); /** - * Remove the channel from a session + * Unmount the file system * - * If the channel is not assigned to a session, then this is a no-op - * - * @param ch the channel to remove + * @param se the session */ -void fuse_session_remove_chan(struct fuse_chan *ch); +void fuse_session_unmount(struct fuse_session *se); /** * Destroy a session @@ -1687,15 +1662,6 @@ void fuse_session_remove_chan(struct fuse_chan *ch); */ void fuse_session_destroy(struct fuse_session *se); -/** - * Umount a FUSE mountpoint - * - * @param mountpoint the mount point path - * @param ch the communication channel - */ -void fuse_session_unmount(const char *mountpoint, struct fuse_chan *ch); - - /* ----------------------------------------------------------- * * Request processing (for custom event loops) * * ----------------------------------------------------------- */ @@ -1710,7 +1676,7 @@ void fuse_session_unmount(const char *mountpoint, struct fuse_chan *ch); * @param ch channel on which the request was received */ void fuse_session_process_buf(struct fuse_session *se, - const struct fuse_buf *buf, struct fuse_chan *ch); + const struct fuse_buf *buf); /** * Receive a raw request supplied in a generic buffer @@ -1723,36 +1689,7 @@ void fuse_session_process_buf(struct fuse_session *se, * @param ch the channel * @return the actual size of the raw request, or -errno on error */ -int fuse_session_receive_buf(struct fuse_session *se, struct fuse_buf *buf, - struct fuse_chan *ch); - -/* ----------------------------------------------------------- * - * Channel interface * - * ----------------------------------------------------------- */ - -/** - * Return channel assigned to the session - * - * @param se the session - * @return the channel - */ -struct fuse_chan *fuse_session_chan(struct fuse_session *se); - - -/** - * Obtain counted reference to the channel - * - * @param ch the channel - * @return the channel - */ -struct fuse_chan *fuse_chan_get(struct fuse_chan *ch); - -/** - * Drop counted reference to a channel - * - * @param ch the channel - */ -void fuse_chan_put(struct fuse_chan *ch); +int fuse_session_receive_buf(struct fuse_session *se, struct fuse_buf *buf); #ifdef __cplusplus } @@ -4631,7 +4631,7 @@ void fuse_stop_cleanup_thread(struct fuse *f) } } -struct fuse *fuse_new(struct fuse_chan *ch, struct fuse_args *args, +struct fuse *fuse_new(struct fuse_args *args, const struct fuse_operations *op, size_t op_size, void *user_data) { @@ -4721,13 +4721,13 @@ struct fuse *fuse_new(struct fuse_chan *ch, struct fuse_args *args, 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(); goto out_free_fs; } - fuse_session_add_chan(f->se, ch); - if (f->conf.debug) { fprintf(stderr, "nopath: %i\n", f->conf.nopath); } @@ -4837,12 +4837,11 @@ void fuse_destroy(struct fuse *f) fuse_delete_context_key(); } -struct fuse_chan *fuse_mount(const char *mountpoint, struct fuse_args *args) -{ - return fuse_session_mount(mountpoint, args); +int fuse_mount(struct fuse *f, const char *mountpoint) { + return fuse_session_mount(fuse_get_session(f), mountpoint); } -void fuse_unmount(const char *mountpoint, struct fuse_chan *ch) -{ - fuse_session_unmount(mountpoint, ch); + +void fuse_unmount(struct fuse *f) { + return fuse_session_unmount(fuse_get_session(f)); } diff --git a/lib/fuse_i.h b/lib/fuse_i.h index dca588a..c4d0709 100644 --- a/lib/fuse_i.h +++ b/lib/fuse_i.h @@ -11,13 +11,16 @@ struct fuse_chan; struct fuse_ll; +struct mount_opts; struct fuse_session { struct fuse_ll *f; + char *mountpoint; volatile int exited; struct fuse_chan *ch; + struct mount_opts *mo; }; struct fuse_chan { @@ -116,7 +119,11 @@ struct fuse_module { int fuse_chan_clearfd(struct fuse_chan *ch); void fuse_chan_close(struct fuse_chan *ch); -/** +/* ----------------------------------------------------------- * + * Channel interface * + * ----------------------------------------------------------- */ + + /** * Create a new channel * * @param op channel operations @@ -133,8 +140,56 @@ struct fuse_chan *fuse_chan_new(int fd); */ struct fuse_session *fuse_chan_session(struct fuse_chan *ch); +/** + * Remove the channel from a session + * + * If the channel is not assigned to a session, then this is a no-op + * + * @param ch the channel to remove + */ +void fuse_session_remove_chan(struct fuse_chan *ch); + +/** + * Assign a channel to a session + * + * If a session is destroyed, the assigned channel is also destroyed + * + * @param se the session + * @param ch the channel + */ +void fuse_session_add_chan(struct fuse_session *se, struct fuse_chan *ch); + +/** + * Return channel assigned to the session + * + * @param se the session + * @return the channel + */ +struct fuse_chan *fuse_session_chan(struct fuse_session *se); + +/** + * Obtain counted reference to the channel + * + * @param ch the channel + * @return the channel + */ +struct fuse_chan *fuse_chan_get(struct fuse_chan *ch); + +/** + * Drop counted reference to a channel + * + * @param ch the channel + */ +void fuse_chan_put(struct fuse_chan *ch); + + +struct mount_opts *parse_mount_opts(struct fuse_args *args); +void destroy_mount_opts(struct mount_opts *mo); +void fuse_mount_help(void); +void fuse_mount_version(void); + void fuse_kern_unmount(const char *mountpoint, int fd); -int fuse_kern_mount(const char *mountpoint, struct fuse_args *args); +int fuse_kern_mount(const char *mountpoint, struct mount_opts *mo); int fuse_send_reply_iov_nofree(fuse_req_t req, int error, struct iovec *iov, int count); diff --git a/lib/fuse_lowlevel.c b/lib/fuse_lowlevel.c index 92265cc..43539da 100755 --- a/lib/fuse_lowlevel.c +++ b/lib/fuse_lowlevel.c @@ -2437,10 +2437,9 @@ static int fuse_ll_copy_from_pipe(struct fuse_bufvec *dst, } void fuse_session_process_buf(struct fuse_session *se, - const struct fuse_buf *buf, - struct fuse_chan *ch) + const struct fuse_buf *buf) { - fuse_session_process_buf_int(se, buf, ch); + fuse_session_process_buf_int(se, buf, se->ch); } void fuse_session_process_buf_int(struct fuse_session *se, @@ -2666,15 +2665,17 @@ 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) 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; default: @@ -2706,6 +2707,7 @@ void fuse_session_destroy(struct fuse_session *se) { fuse_ll_destroy(se->f); fuse_chan_put(se->ch); + destroy_mount_opts(se->mo); free(se); } @@ -2716,10 +2718,9 @@ static void fuse_ll_pipe_destructor(void *data) fuse_ll_pipe_free(llp); } -int fuse_session_receive_buf(struct fuse_session *se, struct fuse_buf *buf, - struct fuse_chan *ch) +int fuse_session_receive_buf(struct fuse_session *se, struct fuse_buf *buf) { - return fuse_session_receive_buf_int(se, buf, ch); + return fuse_session_receive_buf_int(se, buf, se->ch); } int fuse_session_receive_buf_int(struct fuse_session *se, struct fuse_buf *buf, @@ -2878,6 +2879,7 @@ struct fuse_session *fuse_session_new(struct fuse_args *args, int err; struct fuse_ll *f; struct fuse_session *se; + struct mount_opts *mo; if (sizeof(struct fuse_lowlevel_ops) < op_size) { fprintf(stderr, "fuse: warning: library too old, some operations may not work\n"); @@ -2890,6 +2892,16 @@ struct fuse_session *fuse_session_new(struct fuse_args *args, goto out; } + /* 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; + + if (f->debug) + fprintf(stderr, "FUSE library version: %s\n", PACKAGE_VERSION); + f->conn.async_read = 1; f->conn.max_write = UINT_MAX; f->conn.max_readahead = UINT_MAX; @@ -2910,12 +2922,6 @@ struct fuse_session *fuse_session_new(struct fuse_args *args, goto out_free; } - if (fuse_opt_parse(args, f, fuse_ll_opts, fuse_ll_opt_proc) == -1) - goto out_key_destroy; - - if (f->debug) - fprintf(stderr, "FUSE library version: %s\n", PACKAGE_VERSION); - memcpy(&f->op, op, op_size); f->owner = getuid(); f->userdata = userdata; @@ -2927,19 +2933,21 @@ struct fuse_session *fuse_session_new(struct fuse_args *args, } memset(se, 0, sizeof(*se)); se->f = f; + se->mo = mo; return se; out_key_destroy: pthread_key_delete(f->pipe_key); out_free: + free(mo); +out_free0: pthread_mutex_destroy(&f->lock); free(f); out: return NULL; } -struct fuse_chan *fuse_session_mount(const char *mountpoint, - struct fuse_args *args) +int fuse_session_mount(struct fuse_session *se, const char *mountpoint) { struct fuse_chan *ch; int fd; @@ -2954,23 +2962,39 @@ struct fuse_chan *fuse_session_mount(const char *mountpoint, close(fd); } while (fd >= 0 && fd <= 2); - fd = fuse_kern_mount(mountpoint, args); + /* Open channel */ + fd = fuse_kern_mount(mountpoint, se->mo); if (fd == -1) - return NULL; + return -1; ch = fuse_chan_new(fd); if (!ch) - fuse_kern_unmount(mountpoint, fd); + goto error_out; + + /* Add channel to session */ + fuse_session_add_chan(se, ch); - return ch; + /* Save mountpoint */ + se->mountpoint = strdup(mountpoint); + if (se->mountpoint == NULL) + goto error_out; + + return 0; + +error_out: + fuse_kern_unmount(mountpoint, fd); + return -1; } -void fuse_session_unmount(const char *mountpoint, struct fuse_chan *ch) +void fuse_session_unmount(struct fuse_session *se) { - if (mountpoint) { - int fd = ch ? fuse_chan_clearfd(ch) : -1; - fuse_kern_unmount(mountpoint, fd); - fuse_chan_put(ch); + fuse_session_remove_chan(se->ch); + if (se->mountpoint) { + int fd = se->ch ? fuse_chan_clearfd(se->ch) : -1; + fuse_kern_unmount(se->mountpoint, fd); + fuse_chan_put(se->ch); + free(se->mountpoint); + se->mountpoint = NULL; } } diff --git a/lib/fuse_versionscript b/lib/fuse_versionscript index eacd37a..ee9c9d7 100644 --- a/lib/fuse_versionscript +++ b/lib/fuse_versionscript @@ -4,8 +4,6 @@ FUSE_3.0 { fuse_exit; fuse_loop; fuse_loop_mt; - fuse_chan_destroy; - fuse_chan_fd; fuse_reply_attr; fuse_reply_buf; fuse_reply_entry; @@ -15,13 +13,11 @@ FUSE_3.0 { fuse_reply_write; fuse_reply_xattr; fuse_req_userdata; - fuse_session_add_chan; fuse_session_destroy; fuse_session_exit; fuse_session_exited; fuse_session_loop; fuse_session_loop_mt; - fuse_session_chan; fuse_session_reset; fuse_opt_parse; fuse_opt_add_opt; @@ -48,7 +44,6 @@ FUSE_3.0 { fuse_reply_lock; fuse_req_interrupt_func; fuse_req_interrupted; - fuse_session_remove_chan; fuse_unmount; fuse_session_unmount; fuse_fs_access; diff --git a/lib/helper.c b/lib/helper.c index cd1a54b..7ee767b 100644 --- a/lib/helper.c +++ b/lib/helper.c @@ -227,30 +227,32 @@ 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, - char **mountpoint, int *multithreaded, void *user_data) + const struct fuse_operations *op, size_t op_size, + int *multithreaded, void *user_data) { struct fuse_args args = FUSE_ARGS_INIT(argc, argv); - struct fuse_chan *ch; struct fuse *fuse; + char *mountpoint; int foreground; int res; - res = fuse_parse_cmdline(&args, mountpoint, multithreaded, &foreground); + res = fuse_parse_cmdline(&args, &mountpoint, multithreaded, &foreground); if (res == -1) return NULL; - ch = fuse_mount(*mountpoint, &args); - if (!ch) { + fuse = fuse_new(&args, op, op_size, user_data); + if (fuse == NULL) { fuse_opt_free_args(&args); - goto err_free; + free(mountpoint); + return NULL; } - fuse = fuse_new(ch, &args, op, op_size, user_data); - fuse_opt_free_args(&args); - if (fuse == NULL) - goto err_unmount; + res = fuse_mount(fuse, mountpoint); + free(mountpoint); + if (res != 0) + goto err_out1; res = fuse_daemonize(foreground); if (res == -1) @@ -263,33 +265,29 @@ static struct fuse *fuse_setup(int argc, char *argv[], return fuse; err_unmount: - fuse_unmount(*mountpoint, ch); - if (fuse) - fuse_destroy(fuse); -err_free: - free(*mountpoint); + fuse_unmount(fuse); +err_out1: + fuse_destroy(fuse); + fuse_opt_free_args(&args); return NULL; } -static void fuse_teardown(struct fuse *fuse, char *mountpoint) +static void fuse_teardown(struct fuse *fuse) { struct fuse_session *se = fuse_get_session(fuse); - struct fuse_chan *ch = fuse_session_chan(se); fuse_remove_signal_handlers(se); - fuse_unmount(mountpoint, ch); + fuse_unmount(fuse); fuse_destroy(fuse); - free(mountpoint); } int fuse_main_real(int argc, char *argv[], const struct fuse_operations *op, size_t op_size, void *user_data) { struct fuse *fuse; - char *mountpoint; int multithreaded; int res; - fuse = fuse_setup(argc, argv, op, op_size, &mountpoint, + fuse = fuse_setup(argc, argv, op, op_size, &multithreaded, user_data); if (fuse == NULL) return 1; @@ -299,7 +297,7 @@ int fuse_main_real(int argc, char *argv[], const struct fuse_operations *op, else res = fuse_loop(fuse); - fuse_teardown(fuse, mountpoint); + fuse_teardown(fuse); if (res == -1) return 1; diff --git a/lib/mount.c b/lib/mount.c index b2b841d..fb17c00 100644 --- a/lib/mount.c +++ b/lib/mount.c @@ -57,14 +57,11 @@ enum { KEY_MTAB_OPT, KEY_ALLOW_ROOT, KEY_RO, - KEY_HELP, - KEY_VERSION, }; struct mount_opts { int allow_other; int allow_root; - int ishelp; int flags; int nonempty; int auto_unmount; @@ -118,14 +115,10 @@ static const struct fuse_opt fuse_mount_opts[] = { FUSE_OPT_KEY("dirsync", KEY_KERN_FLAG), FUSE_OPT_KEY("atime", KEY_KERN_FLAG), FUSE_OPT_KEY("noatime", KEY_KERN_FLAG), - 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 mount_help(void) +void fuse_mount_help(void) { printf( " -o allow_other allow access to other users\n" @@ -146,7 +139,7 @@ static void exec_fusermount(const char *argv[]) execvp(FUSERMOUNT_PROG, (char **) argv); } -static void mount_version(void) +void fuse_mount_version(void) { int pid = fork(); if (!pid) { @@ -230,16 +223,6 @@ static int fuse_mount_opt_proc(void *data, const char *arg, int key, case KEY_MTAB_OPT: return fuse_opt_add_opt(&mo->mtab_opts, arg); - - case KEY_HELP: - mount_help(); - mo->ishelp = 1; - break; - - case KEY_VERSION: - mount_version(); - mo->ishelp = 1; - break; } /* Pass through unknown options */ @@ -568,67 +551,84 @@ static int get_mnt_flag_opts(char **mnt_optsp, int flags) return 0; } -int fuse_kern_mount(const char *mountpoint, struct fuse_args *args) +struct mount_opts *parse_mount_opts(struct fuse_args *args) { - struct mount_opts mo; - int res = -1; - char *mnt_opts = NULL; + struct mount_opts *mo; + + mo = (struct mount_opts*) malloc(sizeof(struct mount_opts)); + if (mo == NULL) + return NULL; - memset(&mo, 0, sizeof(mo)); - mo.flags = MS_NOSUID | MS_NODEV; + memset(mo, 0, sizeof(struct mount_opts)); + mo->flags = MS_NOSUID | MS_NODEV; if (args && - fuse_opt_parse(args, &mo, fuse_mount_opts, fuse_mount_opt_proc) == -1) - return -1; + fuse_opt_parse(args, mo, fuse_mount_opts, fuse_mount_opt_proc) == -1) + goto err_out; - if (mo.allow_other && mo.allow_root) { + if (mo->allow_other && mo->allow_root) { fprintf(stderr, "fuse: 'allow_other' and 'allow_root' options are mutually exclusive\n"); - goto out; + goto err_out; } - res = 0; - if (mo.ishelp) - goto out; + + return mo; + +err_out: + destroy_mount_opts(mo); + return NULL; +} + +void destroy_mount_opts(struct mount_opts *mo) +{ + free(mo->fsname); + free(mo->subtype); + free(mo->fusermount_opts); + free(mo->subtype_opt); + free(mo->kernel_opts); + free(mo->mtab_opts); + free(mo); +} + + +int fuse_kern_mount(const char *mountpoint, struct mount_opts *mo) +{ + int res = -1; + char *mnt_opts = NULL; res = -1; - if (get_mnt_flag_opts(&mnt_opts, mo.flags) == -1) + if (get_mnt_flag_opts(&mnt_opts, mo->flags) == -1) goto out; - if (mo.kernel_opts && fuse_opt_add_opt(&mnt_opts, mo.kernel_opts) == -1) + if (mo->kernel_opts && fuse_opt_add_opt(&mnt_opts, mo->kernel_opts) == -1) goto out; - if (mo.mtab_opts && fuse_opt_add_opt(&mnt_opts, mo.mtab_opts) == -1) + if (mo->mtab_opts && fuse_opt_add_opt(&mnt_opts, mo->mtab_opts) == -1) goto out; - res = fuse_mount_sys(mountpoint, &mo, mnt_opts); + res = fuse_mount_sys(mountpoint, mo, mnt_opts); if (res == -2) { - if (mo.fusermount_opts && - fuse_opt_add_opt(&mnt_opts, mo.fusermount_opts) == -1) + if (mo->fusermount_opts && + fuse_opt_add_opt(&mnt_opts, mo->fusermount_opts) == -1) goto out; - if (mo.subtype) { + if (mo->subtype) { char *tmp_opts = NULL; res = -1; if (fuse_opt_add_opt(&tmp_opts, mnt_opts) == -1 || - fuse_opt_add_opt(&tmp_opts, mo.subtype_opt) == -1) { + fuse_opt_add_opt(&tmp_opts, mo->subtype_opt) == -1) { free(tmp_opts); goto out; } - res = fuse_mount_fusermount(mountpoint, &mo, tmp_opts, 1); + res = fuse_mount_fusermount(mountpoint, mo, tmp_opts, 1); free(tmp_opts); if (res == -1) - res = fuse_mount_fusermount(mountpoint, &mo, + res = fuse_mount_fusermount(mountpoint, mo, mnt_opts, 0); } else { - res = fuse_mount_fusermount(mountpoint, &mo, mnt_opts, 0); + res = fuse_mount_fusermount(mountpoint, mo, mnt_opts, 0); } } out: free(mnt_opts); - free(mo.fsname); - free(mo.subtype); - free(mo.fusermount_opts); - free(mo.subtype_opt); - free(mo.kernel_opts); - free(mo.mtab_opts); return res; } diff --git a/lib/mount_bsd.c b/lib/mount_bsd.c index 40ef93f..0d886b0 100644 --- a/lib/mount_bsd.c +++ b/lib/mount_bsd.c @@ -31,15 +31,12 @@ enum { KEY_ALLOW_ROOT, KEY_RO, - KEY_HELP, - KEY_VERSION, KEY_KERN }; struct mount_opts { int allow_other; int allow_root; - int ishelp; char *kernel_opts; }; @@ -51,10 +48,6 @@ static const struct fuse_opt fuse_mount_opts[] = { { "allow_root", offsetof(struct mount_opts, allow_root), 1 }, FUSE_OPT_KEY("allow_root", KEY_ALLOW_ROOT), FUSE_OPT_KEY("-r", KEY_RO), - FUSE_OPT_KEY("-h", KEY_HELP), - FUSE_OPT_KEY("--help", KEY_HELP), - FUSE_OPT_KEY("-V", KEY_VERSION), - FUSE_OPT_KEY("--version", KEY_VERSION), /* standard FreeBSD mount options */ FUSE_DUAL_OPT_KEY("dev", KEY_KERN), FUSE_DUAL_OPT_KEY("async", KEY_KERN), @@ -100,14 +93,14 @@ static const struct fuse_opt fuse_mount_opts[] = { FUSE_OPT_END }; -static void mount_help(void) +void fuse_mount_help(void) { printf(" -o allow_root allow access to root\n"); system(FUSERMOUNT_PROG " --help"); fputc('\n', stderr); } -static void mount_version(void) +void fuse_mount_version(void) { system(FUSERMOUNT_PROG " --version"); } @@ -130,16 +123,6 @@ static int fuse_mount_opt_proc(void *data, const char *arg, int key, case KEY_KERN: return fuse_opt_add_opt(&mo->kernel_opts, arg); - - case KEY_HELP: - mount_help(); - mo->ishelp = 1; - break; - - case KEY_VERSION: - mount_version(); - mo->ishelp = 1; - break; } /* Pass through unknown options */ @@ -314,30 +297,44 @@ out: return fd; } -int fuse_kern_mount(const char *mountpoint, struct fuse_args *args) +struct mount_opts *parse_mount_opts(struct fuse_args *args) { - struct mount_opts mo; - int res = -1; + struct mount_opts *mo; - memset(&mo, 0, sizeof(mo)); - /* mount util should not try to spawn the daemon */ - setenv("MOUNT_FUSEFS_SAFE", "1", 1); - /* to notify the mount util it's called from lib */ - setenv("MOUNT_FUSEFS_CALL_BY_LIB", "1", 1); + mo = (struct mount_opts*) malloc(sizeof(struct mount_opts)); + if (mo == NULL) + return NULL; + + memset(mo, 0, sizeof(struct mount_opts)); if (args && - fuse_opt_parse(args, &mo, fuse_mount_opts, fuse_mount_opt_proc) == -1) - return -1; + fuse_opt_parse(args, mo, fuse_mount_opts, fuse_mount_opt_proc) == -1) + goto err_out; - if (mo.allow_other && mo.allow_root) { + if (mo->allow_other && mo->allow_root) { fprintf(stderr, "fuse: 'allow_other' and 'allow_root' options are mutually exclusive\n"); - goto out; + goto err_out; } - if (mo.ishelp) - return 0; - res = fuse_mount_core(mountpoint, mo.kernel_opts); -out: - free(mo.kernel_opts); - return res; + return mo; + +err_out: + destroy_mount_opts(mo); + return NULL; +} + +void destroy_mount_opts(struct mount_opts *mo) +{ + free(mo->kernel_opts); + free(mo); +} + +int fuse_kern_mount(const char *mountpoint, struct mount_opts *mo) +{ + /* mount util should not try to spawn the daemon */ + setenv("MOUNT_FUSEFS_SAFE", "1", 1); + /* to notify the mount util it's called from lib */ + setenv("MOUNT_FUSEFS_CALL_BY_LIB", "1", 1); + + return fuse_mount_core(mountpoint, mo->kernel_opts); } |