aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.travis.yml3
-rw-r--r--AUTHORS9
-rw-r--r--ChangeLog.rst28
-rw-r--r--configure.ac2
-rw-r--r--[-rwxr-xr-x]example/cusexmp.c0
-rw-r--r--[-rwxr-xr-x]example/fioc.c0
-rw-r--r--[-rwxr-xr-x]example/fioclient.c0
-rw-r--r--[-rwxr-xr-x]example/fsel.c0
-rw-r--r--[-rwxr-xr-x]example/fselclient.c0
-rw-r--r--example/fuse_lo-plus.c51
-rw-r--r--[-rwxr-xr-x]example/fusexmp.c0
-rw-r--r--[-rwxr-xr-x]example/fusexmp_fh.c0
-rw-r--r--[-rwxr-xr-x]example/hello.c0
-rw-r--r--[-rwxr-xr-x]example/hello_ll.c42
-rw-r--r--[-rwxr-xr-x]example/null.c0
-rw-r--r--include/fuse.h14
-rw-r--r--include/fuse_common.h28
-rw-r--r--include/fuse_lowlevel.h108
-rw-r--r--lib/Makefile.am6
-rw-r--r--lib/buffer.c3
-rw-r--r--lib/cuse_lowlevel.c33
-rw-r--r--lib/fuse.c103
-rw-r--r--lib/fuse_i.h59
-rw-r--r--lib/fuse_loop.c7
-rw-r--r--[-rwxr-xr-x]lib/fuse_loop_mt.c64
-rw-r--r--[-rwxr-xr-x]lib/fuse_lowlevel.c209
-rw-r--r--lib/fuse_mt.c25
-rw-r--r--lib/fuse_opt.c3
-rw-r--r--lib/fuse_session.c112
-rw-r--r--[-rwxr-xr-x]lib/fuse_signals.c2
-rw-r--r--lib/fuse_versionscript5
-rw-r--r--lib/helper.c242
-rw-r--r--lib/mount.c7
-rw-r--r--lib/mount_bsd.c6
-rw-r--r--lib/mount_util.c2
-rw-r--r--test/conftest.py10
-rwxr-xr-xtest/test_examples.py106
-rwxr-xr-xtest/test_fuse.py5
-rw-r--r--test/util.py17
39 files changed, 658 insertions, 653 deletions
diff --git a/.travis.yml b/.travis.yml
index b90c8bf..6d2f313 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -16,6 +16,7 @@ addons:
packages:
- doxygen
- libtool
+ - valgrind
- automake
- autoconf
- gcc-6
@@ -23,6 +24,8 @@ install:
- sudo python -m pip install pytest
script:
- $CC --version
+ - libtool --version
+ - valgrind --version
- ./makeconf.sh
- ./configure
- CFLAGS="-fsanitize=address,undefined -g -O1 -Wall -Werror" make
diff --git a/AUTHORS b/AUTHORS
index a43c073..b32cc92 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -16,19 +16,26 @@ Contributors
CUSE has been written by Tejun Heo <teheo@suse.de>. Furthermore, the
following people have contributed patches (autogenerated list):
+Alex Richman <alex@richman.io>
Anatol Pomozov <anatol.pomozov@gmail.com>
+Antonio SJ Musumeci <trapexit@spawn.link>
+bobrofon <ifbossfor@ya.ru>
Christopher Harrison <ch12@sanger.ac.uk>
Csaba Henk <csaba.henk@creo.hu>
cvs2git <>
Dalvik Khertel <khertel@outlook.com>
Daniel Thau <danthau@bedrocklinux.org>
David McNab <david@rebirthing.co.nz>
+David Sheets <sheets@alum.mit.edu>
Emmanuel Dreyfus <manu@netbsd.org>
Enke Chen <enkechen@yahoo.com>
+Eric Engestrom <eric@engestrom.ch>
Eric Wong <normalperson@yhbt.net>
Fabrice Bauzac <fbauzac@amadeus.com>
Feng Shuo <steve.shuo.feng@gmail.com>
+Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
Ikey Doherty <michael.i.doherty@intel.com>
+Jan Blumschein <jan@jan-blumschein.de>
Joachim Schiele <joachim.schiele@daimler.com>
Joachim Schiele <js@lastlog.de>
John Muir <john@jmuir.com>
@@ -48,5 +55,7 @@ Reuben Hawkins <reubenhwk@gmail.com>
Richard W.M. Jones <rjones@redhat.com>
Riku Voipio <riku.voipio@linaro.org>
Roland Bauerschmidt <rb@debian.org>
+Sam Stuewe <halosghost@archlinux.info>
Sebastian Pipping <sebastian@pipping.org>
therealneworld@gmail.com <therealneworld@gmail.com>
+Winfried Koehler <w_scan@gmx-topmail.de>
diff --git a/ChangeLog.rst b/ChangeLog.rst
index a15b55a..78f6d51 100644
--- a/ChangeLog.rst
+++ b/ChangeLog.rst
@@ -1,13 +1,24 @@
-Unreleased Changes
-==================
+FUSE 3.0.0pre0 (2016-10-03)
+============================
+
+* This is a preview release. Functionality and API may still change
+ before the 3.0.0 release.
* The `fuse_lowlevel_new` function has been renamed to
- `fuse_session_new`.
+ `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.
-* 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.
+* 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`.
@@ -76,6 +87,9 @@ Unreleased Changes
File systems that use `fuse_main` are not affected by this change.
+ For integration with custom event loops, the new `fuse_session_fd`
+ function provides the file descriptor that's used for communication
+ with the kernel.
* Added *clone_fd* option. This creates a separate device file
descriptor for each processing thread, which might improve
diff --git a/configure.ac b/configure.ac
index db5852b..39bddc7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,4 +1,4 @@
-AC_INIT(fuse, 3.0.0_pre0)
+AC_INIT(fuse, 3.0.0pre0)
AC_PREREQ(2.59d)
AC_CONFIG_MACRO_DIR([m4])
AC_CANONICAL_TARGET
diff --git a/example/cusexmp.c b/example/cusexmp.c
index 8d22075..8d22075 100755..100644
--- a/example/cusexmp.c
+++ b/example/cusexmp.c
diff --git a/example/fioc.c b/example/fioc.c
index 368f807..368f807 100755..100644
--- a/example/fioc.c
+++ b/example/fioc.c
diff --git a/example/fioclient.c b/example/fioclient.c
index 704f24b..704f24b 100755..100644
--- a/example/fioclient.c
+++ b/example/fioclient.c
diff --git a/example/fsel.c b/example/fsel.c
index b496c9a..b496c9a 100755..100644
--- a/example/fsel.c
+++ b/example/fsel.c
diff --git a/example/fselclient.c b/example/fselclient.c
index 637cb07..637cb07 100755..100644
--- a/example/fselclient.c
+++ b/example/fselclient.c
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/fusexmp.c b/example/fusexmp.c
index eae3562..eae3562 100755..100644
--- a/example/fusexmp.c
+++ b/example/fusexmp.c
diff --git a/example/fusexmp_fh.c b/example/fusexmp_fh.c
index 84fce3f..84fce3f 100755..100644
--- a/example/fusexmp_fh.c
+++ b/example/fusexmp_fh.c
diff --git a/example/hello.c b/example/hello.c
index 3c24c8b..3c24c8b 100755..100644
--- a/example/hello.c
+++ b/example/hello.c
diff --git a/example/hello_ll.c b/example/hello_ll.c
index 07529d1..b7e77cd 100755..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/example/null.c b/example/null.c
index 1ff1954..1ff1954 100755..100644
--- a/example/null.c
+++ b/example/null.c
diff --git a/include/fuse.h b/include/fuse.h
index c3fea2d..719623a 100644
--- a/include/fuse.h
+++ b/include/fuse.h
@@ -608,8 +608,7 @@ struct fuse_context {
* main() function.
*
* This function does the following:
- * - parses command line options (-d -s and -h)
- * - passes relevant mount options to the fuse_mount()
+ * - parses command line options
* - installs signal handlers for INT, HUP, TERM and PIPE
* - registers an exit handler to unmount the filesystem on program exit
* - creates a fuse handle
@@ -640,14 +639,13 @@ struct fuse_context {
/**
* Create a new FUSE filesystem.
*
- * Known arguments are defined in `struct fuse_opt fuse_lib_opts[]`,
+ * Known options 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.
+ * fuse_ll_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 requested information to stdout and returns NULL.
+ * If the --help option is specified, the function writes a help text
+ * to stdout and returns NULL.
*
* @param args argument vector
* @param op the filesystem operations
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
@@ -209,34 +209,6 @@ 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
*
* @param foreground if true, stay in the foreground
diff --git a/include/fuse_lowlevel.h b/include/fuse_lowlevel.h
index f0f0e0b..f2d9caa 100644
--- a/include/fuse_lowlevel.h
+++ b/include/fuse_lowlevel.h
@@ -98,7 +98,14 @@ struct fuse_entry_param {
double entry_timeout;
};
-/** Additional context associated with requests */
+/**
+ * Additional context associated with requests.
+ *
+ * Note that the reported client uid, gid and pid may be zero in some
+ * situations. For example, if the FUSE file system is running in a
+ * PID or user namespace but then accessed from outside the namespace,
+ * there is no valid uid/pid/gid that could be reported.
+ */
struct fuse_ctx {
/** User ID of the calling process */
uid_t uid;
@@ -109,7 +116,7 @@ struct fuse_ctx {
/** Thread ID of the calling process */
pid_t pid;
- /** Umask of the calling process (introduced in version 2.8) */
+ /** Umask of the calling process */
mode_t umask;
};
@@ -1560,23 +1567,81 @@ 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.
*
* Returns a session structure suitable for passing to
* fuse_session_mount() and fuse_session_loop().
*
- * 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.
+ * Known options are defined in `struct fuse_opt fuse_ll_opts[]` and
+ * `struct fuse_opt fuse_mount_opts[]`. If not all options are known,
+ * an error message is written to stderr and the function returns NULL.
*
* @param args argument vector
* @param op the (low-level) filesystem operations
@@ -1663,10 +1728,26 @@ void fuse_session_unmount(struct fuse_session *se);
void fuse_session_destroy(struct fuse_session *se);
/* ----------------------------------------------------------- *
- * Request processing (for custom event loops) *
+ * Custom event loop support *
* ----------------------------------------------------------- */
/**
+ * Return file descriptor for communication with kernel.
+ *
+ * The file selector can be used to integrate FUSE with a custom event
+ * loop. Whenever data is available for reading on the provided fd,
+ * the event loop should call `fuse_session_receive_buf` followed by
+ * `fuse_session_process_buf` to process the request.
+ *
+ * The returned file descriptor is valid until `fuse_session_unmount`
+ * is called.
+ *
+ * @param se the session
+ * @return a file descriptor
+ */
+int fuse_session_fd(struct fuse_session *se);
+
+/**
* Process a raw request supplied in a generic buffer
*
* The fuse_buf may contain a memory buffer or a pipe file descriptor.
@@ -1679,10 +1760,11 @@ void fuse_session_process_buf(struct fuse_session *se,
const struct fuse_buf *buf);
/**
- * Receive a raw request supplied in a generic buffer
+ * Read a raw request from the kernel into the supplied buffer.
*
- * The fuse_buf supplied to this function contains a suitably allocated memory
- * buffer. This may be overwritten with a file descriptor buffer.
+ * Depending on file system options, system capabilities, and request
+ * size the request is either read into a memory buffer or spliced
+ * into a temporary pipe.
*
* @param se the session
* @param buf the fuse_buf to store the request in
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 2ad0f15..e7f6fd4 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -17,16 +17,14 @@ else
iconv_source =
endif
-libfuse3_la_SOURCES = \
+libfuse3_la_SOURCES = \
fuse.c \
fuse_i.h \
fuse_loop.c \
fuse_loop_mt.c \
fuse_lowlevel.c \
fuse_misc.h \
- fuse_mt.c \
fuse_opt.c \
- fuse_session.c \
fuse_signals.c \
buffer.c \
cuse_lowlevel.c \
@@ -35,7 +33,7 @@ libfuse3_la_SOURCES = \
$(iconv_source) \
$(mount_source)
-libfuse3_la_LDFLAGS = -pthread @libfuse_libs@ -version-number 0:0:0 \
+libfuse3_la_LDFLAGS = -pthread @libfuse_libs@ -version-number 3:0:0 \
-Wl,--version-script,$(srcdir)/fuse_versionscript
if NETBSD
diff --git a/lib/buffer.c b/lib/buffer.c
index 17a595c..85309ac 100644
--- a/lib/buffer.c
+++ b/lib/buffer.c
@@ -2,6 +2,9 @@
FUSE: Filesystem in Userspace
Copyright (C) 2010 Miklos Szeredi <miklos@szeredi.hu>
+ Functions for dealing with `struct fuse_buf` and `struct
+ fuse_bufvec`.
+
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB
*/
diff --git a/lib/cuse_lowlevel.c b/lib/cuse_lowlevel.c
index 3dd79d8..03ae9a6 100644
--- a/lib/cuse_lowlevel.c
+++ b/lib/cuse_lowlevel.c
@@ -275,22 +275,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 +299,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) {
@@ -316,20 +311,13 @@ struct fuse_session *cuse_lowlevel_setup(int argc, char *argv[],
devname, strerror(errno));
goto err_se;
}
-
- ch = fuse_chan_new(fd);
- if (!ch) {
- close(fd);
- goto err_se;
- }
-
- fuse_session_add_chan(se, ch);
+ se->fd = fd;
res = fuse_set_signal_handlers(se);
if (res == -1)
goto err_se;
- res = fuse_daemonize(foreground);
+ res = fuse_daemonize(opts.foreground);
if (res == -1)
goto err_sig;
@@ -339,6 +327,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 bd7dc27..8bc6b0a 100644
--- a/lib/fuse.c
+++ b/lib/fuse.c
@@ -2,6 +2,9 @@
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
+ Implementation of the high-level FUSE API on top of the low-level
+ API.
+
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB
*/
@@ -77,7 +80,7 @@ struct fuse_config {
int auto_cache;
int intr;
int intr_signal;
- int help;
+ int show_help;
char *modules;
};
@@ -4318,9 +4321,8 @@ static int fuse_session_loop_remember(struct fuse *f)
int res = 0;
struct timespec now;
time_t next_clean;
- struct fuse_chan *ch = fuse_session_chan(se);
struct pollfd fds = {
- .fd = ch->fd,
+ .fd = se->fd,
.events = POLLIN
};
struct fuse_buf fbuf = {
@@ -4345,14 +4347,14 @@ static int fuse_session_loop_remember(struct fuse *f)
else
break;
} else if (res > 0) {
- res = fuse_session_receive_buf_int(se, &fbuf, ch);
+ res = fuse_session_receive_buf_int(se, &fbuf, NULL);
if (res == -EINTR)
continue;
if (res <= 0)
break;
- fuse_session_process_buf_int(se, &fbuf, ch);
+ fuse_session_process_buf_int(se, &fbuf, NULL);
} else {
timeout = fuse_clean_cache(f);
curr_time(&now);
@@ -4376,6 +4378,20 @@ int fuse_loop(struct fuse *f)
return fuse_session_loop(f->se);
}
+int fuse_loop_mt(struct fuse *f)
+{
+ if (f == NULL)
+ return -1;
+
+ int res = fuse_start_cleanup_thread(f);
+ if (res)
+ return -1;
+
+ res = fuse_session_loop_mt(fuse_get_session(f));
+ fuse_stop_cleanup_thread(f);
+ return res;
+}
+
void fuse_exit(struct fuse *f)
{
fuse_session_exit(f->se);
@@ -4410,15 +4426,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),
@@ -4453,6 +4465,7 @@ static const struct fuse_opt fuse_lib_opts[] = {
static void fuse_lib_help(void)
{
printf(
+"High-level options\n"
" -o hard_remove immediate removal (don't hide files)\n"
" -o use_ino let filesystem set inode numbers\n"
" -o readdir_ino try to fill in d_ino in readdir\n"
@@ -4471,8 +4484,8 @@ static void fuse_lib_help(void)
" -o nopath don't supply path if not necessary\n"
" -o intr allow requests to be interrupted\n"
" -o intr_signal=NUM signal to send on interrupt (%i)\n"
-" -o modules=M1[:M2...] names of modules to push onto filesystem stack\n"
-"\n", FUSE_DEFAULT_INTR_SIGNAL);
+" -o modules=M1[:M2...] names of modules to push onto filesystem stack\n\n",
+ FUSE_DEFAULT_INTR_SIGNAL);
}
static void fuse_lib_help_modules(void)
@@ -4498,14 +4511,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;
}
@@ -4640,6 +4648,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? */
@@ -4651,19 +4678,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;
@@ -4684,13 +4704,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;
@@ -4706,6 +4719,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;
@@ -4717,16 +4735,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);
@@ -4782,10 +4793,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_i.h b/lib/fuse_i.h
index c4d0709..c968321 100644
--- a/lib/fuse_i.h
+++ b/lib/fuse_i.h
@@ -9,31 +9,26 @@
#include "fuse.h"
#include "fuse_lowlevel.h"
-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;
+ int fd;
struct mount_opts *mo;
};
struct fuse_chan {
- struct fuse_session *se;
-
pthread_mutex_t lock;
int ctr;
int fd;
};
-
struct fuse_req {
struct fuse_ll *f;
+ struct fuse_session *se;
uint64_t unique;
int ctr;
pthread_mutex_t lock;
@@ -116,57 +111,10 @@ struct fuse_module {
int ctr;
};
-int fuse_chan_clearfd(struct fuse_chan *ch);
-void fuse_chan_close(struct fuse_chan *ch);
-
/* ----------------------------------------------------------- *
- * Channel interface *
+ * Channel interface (when using -o clone_fd) *
* ----------------------------------------------------------- */
- /**
- * Create a new channel
- *
- * @param op channel operations
- * @param fd file descriptor of the channel
- * @return the new channel object, or NULL on failure
- */
-struct fuse_chan *fuse_chan_new(int fd);
-
-/**
- * Query the session to which this channel is assigned
- *
- * @param ch the channel
- * @return the session, or NULL if the channel is not assigned
- */
-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
*
@@ -182,7 +130,6 @@ struct fuse_chan *fuse_chan_get(struct fuse_chan *ch);
*/
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);
diff --git a/lib/fuse_loop.c b/lib/fuse_loop.c
index 6df4a62..4a85b13 100644
--- a/lib/fuse_loop.c
+++ b/lib/fuse_loop.c
@@ -2,6 +2,8 @@
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
+ Implementation of the single-threaded FUSE session loop.
+
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB
*/
@@ -17,20 +19,19 @@
int fuse_session_loop(struct fuse_session *se)
{
int res = 0;
- struct fuse_chan *ch = fuse_session_chan(se);
struct fuse_buf fbuf = {
.mem = NULL,
};
while (!fuse_session_exited(se)) {
- res = fuse_session_receive_buf_int(se, &fbuf, ch);
+ res = fuse_session_receive_buf_int(se, &fbuf, NULL);
if (res == -EINTR)
continue;
if (res <= 0)
break;
- fuse_session_process_buf_int(se, &fbuf, ch);
+ fuse_session_process_buf_int(se, &fbuf, NULL);
}
free(fbuf.mem);
diff --git a/lib/fuse_loop_mt.c b/lib/fuse_loop_mt.c
index f482962..c925cd7 100755..100644
--- a/lib/fuse_loop_mt.c
+++ b/lib/fuse_loop_mt.c
@@ -2,6 +2,8 @@
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
+ Implementation of the multi-threaded FUSE session loop.
+
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB.
*/
@@ -21,6 +23,7 @@
#include <errno.h>
#include <sys/time.h>
#include <sys/ioctl.h>
+#include <assert.h>
/* Environment var controlling the thread stack size */
#define ENVNAME_THREAD_STACK "FUSE_THREAD_STACK"
@@ -40,13 +43,53 @@ struct fuse_mt {
int numworker;
int numavail;
struct fuse_session *se;
- struct fuse_chan *prevch;
struct fuse_worker main;
sem_t finish;
int exit;
int error;
};
+static struct fuse_chan *fuse_chan_new(int fd)
+{
+ struct fuse_chan *ch = (struct fuse_chan *) malloc(sizeof(*ch));
+ if (ch == NULL) {
+ fprintf(stderr, "fuse: failed to allocate channel\n");
+ return NULL;
+ }
+
+ memset(ch, 0, sizeof(*ch));
+ ch->fd = fd;
+ ch->ctr = 1;
+ fuse_mutex_init(&ch->lock);
+
+ return ch;
+}
+
+struct fuse_chan *fuse_chan_get(struct fuse_chan *ch)
+{
+ assert(ch->ctr > 0);
+ pthread_mutex_lock(&ch->lock);
+ ch->ctr++;
+ pthread_mutex_unlock(&ch->lock);
+
+ return ch;
+}
+
+void fuse_chan_put(struct fuse_chan *ch)
+{
+ if (ch == NULL)
+ return;
+ pthread_mutex_lock(&ch->lock);
+ ch->ctr--;
+ if (!ch->ctr) {
+ pthread_mutex_unlock(&ch->lock);
+ close(ch->fd);
+ pthread_mutex_destroy(&ch->lock);
+ free(ch);
+ } else
+ pthread_mutex_unlock(&ch->lock);
+}
+
static void list_add_worker(struct fuse_worker *w, struct fuse_worker *next)
{
struct fuse_worker *prev = next->prev;
@@ -193,15 +236,13 @@ static struct fuse_chan *fuse_clone_chan(struct fuse_mt *mt)
}
fcntl(clonefd, F_SETFD, FD_CLOEXEC);
- masterfd = mt->prevch->fd;
+ masterfd = mt->se->fd;
res = ioctl(clonefd, FUSE_DEV_IOC_CLONE, &masterfd);
if (res == -1) {
fprintf(stderr, "fuse: failed to clone device fd: %s\n",
strerror(errno));
close(clonefd);
- mt->se->f->clone_fd = 0;
-
- return fuse_chan_get(mt->prevch);
+ return NULL;
}
newch = fuse_chan_new(clonefd);
if (newch == NULL)
@@ -223,13 +264,15 @@ static int fuse_loop_start_thread(struct fuse_mt *mt)
w->fbuf.mem = NULL;
w->mt = mt;
-
+ w->ch = NULL;
if (mt->se->f->clone_fd) {
w->ch = fuse_clone_chan(mt);
- if (!w->ch)
- return -1;
- } else {
- w->ch = fuse_chan_get(mt->prevch);
+ if(!w->ch) {
+ /* Don't attempt this again */
+ fprintf(stderr, "fuse: trying to continue "
+ "without -o clone_fd.\n");
+ mt->se->f->clone_fd = 0;
+ }
}
res = fuse_start_thread(&w->thread_id, fuse_do_work, w);
@@ -264,7 +307,6 @@ int fuse_session_loop_mt(struct fuse_session *se)
memset(&mt, 0, sizeof(struct fuse_mt));
mt.se = se;
- mt.prevch = fuse_session_chan(se);
mt.error = 0;
mt.numworker = 0;
mt.numavail = 0;
diff --git a/lib/fuse_lowlevel.c b/lib/fuse_lowlevel.c
index 2a7c580..7acc206 100755..100644
--- a/lib/fuse_lowlevel.c
+++ b/lib/fuse_lowlevel.c
@@ -2,6 +2,9 @@
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
+ Implementation of (most of) the low-level FUSE API. The session loop
+ functions are implemented in separate files.
+
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB
*/
@@ -41,8 +44,7 @@
struct fuse_pollhandle {
uint64_t kh;
- struct fuse_chan *ch;
- struct fuse_ll *f;
+ struct fuse_session *se;
};
static size_t pagesize;
@@ -141,7 +143,7 @@ void fuse_free_req(fuse_req_t req)
destroy_req(req);
}
-static struct fuse_req *fuse_ll_alloc_req(struct fuse_ll *f)
+static struct fuse_req *fuse_ll_alloc_req(struct fuse_session *se)
{
struct fuse_req *req;
@@ -149,7 +151,8 @@ static struct fuse_req *fuse_ll_alloc_req(struct fuse_ll *f)
if (req == NULL) {
fprintf(stderr, "fuse: failed to allocate request\n");
} else {
- req->f = f;
+ req->f = se->f;
+ req->se = se;
req->ctr = 1;
list_init_req(req);
fuse_mutex_init(&req->lock);
@@ -158,18 +161,12 @@ static struct fuse_req *fuse_ll_alloc_req(struct fuse_ll *f)
return req;
}
-void fuse_chan_close(struct fuse_chan *ch)
-{
- int fd = ch->fd;
- if (fd != -1)
- close(fd);
-}
-
-
-static int fuse_send_msg(struct fuse_ll *f, struct fuse_chan *ch,
+/* Send data. If *ch* is NULL, send via session master fd */
+static int fuse_send_msg(struct fuse_session *se, struct fuse_chan *ch,
struct iovec *iov, int count)
{
struct fuse_out_header *out = iov[0].iov_base;
+ struct fuse_ll *f = se->f;
out->len = iov_length(iov, count);
if (f->debug) {
@@ -188,12 +185,11 @@ static int fuse_send_msg(struct fuse_ll *f, struct fuse_chan *ch,
}
}
- ssize_t res = writev(ch->fd, iov, count);
+ ssize_t res = writev(ch ? ch->fd : se->fd,
+ iov, count);
int err = errno;
if (res == -1) {
- struct fuse_session *se = fuse_chan_session(ch);
-
assert(se != NULL);
/* ENOENT means the operation was interrupted */
@@ -222,7 +218,7 @@ int fuse_send_reply_iov_nofree(fuse_req_t req, int error, struct iovec *iov,
iov[0].iov_base = &out;
iov[0].iov_len = sizeof(struct fuse_out_header);
- return fuse_send_msg(req->f, req->ch, iov, count);
+ return fuse_send_msg(req->se, req->ch, iov, count);
}
static int send_reply_iov(fuse_req_t req, int error, struct iovec *iov,
@@ -477,7 +473,8 @@ int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size)
return send_reply_ok(req, buf, size);
}
-static int fuse_send_data_iov_fallback(struct fuse_ll *f, struct fuse_chan *ch,
+static int fuse_send_data_iov_fallback(struct fuse_session *se,
+ struct fuse_chan *ch,
struct iovec *iov, int iov_count,
struct fuse_bufvec *buf,
size_t len)
@@ -495,7 +492,7 @@ static int fuse_send_data_iov_fallback(struct fuse_ll *f, struct fuse_chan *ch,
iov[iov_count].iov_base = buf->buf[0].mem;
iov[iov_count].iov_len = len;
iov_count++;
- return fuse_send_msg(f, ch, iov, iov_count);
+ return fuse_send_msg(se, ch, iov, iov_count);
}
res = posix_memalign(&mbuf, pagesize, len);
@@ -513,7 +510,7 @@ static int fuse_send_data_iov_fallback(struct fuse_ll *f, struct fuse_chan *ch,
iov[iov_count].iov_base = mbuf;
iov[iov_count].iov_len = len;
iov_count++;
- res = fuse_send_msg(f, ch, iov, iov_count);
+ res = fuse_send_msg(se, ch, iov, iov_count);
free(mbuf);
return res;
@@ -613,7 +610,7 @@ static int read_back(int fd, char *buf, size_t len)
return 0;
}
-static int fuse_send_data_iov(struct fuse_ll *f, struct fuse_chan *ch,
+static int fuse_send_data_iov(struct fuse_session *se, struct fuse_chan *ch,
struct iovec *iov, int iov_count,
struct fuse_bufvec *buf, unsigned int flags)
{
@@ -621,6 +618,7 @@ static int fuse_send_data_iov(struct fuse_ll *f, struct fuse_chan *ch,
size_t len = fuse_buf_size(buf);
struct fuse_out_header *out = iov[0].iov_base;
struct fuse_ll_pipe *llp;
+ struct fuse_ll *f = se->f;
int splice_flags;
size_t pipesize;
size_t total_fd_size;
@@ -766,7 +764,7 @@ static int fuse_send_data_iov(struct fuse_ll *f, struct fuse_chan *ch,
iov[iov_count].iov_base = mbuf;
iov[iov_count].iov_len = len;
iov_count++;
- res = fuse_send_msg(f, ch, iov, iov_count);
+ res = fuse_send_msg(se, ch, iov, iov_count);
free(mbuf);
return res;
}
@@ -787,8 +785,8 @@ static int fuse_send_data_iov(struct fuse_ll *f, struct fuse_chan *ch,
(f->conn.want & FUSE_CAP_SPLICE_MOVE))
splice_flags |= SPLICE_F_MOVE;
- res = splice(llp->pipe[0], NULL,
- ch->fd, NULL, out->len, splice_flags);
+ res = splice(llp->pipe[0], NULL, ch ? ch->fd : se->fd,
+ NULL, out->len, splice_flags);
if (res == -1) {
res = -errno;
perror("fuse: splice from pipe");
@@ -807,17 +805,17 @@ clear_pipe:
return res;
fallback:
- return fuse_send_data_iov_fallback(f, ch, iov, iov_count, buf, len);
+ return fuse_send_data_iov_fallback(se, ch, iov, iov_count, buf, len);
}
#else
-static int fuse_send_data_iov(struct fuse_ll *f, struct fuse_chan *ch,
+static int fuse_send_data_iov(struct fuse_session *se, struct fuse_chan *ch,
struct iovec *iov, int iov_count,
struct fuse_bufvec *buf, unsigned int flags)
{
size_t len = fuse_buf_size(buf);
(void) flags;
- return fuse_send_data_iov_fallback(f, ch, iov, iov_count, buf, len);
+ return fuse_send_data_iov_fallback(se, ch, iov, iov_count, buf, len);
}
#endif
@@ -834,7 +832,7 @@ int fuse_reply_data(fuse_req_t req, struct fuse_bufvec *bufv,
out.unique = req->unique;
out.error = 0;
- res = fuse_send_data_iov(req->f, req->ch, iov, 1, bufv, flags);
+ res = fuse_send_data_iov(req->se, req->ch, iov, 1, bufv, flags);
if (res <= 0) {
fuse_free_req(req);
return res;
@@ -1072,7 +1070,7 @@ static void do_batch_forget(fuse_req_t req, fuse_ino_t nodeid,
struct fuse_forget_one *forget = &param[i];
struct fuse_req *dummy_req;
- dummy_req = fuse_ll_alloc_req(req->f);
+ dummy_req = fuse_ll_alloc_req(req->se);
if (dummy_req == NULL)
break;
@@ -1790,8 +1788,7 @@ static void do_poll(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
return;
}
ph->kh = arg->kh;
- ph->ch = req->ch;
- ph->f = req->f;
+ ph->se = req->se;
}
req->f->op.poll(req, nodeid, &fi, ph);
@@ -2079,12 +2076,12 @@ static void do_notify_reply(fuse_req_t req, fuse_ino_t nodeid,
nreq->reply(nreq, req, nodeid, inarg, buf);
}
-static int send_notify_iov(struct fuse_ll *f, struct fuse_chan *ch,
- int notify_code, struct iovec *iov, int count)
+static int send_notify_iov(struct fuse_session *se, int notify_code,
+ struct iovec *iov, int count)
{
struct fuse_out_header out;
- if (!f->got_init)
+ if (!se->f->got_init)
return -ENOTCONN;
out.unique = 0;
@@ -2092,7 +2089,7 @@ static int send_notify_iov(struct fuse_ll *f, struct fuse_chan *ch,
iov[0].iov_base = &out;
iov[0].iov_len = sizeof(struct fuse_out_header);
- return fuse_send_msg(f, ch, iov, count);
+ return fuse_send_msg(se, NULL, iov, count);
}
int fuse_lowlevel_notify_poll(struct fuse_pollhandle *ph)
@@ -2106,7 +2103,7 @@ int fuse_lowlevel_notify_poll(struct fuse_pollhandle *ph)
iov[1].iov_base = &outarg;
iov[1].iov_len = sizeof(outarg);
- return send_notify_iov(ph->f, ph->ch, FUSE_NOTIFY_POLL, iov, 2);
+ return send_notify_iov(ph->se, FUSE_NOTIFY_POLL, iov, 2);
} else {
return 0;
}
@@ -2133,7 +2130,7 @@ int fuse_lowlevel_notify_inval_inode(struct fuse_session *se, fuse_ino_t ino,
iov[1].iov_base = &outarg;
iov[1].iov_len = sizeof(outarg);
- return send_notify_iov(f, se->ch, FUSE_NOTIFY_INVAL_INODE, iov, 2);
+ return send_notify_iov(se, FUSE_NOTIFY_INVAL_INODE, iov, 2);
}
int fuse_lowlevel_notify_inval_entry(struct fuse_session *se, fuse_ino_t parent,
@@ -2159,7 +2156,7 @@ int fuse_lowlevel_notify_inval_entry(struct fuse_session *se, fuse_ino_t parent,
iov[2].iov_base = (void *)name;
iov[2].iov_len = namelen + 1;
- return send_notify_iov(f, se->ch, FUSE_NOTIFY_INVAL_ENTRY, iov, 3);
+ return send_notify_iov(se, FUSE_NOTIFY_INVAL_ENTRY, iov, 3);
}
int fuse_lowlevel_notify_delete(struct fuse_session *se,
@@ -2190,7 +2187,7 @@ int fuse_lowlevel_notify_delete(struct fuse_session *se,
iov[2].iov_base = (void *)name;
iov[2].iov_len = namelen + 1;
- return send_notify_iov(f, se->ch, FUSE_NOTIFY_DELETE, iov, 3);
+ return send_notify_iov(se, FUSE_NOTIFY_DELETE, iov, 3);
}
int fuse_lowlevel_notify_store(struct fuse_session *se, fuse_ino_t ino,
@@ -2227,7 +2224,7 @@ int fuse_lowlevel_notify_store(struct fuse_session *se, fuse_ino_t ino,
iov[1].iov_base = &outarg;
iov[1].iov_len = sizeof(outarg);
- res = fuse_send_data_iov(f, se->ch, iov, 2, bufv, flags);
+ res = fuse_send_data_iov(se, NULL, iov, 2, bufv, flags);
if (res > 0)
res = -res;
@@ -2316,7 +2313,7 @@ int fuse_lowlevel_notify_retrieve(struct fuse_session *se, fuse_ino_t ino,
iov[1].iov_base = &outarg;
iov[1].iov_len = sizeof(outarg);
- err = send_notify_iov(f, se->ch, FUSE_NOTIFY_RETRIEVE, iov, 2);
+ err = send_notify_iov(se, FUSE_NOTIFY_RETRIEVE, iov, 2);
if (err) {
pthread_mutex_lock(&f->lock);
list_del_nreq(&rreq->nreq);
@@ -2439,7 +2436,7 @@ 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)
{
- fuse_session_process_buf_int(se, buf, se->ch);
+ fuse_session_process_buf_int(se, buf, NULL);
}
void fuse_session_process_buf_int(struct fuse_session *se,
@@ -2485,7 +2482,7 @@ void fuse_session_process_buf_int(struct fuse_session *se,
(unsigned long long) in->nodeid, buf->size, in->pid);
}
- req = fuse_ll_alloc_req(f);
+ req = fuse_ll_alloc_req(se);
if (req == NULL) {
struct fuse_out_header out = {
.unique = in->unique,
@@ -2496,7 +2493,7 @@ void fuse_session_process_buf_int(struct fuse_session *se,
.iov_len = sizeof(struct fuse_out_header),
};
- fuse_send_msg(f, ch, &iov, 1);
+ fuse_send_msg(se, ch, &iov, 1);
goto clear_pipe;
}
@@ -2504,7 +2501,7 @@ void fuse_session_process_buf_int(struct fuse_session *se,
req->ctx.uid = in->uid;
req->ctx.gid = in->gid;
req->ctx.pid = in->pid;
- req->ch = fuse_chan_get(ch);
+ req->ch = ch ? fuse_chan_get(ch) : NULL;
err = EIO;
if (!f->got_init) {
@@ -2581,11 +2578,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,23 +2614,19 @@ 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("max_read=", FUSE_OPT_KEY_DISCARD),
- 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"
" -o max_write=N set maximum size of write requests\n"
" -o max_readahead=N set maximum readahead\n"
" -o max_background=N set number of maximum background requests\n"
@@ -2658,32 +2646,16 @@ static void fuse_ll_help(void)
" -o [no_]async_dio asynchronous direct I/O\n"
" -o [no_]writeback_cache asynchronous, buffered writes\n"
" -o time_gran=N time granularity in nsec\n"
-" -o clone_fd clone fuse device file descriptors\n"
-);
+" -o clone_fd clone fuse device file descriptors\n\n");
}
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;
-
- default:
- fprintf(stderr, "fuse: unknown option `%s'\n", arg);
- }
+ (void) data; (void) outargs; (void) key; (void) arg;
- /* Fail */
- return -1;
+ /* Passthrough unknown options */
+ return 1;
}
static void fuse_ll_destroy(struct fuse_ll *f)
@@ -2706,7 +2678,7 @@ static void fuse_ll_destroy(struct fuse_ll *f)
void fuse_session_destroy(struct fuse_session *se)
{
fuse_ll_destroy(se->f);
- fuse_chan_put(se->ch);
+ close(se->fd);
destroy_mount_opts(se->mo);
free(se);
}
@@ -2720,7 +2692,7 @@ static void fuse_ll_pipe_destructor(void *data)
int fuse_session_receive_buf(struct fuse_session *se, struct fuse_buf *buf)
{
- return fuse_session_receive_buf_int(se, buf, se->ch);
+ return fuse_session_receive_buf_int(se, buf, NULL);
}
int fuse_session_receive_buf_int(struct fuse_session *se, struct fuse_buf *buf,
@@ -2754,7 +2726,8 @@ int fuse_session_receive_buf_int(struct fuse_session *se, struct fuse_buf *buf,
goto fallback;
}
- res = splice(ch->fd, NULL, llp->pipe[1], NULL, bufsize, 0);
+ res = splice(ch ? ch->fd : se->fd,
+ NULL, llp->pipe[1], NULL, bufsize, 0);
err = errno;
if (fuse_session_exited(se))
@@ -2838,7 +2811,7 @@ fallback:
}
restart:
- res = read(ch->fd, buf->mem, f->bufsize);
+ res = read(ch ? ch->fd : se->fd, buf->mem, f->bufsize);
err = errno;
if (fuse_session_exited(se))
@@ -2889,15 +2862,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);
@@ -2919,7 +2900,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);
@@ -2929,27 +2910,29 @@ 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;
}
int fuse_session_mount(struct fuse_session *se, const char *mountpoint)
{
- struct fuse_chan *ch;
int fd;
/*
@@ -2966,13 +2949,7 @@ int fuse_session_mount(struct fuse_session *se, const char *mountpoint)
fd = fuse_kern_mount(mountpoint, se->mo);
if (fd == -1)
return -1;
-
- ch = fuse_chan_new(fd);
- if (!ch)
- goto error_out;
-
- /* Add channel to session */
- fuse_session_add_chan(se, ch);
+ se->fd = fd;
/* Save mountpoint */
se->mountpoint = strdup(mountpoint);
@@ -2986,17 +2963,16 @@ error_out:
return -1;
}
+int fuse_session_fd(struct fuse_session *se)
+{
+ return se->fd;
+}
+
void fuse_session_unmount(struct fuse_session *se)
{
- struct fuse_chan *ch = se->ch;
- fuse_session_remove_chan(ch);
- if (se->mountpoint) {
- int fd = ch ? fuse_chan_clearfd(ch) : -1;
- fuse_kern_unmount(se->mountpoint, fd);
- fuse_chan_put(ch);
- free(se->mountpoint);
- se->mountpoint = NULL;
- }
+ fuse_kern_unmount(se->mountpoint, se->fd);
+ free(se->mountpoint);
+ se->mountpoint = NULL;
}
#ifdef linux
@@ -3067,3 +3043,18 @@ int fuse_req_getgroups(fuse_req_t req, int size, gid_t list[])
return -ENOSYS;
}
#endif
+
+void fuse_session_exit(struct fuse_session *se)
+{
+ se->exited = 1;
+}
+
+void fuse_session_reset(struct fuse_session *se)
+{
+ se->exited = 0;
+}
+
+int fuse_session_exited(struct fuse_session *se)
+{
+ return se->exited;
+}
diff --git a/lib/fuse_mt.c b/lib/fuse_mt.c
deleted file mode 100644
index be5d644..0000000
--- a/lib/fuse_mt.c
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- FUSE: Filesystem in Userspace
- Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
-
- This program can be distributed under the terms of the GNU LGPLv2.
- See the file COPYING.LIB.
-*/
-
-#include "config.h"
-#include "fuse.h"
-#include "fuse_lowlevel.h"
-
-int fuse_loop_mt(struct fuse *f)
-{
- if (f == NULL)
- return -1;
-
- int res = fuse_start_cleanup_thread(f);
- if (res)
- return -1;
-
- res = fuse_session_loop_mt(fuse_get_session(f));
- fuse_stop_cleanup_thread(f);
- return res;
-}
diff --git a/lib/fuse_opt.c b/lib/fuse_opt.c
index bd7a6ee..3d4a3dd 100644
--- a/lib/fuse_opt.c
+++ b/lib/fuse_opt.c
@@ -2,6 +2,9 @@
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
+ Implementation of option parsing routines (dealing with `struct
+ fuse_args`).
+
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB
*/
diff --git a/lib/fuse_session.c b/lib/fuse_session.c
deleted file mode 100644
index cdf20f7..0000000
--- a/lib/fuse_session.c
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- FUSE: Filesystem in Userspace
- Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
-
- This program can be distributed under the terms of the GNU LGPLv2.
- See the file COPYING.LIB
-*/
-
-#include "config.h"
-#include "fuse_i.h"
-#include "fuse_misc.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include <errno.h>
-
-
-void fuse_session_add_chan(struct fuse_session *se, struct fuse_chan *ch)
-{
- assert(se->ch == NULL);
- assert(ch->se == NULL);
- se->ch = ch;
- ch->se = se;
-}
-
-void fuse_session_remove_chan(struct fuse_chan *ch)
-{
- struct fuse_session *se = ch->se;
- if (se) {
- assert(se->ch == ch);
- se->ch = NULL;
- ch->se = NULL;
- }
-}
-
-struct fuse_chan *fuse_session_chan(struct fuse_session *se)
-{
- return se->ch;
-}
-
-int fuse_chan_clearfd(struct fuse_chan *ch)
-{
- int fd = ch->fd;
- ch->fd = -1;
- return fd;
-}
-
-void fuse_session_exit(struct fuse_session *se)
-{
- se->exited = 1;
-}
-
-void fuse_session_reset(struct fuse_session *se)
-{
- se->exited = 0;
-}
-
-int fuse_session_exited(struct fuse_session *se)
-{
- return se->exited;
-}
-
-struct fuse_chan *fuse_chan_new(int fd)
-{
- struct fuse_chan *ch = (struct fuse_chan *) malloc(sizeof(*ch));
- if (ch == NULL) {
- fprintf(stderr, "fuse: failed to allocate channel\n");
- return NULL;
- }
-
- memset(ch, 0, sizeof(*ch));
- ch->fd = fd;
- ch->ctr = 1;
- fuse_mutex_init(&ch->lock);
-
- return ch;
-}
-
-struct fuse_session *fuse_chan_session(struct fuse_chan *ch)
-{
- return ch->se;
-}
-
-struct fuse_chan *fuse_chan_get(struct fuse_chan *ch)
-{
- assert(ch->ctr > 0);
- pthread_mutex_lock(&ch->lock);
- ch->ctr++;
- pthread_mutex_unlock(&ch->lock);
-
- return ch;
-}
-
-void fuse_chan_put(struct fuse_chan *ch)
-{
- if (ch) {
- pthread_mutex_lock(&ch->lock);
- ch->ctr--;
- if (!ch->ctr) {
- pthread_mutex_unlock(&ch->lock);
- fuse_session_remove_chan(ch);
- fuse_chan_close(ch);
- pthread_mutex_destroy(&ch->lock);
- free(ch);
- } else {
- pthread_mutex_unlock(&ch->lock);
- }
-
- }
-}
diff --git a/lib/fuse_signals.c b/lib/fuse_signals.c
index 9fa787c..2261b7b 100755..100644
--- a/lib/fuse_signals.c
+++ b/lib/fuse_signals.c
@@ -2,6 +2,8 @@
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
+ Utility functions for setting signal handlers.
+
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB
*/
diff --git a/lib/fuse_versionscript b/lib/fuse_versionscript
index ee9c9d7..4031664 100644
--- a/lib/fuse_versionscript
+++ b/lib/fuse_versionscript
@@ -19,6 +19,7 @@ FUSE_3.0 {
fuse_session_loop;
fuse_session_loop_mt;
fuse_session_reset;
+ fuse_session_fd;
fuse_opt_parse;
fuse_opt_add_opt;
fuse_opt_add_arg;
@@ -122,6 +123,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 7ee767b..63f26c2 100644
--- a/lib/helper.c
+++ b/lib/helper.c
@@ -21,36 +21,24 @@
#include <errno.h>
#include <sys/param.h>
-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
@@ -59,16 +47,13 @@ static const struct fuse_opt fuse_helper_opts[] = {
static void usage(const char *progname)
{
printf("usage: %s mountpoint [options]\n\n", progname);
- printf("general options:\n"
- " -o opt,[opt...] mount options\n"
- " -h --help print help\n"
- " -V --version print version\n"
- "\n");
}
static void helper_help(void)
{
- printf("FUSE options:\n"
+ printf("General options:\n"
+ " -h --help print help\n"
+ " -V --version print version\n"
" -d -o debug enable debug output (implies -f)\n"
" -f foreground operation\n"
" -s disable multi-threaded operation\n"
@@ -83,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,
@@ -107,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;
@@ -140,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) {
@@ -227,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)
diff --git a/lib/mount.c b/lib/mount.c
index fb17c00..5c892f6 100644
--- a/lib/mount.c
+++ b/lib/mount.c
@@ -2,6 +2,8 @@
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
+ Architecture specific file system mounting (Linux).
+
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB.
*/
@@ -99,7 +101,6 @@ static const struct fuse_opt fuse_mount_opts[] = {
FUSE_OPT_KEY("defcontext=", KEY_KERN_OPT),
FUSE_OPT_KEY("rootcontext=", KEY_KERN_OPT),
FUSE_OPT_KEY("max_read=", KEY_KERN_OPT),
- FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_KEEP),
FUSE_OPT_KEY("user=", KEY_MTAB_OPT),
FUSE_OPT_KEY("-r", KEY_RO),
FUSE_OPT_KEY("ro", KEY_KERN_FLAG),
@@ -121,6 +122,7 @@ static const struct fuse_opt fuse_mount_opts[] = {
void fuse_mount_help(void)
{
printf(
+"Mount options:\n"
" -o allow_other allow access to other users\n"
" -o allow_root allow access to root\n"
" -o auto_unmount auto unmount on process termination\n"
@@ -129,8 +131,7 @@ void fuse_mount_help(void)
" -o fsname=NAME set filesystem name\n"
" -o subtype=NAME set filesystem type\n"
" -o large_read issue large read requests (2.4 only)\n"
-" -o max_read=N set maximum size of read requests\n"
-"\n");
+" -o max_read=N set maximum size of read requests\n\n");
}
static void exec_fusermount(const char *argv[])
diff --git a/lib/mount_bsd.c b/lib/mount_bsd.c
index 0d886b0..4703d94 100644
--- a/lib/mount_bsd.c
+++ b/lib/mount_bsd.c
@@ -2,6 +2,8 @@
FUSE: Filesystem in Userspace
Copyright (C) 2005-2008 Csaba Henk <csaba.henk@creo.hu>
+ Architecture specific file system mounting (FreeBSD).
+
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB.
*/
@@ -95,7 +97,9 @@ static const struct fuse_opt fuse_mount_opts[] = {
void fuse_mount_help(void)
{
- printf(" -o allow_root allow access to root\n");
+ printf(
+"Mount options:\n"
+" -o allow_root allow access to root\n");
system(FUSERMOUNT_PROG " --help");
fputc('\n', stderr);
}
diff --git a/lib/mount_util.c b/lib/mount_util.c
index ad9d38c..a23ab0b 100644
--- a/lib/mount_util.c
+++ b/lib/mount_util.c
@@ -2,6 +2,8 @@
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
+ Architecture-independent mounting code.
+
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB.
*/
diff --git a/test/conftest.py b/test/conftest.py
index 0da2f4b..70cd0c6 100644
--- a/test/conftest.py
+++ b/test/conftest.py
@@ -35,9 +35,13 @@ def check_test_output(capfd):
if count == 0 or count - cnt > 0:
stderr = cp.sub('', stderr, count=count - cnt)
- for pattern in ('exception', 'error', 'warning', 'fatal', 'traceback',
- 'fault', 'crash(?:ed)?', 'abort(?:ed)'):
- cp = re.compile(r'\b{}\b'.format(pattern), re.IGNORECASE | re.MULTILINE)
+ patterns = [ r'\b{}\b'.format(x) for x in
+ ('exception', 'error', 'warning', 'fatal', 'traceback',
+ 'fault', 'crash(?:ed)?', 'abort(?:ed)',
+ 'uninitiali[zs]ed') ]
+ patterns += ['^==[0-9]+== ']
+ for pattern in patterns:
+ cp = re.compile(pattern, re.IGNORECASE | re.MULTILINE)
hit = cp.search(stderr)
if hit:
raise AssertionError('Suspicious output to stderr (matched "%s")' % hit.group(0))
diff --git a/test/test_examples.py b/test/test_examples.py
index 31d2fae..5ddc860 100755
--- a/test/test_examples.py
+++ b/test/test_examples.py
@@ -14,9 +14,10 @@ import shutil
import filecmp
import errno
from tempfile import NamedTemporaryFile
-from util import wait_for_mount, umount, cleanup
+from util import wait_for_mount, umount, cleanup, base_cmdline
+from os.path import join as pjoin
-basename = os.path.join(os.path.dirname(__file__), '..')
+basename = pjoin(os.path.dirname(__file__), '..')
TEST_FILE = __file__
with open(TEST_FILE, 'rb') as fh:
@@ -29,13 +30,17 @@ def name_generator(__ctr=[0]):
@pytest.mark.parametrize("name", ('hello', 'hello_ll'))
def test_hello(tmpdir, name):
mnt_dir = str(tmpdir)
- cmdline = [os.path.join(basename, 'example', name),
- '-f', mnt_dir ]
+ cmdline = base_cmdline + \
+ [ pjoin(basename, 'example', name),
+ '-f', mnt_dir ]
+ if name == 'hello_ll':
+ # supports single-threading only
+ cmdline.append('-s')
mount_process = subprocess.Popen(cmdline)
try:
wait_for_mount(mount_process, mnt_dir)
assert os.listdir(mnt_dir) == [ 'hello' ]
- filename = os.path.join(mnt_dir, 'hello')
+ filename = pjoin(mnt_dir, 'hello')
with open(filename, 'r') as fh:
assert fh.read() == 'Hello World!\n'
with pytest.raises(IOError) as exc_info:
@@ -50,18 +55,51 @@ def test_hello(tmpdir, name):
else:
umount(mount_process, mnt_dir)
+def test_fuse_lo_plus(tmpdir):
+ mnt_dir = str(tmpdir.mkdir('mnt'))
+ src_dir = str(tmpdir.mkdir('src'))
+
+ cmdline = base_cmdline + \
+ [ pjoin(basename, 'example', 'fuse_lo-plus'),
+ '-f', '-s', mnt_dir ]
+ mount_process = subprocess.Popen(cmdline)
+ try:
+ wait_for_mount(mount_process, mnt_dir)
+ work_dir = pjoin(mnt_dir, src_dir)
+ tst_write(work_dir)
+ tst_mkdir(work_dir)
+ tst_symlink(work_dir)
+ tst_mknod(work_dir)
+ if os.getuid() == 0:
+ tst_chown(work_dir)
+ # Underlying fs may not have full nanosecond resolution
+ tst_utimens(work_dir, ns_tol=1000)
+ tst_link(work_dir)
+ tst_readdir(work_dir)
+ tst_statvfs(work_dir)
+ tst_truncate_path(work_dir)
+ tst_truncate_fd(work_dir)
+ tst_unlink(work_dir)
+ tst_passthrough(src_dir, work_dir)
+ except:
+ cleanup(mnt_dir)
+ raise
+ else:
+ umount(mount_process, mnt_dir)
+
@pytest.mark.parametrize("name", ('fusexmp', 'fusexmp_fh'))
def test_fusexmp_fh(tmpdir, name):
mnt_dir = str(tmpdir.mkdir('mnt'))
src_dir = str(tmpdir.mkdir('src'))
- cmdline = [os.path.join(basename, 'example', name),
- '-f', '-o' , 'use_ino,readdir_ino,kernel_cache',
+ cmdline = base_cmdline + \
+ [ pjoin(basename, 'example', name),
+ '-f', '-o', 'use_ino,readdir_ino,kernel_cache',
mnt_dir ]
mount_process = subprocess.Popen(cmdline)
try:
wait_for_mount(mount_process, mnt_dir)
- work_dir = os.path.join(mnt_dir, src_dir)
+ work_dir = pjoin(mnt_dir, src_dir)
tst_write(work_dir)
tst_mkdir(work_dir)
tst_symlink(work_dir)
@@ -85,20 +123,21 @@ def test_fusexmp_fh(tmpdir, name):
def test_fioc(tmpdir):
mnt_dir = str(tmpdir)
- testfile = os.path.join(mnt_dir, 'fioc')
- cmdline = [os.path.join(basename, 'example', 'fioc'),
- '-f', mnt_dir ]
+ testfile = pjoin(mnt_dir, 'fioc')
+ cmdline = base_cmdline + \
+ [pjoin(basename, 'example', 'fioc'), '-f', mnt_dir ]
mount_process = subprocess.Popen(cmdline)
try:
wait_for_mount(mount_process, mnt_dir)
- base_cmd = [ os.path.join(basename, 'example', 'fioclient'),
- testfile ]
- assert subprocess.check_output(base_cmd) == b'0\n'
+ cmdline = base_cmdline + \
+ [ pjoin(basename, 'example', 'fioclient'),
+ testfile ]
+ assert subprocess.check_output(cmdline) == b'0\n'
with open(testfile, 'wb') as fh:
fh.write(b'foobar')
- assert subprocess.check_output(base_cmd) == b'6\n'
- subprocess.check_call(base_cmd + [ '3' ])
+ assert subprocess.check_output(cmdline) == b'6\n'
+ subprocess.check_call(cmdline + [ '3' ])
with open(testfile, 'rb') as fh:
assert fh.read()== b'foo'
except:
@@ -109,12 +148,13 @@ def test_fioc(tmpdir):
def test_fsel(tmpdir):
mnt_dir = str(tmpdir)
- cmdline = [os.path.join(basename, 'example', 'fsel'),
+ cmdline = base_cmdline + [pjoin(basename, 'example', 'fsel'),
'-f', mnt_dir ]
mount_process = subprocess.Popen(cmdline)
try:
wait_for_mount(mount_process, mnt_dir)
- cmdline = [ os.path.join(basename, 'example', 'fselclient') ]
+ cmdline = base_cmdline + \
+ [ pjoin(basename, 'example', 'fselclient') ]
subprocess.check_call(cmdline, cwd=mnt_dir)
except:
cleanup(mnt_dir)
@@ -123,7 +163,7 @@ def test_fsel(tmpdir):
umount(mount_process, mnt_dir)
def checked_unlink(filename, path, isdir=False):
- fullname = os.path.join(path, filename)
+ fullname = pjoin(path, filename)
if isdir:
os.rmdir(fullname)
else:
@@ -156,7 +196,7 @@ def tst_symlink(mnt_dir):
checked_unlink(linkname, mnt_dir)
def tst_mknod(mnt_dir):
- filename = os.path.join(mnt_dir, name_generator())
+ filename = pjoin(mnt_dir, name_generator())
shutil.copyfile(TEST_FILE, filename)
fstat = os.lstat(filename)
assert stat.S_ISREG(fstat.st_mode)
@@ -166,7 +206,7 @@ def tst_mknod(mnt_dir):
checked_unlink(filename, mnt_dir)
def tst_chown(mnt_dir):
- filename = os.path.join(mnt_dir, name_generator())
+ filename = pjoin(mnt_dir, name_generator())
os.mkdir(filename)
fstat = os.lstat(filename)
uid = fstat.st_uid
@@ -187,17 +227,17 @@ def tst_chown(mnt_dir):
checked_unlink(filename, mnt_dir, isdir=True)
def tst_write(mnt_dir):
- name = os.path.join(mnt_dir, name_generator())
+ name = pjoin(mnt_dir, name_generator())
shutil.copyfile(TEST_FILE, name)
assert filecmp.cmp(name, TEST_FILE, False)
checked_unlink(name, mnt_dir)
def tst_unlink(mnt_dir):
- name = os.path.join(mnt_dir, name_generator())
+ name = pjoin(mnt_dir, name_generator())
data1 = b'foo'
data2 = b'bar'
- with open(os.path.join(mnt_dir, name), 'wb+', buffering=0) as fh:
+ with open(pjoin(mnt_dir, name), 'wb+', buffering=0) as fh:
fh.write(data1)
checked_unlink(name, mnt_dir)
fh.write(data2)
@@ -208,8 +248,8 @@ def tst_statvfs(mnt_dir):
os.statvfs(mnt_dir)
def tst_link(mnt_dir):
- name1 = os.path.join(mnt_dir, name_generator())
- name2 = os.path.join(mnt_dir, name_generator())
+ name1 = pjoin(mnt_dir, name_generator())
+ name2 = pjoin(mnt_dir, name_generator())
shutil.copyfile(TEST_FILE, name1)
assert filecmp.cmp(name1, TEST_FILE, False)
os.link(name1, name2)
@@ -228,7 +268,7 @@ def tst_link(mnt_dir):
os.unlink(name1)
def tst_readdir(mnt_dir):
- dir_ = os.path.join(mnt_dir, name_generator())
+ dir_ = pjoin(mnt_dir, name_generator())
file_ = dir_ + "/" + name_generator()
subdir = dir_ + "/" + name_generator()
subfile = subdir + "/" + name_generator()
@@ -252,7 +292,7 @@ def tst_readdir(mnt_dir):
def tst_truncate_path(mnt_dir):
assert len(TEST_DATA) > 1024
- filename = os.path.join(mnt_dir, name_generator())
+ filename = pjoin(mnt_dir, name_generator())
with open(filename, 'wb') as fh:
fh.write(TEST_DATA)
@@ -298,7 +338,7 @@ def tst_truncate_fd(mnt_dir):
assert fh.read(size) == TEST_DATA[:size-1024]
def tst_utimens(mnt_dir, ns_tol=0):
- filename = os.path.join(mnt_dir, name_generator())
+ filename = pjoin(mnt_dir, name_generator())
os.mkdir(filename)
fstat = os.lstat(filename)
@@ -323,8 +363,8 @@ def tst_utimens(mnt_dir, ns_tol=0):
def tst_passthrough(src_dir, mnt_dir):
name = name_generator()
- src_name = os.path.join(src_dir, name)
- mnt_name = os.path.join(src_dir, name)
+ src_name = pjoin(src_dir, name)
+ mnt_name = pjoin(src_dir, name)
assert name not in os.listdir(src_dir)
assert name not in os.listdir(mnt_dir)
with open(src_name, 'w') as fh:
@@ -334,8 +374,8 @@ def tst_passthrough(src_dir, mnt_dir):
assert os.stat(src_name) == os.stat(mnt_name)
name = name_generator()
- src_name = os.path.join(src_dir, name)
- mnt_name = os.path.join(src_dir, name)
+ src_name = pjoin(src_dir, name)
+ mnt_name = pjoin(src_dir, name)
assert name not in os.listdir(src_dir)
assert name not in os.listdir(mnt_dir)
with open(mnt_name, 'w') as fh:
diff --git a/test/test_fuse.py b/test/test_fuse.py
index bbba6e0..3c60d80 100755
--- a/test/test_fuse.py
+++ b/test/test_fuse.py
@@ -7,7 +7,7 @@ if __name__ == '__main__':
import subprocess
import os
-from util import wait_for_mount, umount, cleanup
+from util import wait_for_mount, umount, cleanup, base_cmdline
basename = os.path.join(os.path.dirname(__file__), '..')
@@ -15,7 +15,8 @@ def test_fuse(tmpdir):
mnt_dir = str(tmpdir.mkdir('mnt'))
src_dir = str(tmpdir.mkdir('src'))
- cmdline = [ os.path.join(basename, 'example', 'fusexmp_fh'),
+ cmdline = base_cmdline + \
+ [ os.path.join(basename, 'example', 'fusexmp_fh'),
'-f', '-o' , 'use_ino,readdir_ino,kernel_cache',
mnt_dir ]
mount_process = subprocess.Popen(cmdline)
diff --git a/test/util.py b/test/util.py
index 48ec995..e8bb9c2 100644
--- a/test/util.py
+++ b/test/util.py
@@ -36,3 +36,20 @@ def umount(mount_process, mnt_dir):
time.sleep(0.1)
elapsed += 0.1
pytest.fail('mount process did not terminate')
+
+
+# If valgrind and libtool are available, use them
+def has_program(name):
+ try:
+ ret = subprocess.call([name, '--version'],
+ stdout=subprocess.DEVNULL,
+ stderr=subprocess.DEVNULL)
+ except FileNotFoundError:
+ return False
+ return ret == 0
+
+if has_program('valgrind') and has_program('libtool'):
+ base_cmdline = [ 'libtool', '--mode=execute',
+ 'valgrind', '-q', '--' ]
+else:
+ base_cmdline = []