aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Nikolaus Rath <Nikolaus@rath.org>2016-10-02 11:30:43 -0700
committerGravatar Nikolaus Rath <Nikolaus@rath.org>2016-10-02 13:56:40 -0700
commit5698ee09cf7a8495da70659ffae1eaec9f57db27 (patch)
tree798a58a4f49d7f82e3f948463daad4405173483e
parentf164e9b8ca319dd1279384ff495b5fa91e778d9e (diff)
Turn struct fuse_chan into an implementation detail
The only struct fuse_chan that's accessible to the user application is the "master" channel that is returned by fuse_mount and stored in struct fuse_session. When using the multi-threaded main loop with the "clone_fd" option, each worker thread gets its own struct fuse_chan. However, none of these are available to the user application, nor do they hold references to struct fuse_session (the pointer is always null). Therefore, any presence of struct fuse_chan can be removed without loss of functionality by relying on struct fuse_session instead. This reduces the number of API functions and removes a potential source of confusion (since the new API no longer looks as if it might be possible to add multiple channels to one session, or to share one channel between multiple sessions). Fixes issue #17.
-rw-r--r--ChangeLog.rst67
-rw-r--r--doc/developer-notes.rst28
-rw-r--r--example/fuse_lo-plus.c40
-rwxr-xr-xexample/hello_ll.c46
-rw-r--r--include/fuse.h43
-rw-r--r--include/fuse_common.h1
-rw-r--r--include/fuse_lowlevel.h99
-rw-r--r--lib/fuse.c17
-rw-r--r--lib/fuse_i.h59
-rwxr-xr-xlib/fuse_lowlevel.c72
-rw-r--r--lib/fuse_versionscript5
-rw-r--r--lib/helper.c44
-rw-r--r--lib/mount.c98
-rw-r--r--lib/mount_bsd.c71
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
}
diff --git a/lib/fuse.c b/lib/fuse.c
index 47b72d0..bd7dc27 100644
--- a/lib/fuse.c
+++ b/lib/fuse.c
@@ -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);
}