mirror of
https://github.com/trapexit/mergerfs.git
synced 2026-10-20 00:17:43 +00:00
Compare commits
5
Commits
passthrough2
...
clonefd
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
075b725f7b | ||
|
|
5cd199eec3 | ||
|
|
67a36d436f | ||
|
|
d03a49459b | ||
|
|
ec46077fb5 |
-3547
File diff suppressed because it is too large
Load Diff
+4
-5
@@ -22,11 +22,9 @@ INSTALLMAN1DIR = $(DESTDIR)$(MAN1DIR)
|
|||||||
|
|
||||||
SRC = \
|
SRC = \
|
||||||
lib/buffer.c \
|
lib/buffer.c \
|
||||||
lib/cuse_lowlevel.c \
|
|
||||||
lib/fuse_dirents.c \
|
|
||||||
lib/fuse.c \
|
lib/fuse.c \
|
||||||
lib/fuse_kern_chan.c \
|
lib/fuse_chan.c \
|
||||||
lib/fuse_loop.c \
|
lib/fuse_dirents.c \
|
||||||
lib/fuse_loop_mt.c \
|
lib/fuse_loop_mt.c \
|
||||||
lib/fuse_lowlevel.c \
|
lib/fuse_lowlevel.c \
|
||||||
lib/fuse_mt.c \
|
lib/fuse_mt.c \
|
||||||
@@ -34,7 +32,8 @@ SRC = \
|
|||||||
lib/fuse_session.c \
|
lib/fuse_session.c \
|
||||||
lib/fuse_signals.c \
|
lib/fuse_signals.c \
|
||||||
lib/helper.c \
|
lib/helper.c \
|
||||||
lib/mount.c
|
lib/mount.c \
|
||||||
|
lib/sys.c
|
||||||
OBJS = $(SRC:lib/%.c=build/%.o)
|
OBJS = $(SRC:lib/%.c=build/%.o)
|
||||||
DEPS = $(SRC:lib/%.c=build/%.d)
|
DEPS = $(SRC:lib/%.c=build/%.d)
|
||||||
|
|
||||||
|
|||||||
-303
@@ -1,303 +0,0 @@
|
|||||||
What is new in 2.9
|
|
||||||
|
|
||||||
- Add "zero copy" support for kernel 2.6.35 or newer
|
|
||||||
|
|
||||||
- Make maximum background requests tunable on kernel 2.6.32 or newer
|
|
||||||
|
|
||||||
- Require --no-canonicalize in (u)mount (util-linux version 2.18 or
|
|
||||||
newer) to fix security problems with fusermount
|
|
||||||
|
|
||||||
- Use dynamically sized hash tables in high level library
|
|
||||||
|
|
||||||
- Memory use of filesystem daemon can shrink more easily
|
|
||||||
|
|
||||||
- Add "auto_unmount" option
|
|
||||||
|
|
||||||
- Add "remember" option
|
|
||||||
|
|
||||||
- Add man pages for fusermount, mount.fuse and ulockmgr_server
|
|
||||||
|
|
||||||
- API changes:
|
|
||||||
|
|
||||||
o Introduce "store" and "retrieve" for accessing kernel buffers on
|
|
||||||
kernel 2.6.36 or newer
|
|
||||||
|
|
||||||
o Introduce abstract buffer for zero copy operations
|
|
||||||
|
|
||||||
o Allow path calculation to be omitted on certain operations
|
|
||||||
|
|
||||||
o Allow batching forget requests
|
|
||||||
|
|
||||||
o Add "flock" method
|
|
||||||
|
|
||||||
o Add support for ioctl on directories
|
|
||||||
|
|
||||||
o Add delete notification
|
|
||||||
|
|
||||||
o Add fallocate operation (linux kernel 3.5 or newer)
|
|
||||||
|
|
||||||
- Bug fixes and small improvements
|
|
||||||
|
|
||||||
============================================================================
|
|
||||||
|
|
||||||
What is new in 2.8
|
|
||||||
|
|
||||||
- More scalable directory tree locking
|
|
||||||
|
|
||||||
- Atomic open(O_TRUNC) support
|
|
||||||
|
|
||||||
- Support big write requests on kernels 2.6.26 and newer
|
|
||||||
|
|
||||||
- Out-of-tree fuse module removed
|
|
||||||
|
|
||||||
- Better NFS exporting support
|
|
||||||
|
|
||||||
- New ioctl and poll requests
|
|
||||||
|
|
||||||
- New CUSE (Character Device in Userspace) interface
|
|
||||||
|
|
||||||
- Allow umask processing in userspace
|
|
||||||
|
|
||||||
- Added cache invalidation notifications
|
|
||||||
|
|
||||||
- Bugfixes and small improvements
|
|
||||||
|
|
||||||
============================================================================
|
|
||||||
|
|
||||||
What is new in 2.7
|
|
||||||
|
|
||||||
- Stacking support for the high level API
|
|
||||||
|
|
||||||
- Add filename charset conversion module
|
|
||||||
|
|
||||||
- Improved mounting
|
|
||||||
|
|
||||||
============================================================================
|
|
||||||
|
|
||||||
What is new in 2.6
|
|
||||||
|
|
||||||
- Improved read characteristics (asynchronous reads)
|
|
||||||
|
|
||||||
- Support for aborting filesystem connection
|
|
||||||
|
|
||||||
- POSIX file locking support
|
|
||||||
|
|
||||||
- Request interruption support
|
|
||||||
|
|
||||||
- Building module for Linux kernels earlier than 2.6.9 not supported
|
|
||||||
|
|
||||||
- Allow block device based filesystems to support swap files
|
|
||||||
|
|
||||||
- Several bugs fixed, including a rare system hang on SMP
|
|
||||||
|
|
||||||
============================================================================
|
|
||||||
|
|
||||||
What is new in 2.5
|
|
||||||
|
|
||||||
- Merge library part of FreeBSD port
|
|
||||||
|
|
||||||
- New atomic create+open, access and ftruncate operations
|
|
||||||
|
|
||||||
- On filesystems implementing the new create+open operation, and
|
|
||||||
running on Linux kernels 2.6.15 or later, the 'cp' operation will
|
|
||||||
work correctly when copying read-only files.
|
|
||||||
|
|
||||||
- New option parsing interface added to the library
|
|
||||||
|
|
||||||
- Lots of minor improvements and fixes
|
|
||||||
|
|
||||||
============================================================================
|
|
||||||
|
|
||||||
What is new in 2.4
|
|
||||||
|
|
||||||
- Simplify device opening. Now '/dev/fuse' is a requirement
|
|
||||||
|
|
||||||
- Allow module auto-loading if user has access to '/dev/fuse'
|
|
||||||
|
|
||||||
- Allow mounting over a regular file for unprivileged users
|
|
||||||
|
|
||||||
- Allow mounting of arbitrary FUSE filesystems from /etc/fstab
|
|
||||||
|
|
||||||
- New mount options: 'umask=M', 'uid=N', 'gid=N'
|
|
||||||
|
|
||||||
- Check for non-empty mountpoint, and refuse mount by default. New
|
|
||||||
mount option: 'nonempty'
|
|
||||||
|
|
||||||
- Low level (inode based) API added
|
|
||||||
|
|
||||||
- Allow 'direct_io' and 'keep_cache' options to be set on a
|
|
||||||
case-by-case basis on open.
|
|
||||||
|
|
||||||
- Add 'attr_timeout' and 'entry_timeout' mount options to the
|
|
||||||
high-level library. Until now these timeouts were fixed at 1 sec.
|
|
||||||
|
|
||||||
- Some bugfixes
|
|
||||||
|
|
||||||
============================================================================
|
|
||||||
|
|
||||||
What is new in 2.3
|
|
||||||
|
|
||||||
- Add new directory related operations: opendir(), readdir(),
|
|
||||||
releasedir() and fsyncdir()
|
|
||||||
|
|
||||||
- Add init() and destroy() operations which are called before the
|
|
||||||
event loop is started and after it has exited
|
|
||||||
|
|
||||||
- Update kernel ABI so that on dual architectures (e.g. AMD64) 32bit
|
|
||||||
binaries work under a 64bit kernel
|
|
||||||
|
|
||||||
- Bugfixes
|
|
||||||
|
|
||||||
============================================================================
|
|
||||||
|
|
||||||
What is new in 2.2
|
|
||||||
|
|
||||||
Userspace changes:
|
|
||||||
|
|
||||||
- Add fuse_file_info structure to file operations, this allows the
|
|
||||||
filesystem to return a file handle in open() which is passed to
|
|
||||||
read(), write(), flush(), fsync() and release().
|
|
||||||
|
|
||||||
- Add source compatibility with 2.1 and 1.4 releases
|
|
||||||
|
|
||||||
- Binary compatibility with 2.1 release is retained
|
|
||||||
|
|
||||||
Kernel changes:
|
|
||||||
|
|
||||||
- Make requests interruptible. This prevents the filesystem to go
|
|
||||||
into an unbreakable deadlock with itself.
|
|
||||||
|
|
||||||
- Make readpages() synchronous. Asynchronous requests are deadlock
|
|
||||||
prone, since they cannot be interrupted (see above)
|
|
||||||
|
|
||||||
- Remove shared-writeable mapping support, which could deadlock the
|
|
||||||
machine
|
|
||||||
|
|
||||||
- Remove INVALIDATE userspace initiated request
|
|
||||||
|
|
||||||
- Update ABI to be independent of sizeof(long), so dual-size archs
|
|
||||||
don't cause problems
|
|
||||||
|
|
||||||
- Remove /sys/fs/fuse/version. Version checking is now done through
|
|
||||||
the fuse device
|
|
||||||
|
|
||||||
- Replace directory reading method on the kernel interface. Instead
|
|
||||||
of passing an open file descriptor to the kernel, send data through
|
|
||||||
the FUSE device, like all other operations.
|
|
||||||
|
|
||||||
============================================================================
|
|
||||||
|
|
||||||
What is new in 2.1
|
|
||||||
|
|
||||||
* Bug fixes
|
|
||||||
|
|
||||||
* Improved support for filesystems implementing a custom event-loop
|
|
||||||
|
|
||||||
* Add 'pkg-config' support
|
|
||||||
|
|
||||||
* Kernel module can be compiled separately
|
|
||||||
|
|
||||||
============================================================================
|
|
||||||
|
|
||||||
What is new in 1.9
|
|
||||||
|
|
||||||
* Lots of bugs fixed
|
|
||||||
|
|
||||||
* Minor modifications to the library API
|
|
||||||
|
|
||||||
* Improvements to the kernel/userspace interface
|
|
||||||
|
|
||||||
* Mounting by non-root made more secure
|
|
||||||
|
|
||||||
* Build shared library in addition to the static one
|
|
||||||
|
|
||||||
* Consolidated mount options
|
|
||||||
|
|
||||||
* Optimized reading under 2.6 kernels
|
|
||||||
|
|
||||||
* Direct I/O support
|
|
||||||
|
|
||||||
* Support file I/O on deleted files
|
|
||||||
|
|
||||||
* Extended attributes support
|
|
||||||
|
|
||||||
============================================================================
|
|
||||||
|
|
||||||
What is new in 1.3
|
|
||||||
|
|
||||||
* Thanks to user bugreports and stress testing with LTP and sfx-linux
|
|
||||||
a number of bugs were fixed, some quite serious.
|
|
||||||
|
|
||||||
* Fix compile problems with recent SuSE kernles
|
|
||||||
|
|
||||||
============================================================================
|
|
||||||
|
|
||||||
What is new in 1.2
|
|
||||||
|
|
||||||
* Fix mount problems on recent 2.6 kernels with SELinux enabled
|
|
||||||
|
|
||||||
* Fixed writing files lager than 2GBytes
|
|
||||||
|
|
||||||
* Other bugfixes
|
|
||||||
|
|
||||||
============================================================================
|
|
||||||
|
|
||||||
What is new in 1.1
|
|
||||||
|
|
||||||
* Support for the 2.6 kernels
|
|
||||||
|
|
||||||
* Support for exporting filesystem over NFS in 2.6 kernels
|
|
||||||
|
|
||||||
* Read efficiency improvements: read in 64k blocks instead of 4k
|
|
||||||
(Michael Grigoriev). Can be turned on with '-l' option of fusermount
|
|
||||||
|
|
||||||
* Lazy automatic unmount
|
|
||||||
|
|
||||||
* Added 'fsync()' VFS call to the FUSE interface
|
|
||||||
|
|
||||||
* Bugfixes
|
|
||||||
|
|
||||||
============================================================================
|
|
||||||
|
|
||||||
What is new in 1.0
|
|
||||||
|
|
||||||
* Cleanups and bugfixes
|
|
||||||
|
|
||||||
* Added 'release()' VFS call to the FUSE interface
|
|
||||||
|
|
||||||
* 64 bit file offsets (handling of > 4 GByte files)
|
|
||||||
|
|
||||||
* libfuse is now under LGPL
|
|
||||||
|
|
||||||
* New 'statfs' call (Mark Glines)
|
|
||||||
|
|
||||||
* Cleaned up mount procedure (mostly by Mark Glines)
|
|
||||||
|
|
||||||
NOTE: Binaries linked with with a previous version of libavfs may
|
|
||||||
not work with the new version of the fusermount program. In such
|
|
||||||
case recompile the program after installing the new libavfs library.
|
|
||||||
|
|
||||||
* Fix for problems under linux kernel 2.4.19
|
|
||||||
|
|
||||||
============================================================================
|
|
||||||
|
|
||||||
What is new in 0.95
|
|
||||||
|
|
||||||
* Optimized read/write operations. Raw throughput has increased to
|
|
||||||
about 60Mbyte/s on a Celeron/360
|
|
||||||
|
|
||||||
* Python bindings by Jeff Epler
|
|
||||||
|
|
||||||
* Perl bindings by Mark Glines
|
|
||||||
|
|
||||||
* Improved multithreaded operation
|
|
||||||
|
|
||||||
* Simplified library interface
|
|
||||||
|
|
||||||
* Bugfixes
|
|
||||||
|
|
||||||
============================================================================
|
|
||||||
|
|
||||||
What is new in 0.9:
|
|
||||||
|
|
||||||
* Everything
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
NFS exporting is supported in Linux kernels 2.6.27 or later.
|
|
||||||
|
|
||||||
You need to add an fsid=NNN option to /etc/exports to make exporting a
|
|
||||||
FUSE directory work.
|
|
||||||
|
|
||||||
Filesystem support
|
|
||||||
------------------
|
|
||||||
|
|
||||||
NFS exporting works to some extent on all fuse filesystems, but not
|
|
||||||
perfectly. This is due to the stateless nature of the protocol, the
|
|
||||||
server has no way of knowing whether the client is keeping a reference
|
|
||||||
to a file or not, and hence that file may be removed from the server's
|
|
||||||
cache. In that case there has to be a way to look up that object
|
|
||||||
using the inode number, otherwise an ESTALE error will be returned.
|
|
||||||
|
|
||||||
1) low-level interface
|
|
||||||
|
|
||||||
Filesystems need to implement special lookups for the names "." and
|
|
||||||
"..". The former may be requested on any inode, including
|
|
||||||
non-directories, while the latter is only requested for directories.
|
|
||||||
Otherwise these special lookups should behave identically to ordinary
|
|
||||||
lookups.
|
|
||||||
|
|
||||||
2) high-level interface
|
|
||||||
|
|
||||||
Because the high-level interface is path based, it is not possible to
|
|
||||||
delegate looking up by inode to the filesystem.
|
|
||||||
|
|
||||||
To work around this, currently a "noforget" option is provided, which
|
|
||||||
makes the library remember nodes forever. This will make the NFS
|
|
||||||
server happy, but also results in an ever growing memory footprint for
|
|
||||||
the filesystem. For this reason if the filesystem is large (or the
|
|
||||||
memory is small), then this option is not recommended.
|
|
||||||
@@ -1,108 +0,0 @@
|
|||||||
libfuse
|
|
||||||
=======
|
|
||||||
|
|
||||||
Warning: unresolved security issue
|
|
||||||
----------------------------------
|
|
||||||
|
|
||||||
Be aware that FUSE has an unresolved security bug
|
|
||||||
([bug #15](https://github.com/libfuse/libfuse/issues/15)): the
|
|
||||||
permission check for accessing a cached directory is only done once
|
|
||||||
when the directory entry is first loaded into the cache. Subsequent
|
|
||||||
accesses will re-use the results of the first check, even if the
|
|
||||||
directory permissions have since changed, and even if the subsequent
|
|
||||||
access is made by a different user.
|
|
||||||
|
|
||||||
This bug needs to be fixed in the Linux kernel and has been known
|
|
||||||
since 2006 but unfortunately no fix has been applied yet. If you
|
|
||||||
depend on correct permission handling for FUSE file systems, the only
|
|
||||||
workaround is to completely disable caching of directory
|
|
||||||
entries. Alternatively, the severity of the bug can be somewhat
|
|
||||||
reduced by not using the `allow_other` mount option.
|
|
||||||
|
|
||||||
|
|
||||||
About
|
|
||||||
-----
|
|
||||||
|
|
||||||
FUSE (Filesystem in Userspace) is an interface for userspace programs
|
|
||||||
to export a filesystem to the Linux kernel. The FUSE project consists
|
|
||||||
of two components: the *fuse* kernel module (maintained in the regular
|
|
||||||
kernel repositories) and the *libfuse* userspace library (maintained
|
|
||||||
in this repository). libfuse provides the reference implementation
|
|
||||||
for communicating with the FUSE kernel module.
|
|
||||||
|
|
||||||
A FUSE file system is typically implemented as a standalone
|
|
||||||
application that links with libfuse. libfuse provides functions to
|
|
||||||
mount the file system, unmount it, read requests from the kernel, and
|
|
||||||
send responses back. libfuse offers two APIs: a "high-level",
|
|
||||||
synchronous API, and a "low-level" asynchronous API. In both cases,
|
|
||||||
incoming requests from the kernel are passed to the main program using
|
|
||||||
callbacks. When using the high-level API, the callbacks may work with
|
|
||||||
file names and paths instead of inodes, and processing of a request
|
|
||||||
finishes when the callback function returns. When using the low-level
|
|
||||||
API, the callbacks must work with inodes and responses must be sent
|
|
||||||
explicitly using a separate set of API functions.
|
|
||||||
|
|
||||||
|
|
||||||
Installation
|
|
||||||
------------
|
|
||||||
|
|
||||||
./configure
|
|
||||||
make -j8
|
|
||||||
make install
|
|
||||||
|
|
||||||
You may also need to add `/usr/local/lib` to `/etc/ld.so.conf` and/or
|
|
||||||
run *ldconfig*. If you're building from the git repository (instead of
|
|
||||||
using a release tarball), you also need to run `./makeconf.sh` to
|
|
||||||
create the `configure` script.
|
|
||||||
|
|
||||||
You'll also need a fuse kernel module (Linux kernels 2.6.14 or later
|
|
||||||
contain FUSE support).
|
|
||||||
|
|
||||||
For more details see the file `INSTALL`
|
|
||||||
|
|
||||||
Security implications
|
|
||||||
---------------------
|
|
||||||
|
|
||||||
If you run `make install`, the *fusermount* program is installed
|
|
||||||
set-user-id to root. This is done to allow normal users to mount
|
|
||||||
their own filesystem implementations.
|
|
||||||
|
|
||||||
There must however be some limitations, in order to prevent Bad User from
|
|
||||||
doing nasty things. Currently those limitations are:
|
|
||||||
|
|
||||||
- The user can only mount on a mountpoint, for which it has write
|
|
||||||
permission
|
|
||||||
|
|
||||||
- The mountpoint is not a sticky directory which isn't owned by the
|
|
||||||
user (like /tmp usually is)
|
|
||||||
|
|
||||||
- No other user (including root) can access the contents of the
|
|
||||||
mounted filesystem (though this can be relaxed by allowing the use
|
|
||||||
of the `allow_other` and `allow_root` mount options in `fuse.conf`)
|
|
||||||
|
|
||||||
|
|
||||||
Building your own filesystem
|
|
||||||
------------------------------
|
|
||||||
|
|
||||||
FUSE comes with several example file systems in the `examples`
|
|
||||||
directory. For example, the *fusexmp* example mirrors the contents of
|
|
||||||
the root directory under the mountpoint. Start from there and adapt
|
|
||||||
the code!
|
|
||||||
|
|
||||||
The documentation of the API functions and necessary callbacks is
|
|
||||||
mostly contained in the files `include/fuse.h` (for the high-level
|
|
||||||
API) and `include/fuse_lowlevel.h` (for the low-level API). An
|
|
||||||
autogenerated html version of the API is available in the `doc/html`
|
|
||||||
directory and at http://libfuse.github.io/doxygen.
|
|
||||||
|
|
||||||
|
|
||||||
Getting Help
|
|
||||||
------------
|
|
||||||
|
|
||||||
If you need help, please ask on the <fuse-devel@lists.sourceforge.net>
|
|
||||||
mailing list (subscribe at
|
|
||||||
https://lists.sourceforge.net/lists/listinfo/fuse-devel).
|
|
||||||
|
|
||||||
Please report any bugs on the GitHub issue tracker at
|
|
||||||
https://github.com/libfuse/main/issues.
|
|
||||||
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
prefix=@prefix@
|
|
||||||
exec_prefix=@exec_prefix@
|
|
||||||
libdir=@libdir@
|
|
||||||
includedir=@includedir@
|
|
||||||
|
|
||||||
Name: fuse
|
|
||||||
Description: Filesystem in Userspace
|
|
||||||
Version: @VERSION@
|
|
||||||
Libs: -L${libdir} -lfuse -pthread
|
|
||||||
Libs.private: @libfuse_libs@
|
|
||||||
Cflags: -I${includedir}/fuse -D_FILE_OFFSET_BITS=64
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
## Process this file with automake to produce Makefile.in
|
|
||||||
|
|
||||||
fuseincludedir=$(includedir)/fuse
|
|
||||||
|
|
||||||
fuseinclude_HEADERS = \
|
|
||||||
fuse.h \
|
|
||||||
fuse_compat.h \
|
|
||||||
fuse_common.h \
|
|
||||||
fuse_common_compat.h \
|
|
||||||
fuse_lowlevel.h \
|
|
||||||
fuse_lowlevel_compat.h \
|
|
||||||
fuse_opt.h \
|
|
||||||
cuse_lowlevel.h
|
|
||||||
|
|
||||||
include_HEADERS = old/fuse.h ulockmgr.h
|
|
||||||
|
|
||||||
noinst_HEADERS = fuse_kernel.h
|
|
||||||
@@ -1,87 +0,0 @@
|
|||||||
/*
|
|
||||||
CUSE: Character device in Userspace
|
|
||||||
Copyright (C) 2008-2009 SUSE Linux Products GmbH
|
|
||||||
Copyright (C) 2008-2009 Tejun Heo <tj@kernel.org>
|
|
||||||
|
|
||||||
This program can be distributed under the terms of the GNU LGPLv2.
|
|
||||||
See the file COPYING.LIB.
|
|
||||||
|
|
||||||
Read example/cusexmp.c for usages.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _CUSE_LOWLEVEL_H_
|
|
||||||
#define _CUSE_LOWLEVEL_H_
|
|
||||||
|
|
||||||
#ifndef FUSE_USE_VERSION
|
|
||||||
#define FUSE_USE_VERSION 29
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "fuse_lowlevel.h"
|
|
||||||
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/uio.h>
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define CUSE_UNRESTRICTED_IOCTL (1 << 0) /* use unrestricted ioctl */
|
|
||||||
|
|
||||||
struct fuse_session;
|
|
||||||
|
|
||||||
struct cuse_info {
|
|
||||||
unsigned dev_major;
|
|
||||||
unsigned dev_minor;
|
|
||||||
unsigned dev_info_argc;
|
|
||||||
const char **dev_info_argv;
|
|
||||||
unsigned flags;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Most ops behave almost identically to the matching fuse_lowlevel
|
|
||||||
* ops except that they don't take @ino.
|
|
||||||
*
|
|
||||||
* init_done : called after initialization is complete
|
|
||||||
* read/write : always direct IO, simultaneous operations allowed
|
|
||||||
* ioctl : might be in unrestricted mode depending on ci->flags
|
|
||||||
*/
|
|
||||||
struct cuse_lowlevel_ops {
|
|
||||||
void (*init) (void *userdata, struct fuse_conn_info *conn);
|
|
||||||
void (*init_done) (void *userdata);
|
|
||||||
void (*destroy) (void *userdata);
|
|
||||||
void (*open) (fuse_req_t req, struct fuse_file_info *fi);
|
|
||||||
void (*read) (fuse_req_t req, size_t size, off_t off,
|
|
||||||
struct fuse_file_info *fi);
|
|
||||||
void (*write) (fuse_req_t req, const char *buf, size_t size, off_t off,
|
|
||||||
struct fuse_file_info *fi);
|
|
||||||
void (*flush) (fuse_req_t req, struct fuse_file_info *fi);
|
|
||||||
void (*release) (fuse_req_t req, struct fuse_file_info *fi);
|
|
||||||
void (*fsync) (fuse_req_t req, int datasync, struct fuse_file_info *fi);
|
|
||||||
void (*ioctl) (fuse_req_t req, int cmd, void *arg,
|
|
||||||
struct fuse_file_info *fi, unsigned int flags,
|
|
||||||
const void *in_buf, size_t in_bufsz, size_t out_bufsz);
|
|
||||||
void (*poll) (fuse_req_t req, struct fuse_file_info *fi,
|
|
||||||
struct fuse_pollhandle *ph);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct fuse_session *cuse_lowlevel_new(struct fuse_args *args,
|
|
||||||
const struct cuse_info *ci,
|
|
||||||
const struct cuse_lowlevel_ops *clop,
|
|
||||||
void *userdata);
|
|
||||||
|
|
||||||
struct fuse_session *cuse_lowlevel_setup(int argc, char *argv[],
|
|
||||||
const struct cuse_info *ci,
|
|
||||||
const struct cuse_lowlevel_ops *clop,
|
|
||||||
int *multithreaded, void *userdata);
|
|
||||||
|
|
||||||
void cuse_lowlevel_teardown(struct fuse_session *se);
|
|
||||||
|
|
||||||
int cuse_lowlevel_main(int argc, char *argv[], const struct cuse_info *ci,
|
|
||||||
const struct cuse_lowlevel_ops *clop, void *userdata);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* _CUSE_LOWLEVEL_H_ */
|
|
||||||
+7
-116
@@ -9,20 +9,6 @@
|
|||||||
#ifndef _FUSE_H_
|
#ifndef _FUSE_H_
|
||||||
#define _FUSE_H_
|
#define _FUSE_H_
|
||||||
|
|
||||||
/** @file
|
|
||||||
*
|
|
||||||
* This file defines the library interface of FUSE
|
|
||||||
*
|
|
||||||
* IMPORTANT: you should define FUSE_USE_VERSION before including this
|
|
||||||
* header. To use the newest API define it to 26 (recommended for any
|
|
||||||
* new application), to use the old API define it to 21 (default) 22
|
|
||||||
* or 25, to use the even older 1.X API define it to 11.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef FUSE_USE_VERSION
|
|
||||||
#define FUSE_USE_VERSION 21
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "fuse_common.h"
|
#include "fuse_common.h"
|
||||||
#include "fuse_dirents.h"
|
#include "fuse_dirents.h"
|
||||||
|
|
||||||
@@ -668,12 +654,11 @@ struct fuse_context {
|
|||||||
* @param user_data user data supplied in the context during the init() method
|
* @param user_data user data supplied in the context during the init() method
|
||||||
* @return 0 on success, nonzero on failure
|
* @return 0 on success, nonzero on failure
|
||||||
*/
|
*/
|
||||||
/*
|
|
||||||
int fuse_main(int argc, char *argv[], const struct fuse_operations *op,
|
int fuse_main(int argc,
|
||||||
void *user_data);
|
char *argv[],
|
||||||
*/
|
const struct fuse_operations *op,
|
||||||
#define fuse_main(argc, argv, op, user_data) \
|
void *user_data);
|
||||||
fuse_main_real(argc, argv, op, sizeof(*(op)), user_data)
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------- *
|
/* ----------------------------------------------------------- *
|
||||||
* More detailed API *
|
* More detailed API *
|
||||||
@@ -689,7 +674,7 @@ struct fuse_context {
|
|||||||
* @param user_data user data supplied in the context during the init() method
|
* @param user_data user data supplied in the context during the init() method
|
||||||
* @return the created FUSE handle
|
* @return the created FUSE handle
|
||||||
*/
|
*/
|
||||||
struct fuse *fuse_new(struct fuse_chan *ch, struct fuse_args *args,
|
struct fuse *fuse_new(int devfuse_fd, struct fuse_args *args,
|
||||||
const struct fuse_operations *op, size_t op_size,
|
const struct fuse_operations *op, size_t op_size,
|
||||||
void *user_data);
|
void *user_data);
|
||||||
|
|
||||||
@@ -705,17 +690,6 @@ struct fuse *fuse_new(struct fuse_chan *ch, struct fuse_args *args,
|
|||||||
*/
|
*/
|
||||||
void fuse_destroy(struct fuse *f);
|
void fuse_destroy(struct fuse *f);
|
||||||
|
|
||||||
/**
|
|
||||||
* FUSE event loop.
|
|
||||||
*
|
|
||||||
* Requests from the kernel are processed, and the appropriate
|
|
||||||
* operations are called.
|
|
||||||
*
|
|
||||||
* @param f the FUSE handle
|
|
||||||
* @return 0 if no error occurred, -1 otherwise
|
|
||||||
*/
|
|
||||||
int fuse_loop(struct fuse *f);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exit from event loop
|
* Exit from event loop
|
||||||
*
|
*
|
||||||
@@ -760,26 +734,6 @@ int fuse_loop_mt(struct fuse *f);
|
|||||||
*/
|
*/
|
||||||
struct fuse_context *fuse_get_context(void);
|
struct fuse_context *fuse_get_context(void);
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the current supplementary group IDs for the current request
|
|
||||||
*
|
|
||||||
* Similar to the getgroups(2) system call, except the return value is
|
|
||||||
* always the total number of group IDs, even if it is larger than the
|
|
||||||
* specified size.
|
|
||||||
*
|
|
||||||
* The current fuse kernel module in linux (as of 2.6.30) doesn't pass
|
|
||||||
* the group list to userspace, hence this function needs to parse
|
|
||||||
* "/proc/$TID/task/$TID/status" to get the group IDs.
|
|
||||||
*
|
|
||||||
* This feature may not be supported on all operating systems. In
|
|
||||||
* such a case this function will return -ENOSYS.
|
|
||||||
*
|
|
||||||
* @param size size of given array
|
|
||||||
* @param list array of group IDs to be filled in
|
|
||||||
* @return the total number of supplementary group IDs or -errno on failure
|
|
||||||
*/
|
|
||||||
int fuse_getgroups(int size, gid_t list[]);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the current request has already been interrupted
|
* Check if the current request has already been interrupted
|
||||||
*
|
*
|
||||||
@@ -787,16 +741,6 @@ int fuse_getgroups(int size, gid_t list[]);
|
|||||||
*/
|
*/
|
||||||
int fuse_interrupted(void);
|
int fuse_interrupted(void);
|
||||||
|
|
||||||
/**
|
|
||||||
* Obsolete, doesn't do anything
|
|
||||||
*
|
|
||||||
* @return -EINVAL
|
|
||||||
*/
|
|
||||||
int fuse_invalidate(struct fuse *f, const char *path);
|
|
||||||
|
|
||||||
/* Deprecated, don't use */
|
|
||||||
int fuse_is_lib_option(const char *opt);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The real main function
|
* The real main function
|
||||||
*
|
*
|
||||||
@@ -1030,18 +974,12 @@ typedef void (*fuse_processor_t)(struct fuse *, struct fuse_cmd *, void *);
|
|||||||
/** This is the part of fuse_main() before the event loop */
|
/** This is the part of fuse_main() before the event loop */
|
||||||
struct fuse *fuse_setup(int argc, char *argv[],
|
struct fuse *fuse_setup(int argc, char *argv[],
|
||||||
const struct fuse_operations *op, size_t op_size,
|
const struct fuse_operations *op, size_t op_size,
|
||||||
char **mountpoint, int *multithreaded,
|
char **mountpoint,
|
||||||
void *user_data);
|
void *user_data);
|
||||||
|
|
||||||
/** This is the part of fuse_main() after the event loop */
|
/** This is the part of fuse_main() after the event loop */
|
||||||
void fuse_teardown(struct fuse *fuse, char *mountpoint);
|
void fuse_teardown(struct fuse *fuse, char *mountpoint);
|
||||||
|
|
||||||
/** Read a single command. If none are read, return NULL */
|
|
||||||
struct fuse_cmd *fuse_read_cmd(struct fuse *f);
|
|
||||||
|
|
||||||
/** Process a single command */
|
|
||||||
void fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd);
|
|
||||||
|
|
||||||
/** Multi threaded event loop, which calls the custom command
|
/** Multi threaded event loop, which calls the custom command
|
||||||
processor function */
|
processor function */
|
||||||
int fuse_loop_mt_proc(struct fuse *f, fuse_processor_t proc, void *data);
|
int fuse_loop_mt_proc(struct fuse *f, fuse_processor_t proc, void *data);
|
||||||
@@ -1056,53 +994,6 @@ void fuse_set_getcontext_func(struct fuse_context *(*func)(void));
|
|||||||
/** Get session from fuse object */
|
/** Get session from fuse object */
|
||||||
struct fuse_session *fuse_get_session(struct fuse *f);
|
struct fuse_session *fuse_get_session(struct fuse *f);
|
||||||
|
|
||||||
/* ----------------------------------------------------------- *
|
|
||||||
* Compatibility stuff *
|
|
||||||
* ----------------------------------------------------------- */
|
|
||||||
|
|
||||||
#if FUSE_USE_VERSION < 26
|
|
||||||
# include "fuse_compat.h"
|
|
||||||
# undef fuse_main
|
|
||||||
# if FUSE_USE_VERSION == 25
|
|
||||||
# define fuse_main(argc, argv, op) \
|
|
||||||
fuse_main_real_compat25(argc, argv, op, sizeof(*(op)))
|
|
||||||
# define fuse_new fuse_new_compat25
|
|
||||||
# define fuse_setup fuse_setup_compat25
|
|
||||||
# define fuse_teardown fuse_teardown_compat22
|
|
||||||
# define fuse_operations fuse_operations_compat25
|
|
||||||
# elif FUSE_USE_VERSION == 22
|
|
||||||
# define fuse_main(argc, argv, op) \
|
|
||||||
fuse_main_real_compat22(argc, argv, op, sizeof(*(op)))
|
|
||||||
# define fuse_new fuse_new_compat22
|
|
||||||
# define fuse_setup fuse_setup_compat22
|
|
||||||
# define fuse_teardown fuse_teardown_compat22
|
|
||||||
# define fuse_operations fuse_operations_compat22
|
|
||||||
# define fuse_file_info fuse_file_info_compat
|
|
||||||
# elif FUSE_USE_VERSION == 24
|
|
||||||
# error Compatibility with high-level API version 24 not supported
|
|
||||||
# else
|
|
||||||
# define fuse_dirfil_t fuse_dirfil_t_compat
|
|
||||||
# define __fuse_read_cmd fuse_read_cmd
|
|
||||||
# define __fuse_process_cmd fuse_process_cmd
|
|
||||||
# define __fuse_loop_mt fuse_loop_mt_proc
|
|
||||||
# if FUSE_USE_VERSION == 21
|
|
||||||
# define fuse_operations fuse_operations_compat2
|
|
||||||
# define fuse_main fuse_main_compat2
|
|
||||||
# define fuse_new fuse_new_compat2
|
|
||||||
# define __fuse_setup fuse_setup_compat2
|
|
||||||
# define __fuse_teardown fuse_teardown_compat22
|
|
||||||
# define __fuse_exited fuse_exited
|
|
||||||
# define __fuse_set_getcontext_func fuse_set_getcontext_func
|
|
||||||
# else
|
|
||||||
# define fuse_statfs fuse_statfs_compat1
|
|
||||||
# define fuse_operations fuse_operations_compat1
|
|
||||||
# define fuse_main fuse_main_compat1
|
|
||||||
# define fuse_new fuse_new_compat1
|
|
||||||
# define FUSE_DEBUG FUSE_DEBUG_COMPAT1
|
|
||||||
# endif
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <sys/uio.h>
|
||||||
|
|
||||||
|
#define FUSE_CHAN_SPLICE_READ (1<<0)
|
||||||
|
#define FUSE_CHAN_SPLICE_WRITE (1<<1)
|
||||||
|
|
||||||
|
typedef struct fuse_chan_t fuse_chan_t;
|
||||||
|
struct fuse_chan_t
|
||||||
|
{
|
||||||
|
void *buf;
|
||||||
|
uint64_t bufsize;
|
||||||
|
int32_t fd;
|
||||||
|
int32_t splice_pipe[2];
|
||||||
|
uint32_t flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
fuse_chan_t *fuse_chan_new(int32_t fd, uint32_t flags);
|
||||||
|
void fuse_chan_destroy(fuse_chan_t *ch);
|
||||||
|
int64_t fuse_chan_recv(fuse_chan_t *ch, char *buf, uint64_t size);
|
||||||
|
int64_t fuse_chan_send(fuse_chan_t *ch, const struct iovec iov[], uint64_t count);
|
||||||
|
|
||||||
@@ -33,8 +33,8 @@
|
|||||||
#error Please add -D_FILE_OFFSET_BITS=64 to your compile flags!
|
#error Please add -D_FILE_OFFSET_BITS=64 to your compile flags!
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define FUSE_DEFAULT_MAX_PAGES_PER_REQ 32
|
#define FUSE_MSG_DEFAULT_PAGES 32
|
||||||
#define FUSE_MAX_MAX_PAGES 256
|
#define FUSE_MSG_MAX_PAGES 256
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@@ -206,7 +206,7 @@ struct fuse_conn_info {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct fuse_session;
|
struct fuse_session;
|
||||||
struct fuse_chan;
|
typedef struct fuse_chan_t fuse_chan_t;
|
||||||
struct fuse_pollhandle;
|
struct fuse_pollhandle;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -219,8 +219,8 @@ struct fuse_pollhandle;
|
|||||||
* @param args argument vector
|
* @param args argument vector
|
||||||
* @return the communication channel on success, NULL on failure
|
* @return the communication channel on success, NULL on failure
|
||||||
*/
|
*/
|
||||||
struct fuse_chan *fuse_mount(const char *mountpoint,
|
int fuse_mount(const char *mountpoint,
|
||||||
struct fuse_args *args);
|
struct fuse_args *args);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Umount a FUSE mountpoint
|
* Umount a FUSE mountpoint
|
||||||
@@ -228,7 +228,8 @@ struct fuse_chan *fuse_mount(const char *mountpoint,
|
|||||||
* @param mountpoint the mount point path
|
* @param mountpoint the mount point path
|
||||||
* @param ch the communication channel
|
* @param ch the communication channel
|
||||||
*/
|
*/
|
||||||
void fuse_unmount(const char *mountpoint, struct fuse_chan *ch);
|
void fuse_unmount(const char *mountpoint,
|
||||||
|
int devfuse_fd);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse common options
|
* Parse common options
|
||||||
@@ -247,12 +248,12 @@ void fuse_unmount(const char *mountpoint, struct fuse_chan *ch);
|
|||||||
*
|
*
|
||||||
* @param args argument vector
|
* @param args argument vector
|
||||||
* @param mountpoint the returned mountpoint, should be freed after use
|
* @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
|
* @param foreground set to 1 if one of the relevant options is present
|
||||||
* @return 0 on success, -1 on failure
|
* @return 0 on success, -1 on failure
|
||||||
*/
|
*/
|
||||||
int fuse_parse_cmdline(struct fuse_args *args, char **mountpoint,
|
int fuse_parse_cmdline(struct fuse_args *args,
|
||||||
int *multithreaded, int *foreground);
|
char **mountpoint,
|
||||||
|
int *foreground);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Go into the background
|
* Go into the background
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
/* these definitions provide source compatibility to prior versions.
|
/* these definitions provide source compatibility to prior versions.
|
||||||
Do not include this file directly! */
|
Do not include this file directly! */
|
||||||
|
|
||||||
|
#include "fuse_opt.h"
|
||||||
|
|
||||||
struct fuse_file_info_compat {
|
struct fuse_file_info_compat {
|
||||||
int flags;
|
int flags;
|
||||||
unsigned long fh;
|
unsigned long fh;
|
||||||
|
|||||||
@@ -1,196 +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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* these definitions provide source compatibility to prior versions.
|
|
||||||
Do not include this file directly! */
|
|
||||||
|
|
||||||
struct fuse_operations_compat25 {
|
|
||||||
int (*getattr) (const char *, struct stat *);
|
|
||||||
int (*readlink) (const char *, char *, size_t);
|
|
||||||
int (*mknod) (const char *, mode_t, dev_t);
|
|
||||||
int (*mkdir) (const char *, mode_t);
|
|
||||||
int (*unlink) (const char *);
|
|
||||||
int (*rmdir) (const char *);
|
|
||||||
int (*symlink) (const char *, const char *);
|
|
||||||
int (*rename) (const char *, const char *);
|
|
||||||
int (*link) (const char *, const char *);
|
|
||||||
int (*chmod) (const char *, mode_t);
|
|
||||||
int (*chown) (const char *, uid_t, gid_t);
|
|
||||||
int (*truncate) (const char *, off_t);
|
|
||||||
int (*utime) (const char *, struct utimbuf *);
|
|
||||||
int (*open) (const char *, struct fuse_file_info *);
|
|
||||||
int (*read) (const char *, char *, size_t, off_t,
|
|
||||||
struct fuse_file_info *);
|
|
||||||
int (*write) (const char *, const char *, size_t, off_t,
|
|
||||||
struct fuse_file_info *);
|
|
||||||
int (*statfs) (const char *, struct statvfs *);
|
|
||||||
int (*flush) (const char *, struct fuse_file_info *);
|
|
||||||
int (*release) (const char *, struct fuse_file_info *);
|
|
||||||
int (*fsync) (const char *, int, struct fuse_file_info *);
|
|
||||||
int (*setxattr) (const char *, const char *, const char *, size_t, int);
|
|
||||||
int (*getxattr) (const char *, const char *, char *, size_t);
|
|
||||||
int (*listxattr) (const char *, char *, size_t);
|
|
||||||
int (*removexattr) (const char *, const char *);
|
|
||||||
int (*opendir) (const char *, struct fuse_file_info *);
|
|
||||||
int (*readdir) (const char *, void *, off_t,
|
|
||||||
struct fuse_file_info *);
|
|
||||||
int (*releasedir) (const char *, struct fuse_file_info *);
|
|
||||||
int (*fsyncdir) (const char *, int, struct fuse_file_info *);
|
|
||||||
void *(*init) (void);
|
|
||||||
void (*destroy) (void *);
|
|
||||||
int (*access) (const char *, int);
|
|
||||||
int (*create) (const char *, mode_t, struct fuse_file_info *);
|
|
||||||
int (*ftruncate) (const char *, off_t, struct fuse_file_info *);
|
|
||||||
int (*fgetattr) (const char *, struct stat *, struct fuse_file_info *);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct fuse *fuse_new_compat25(int fd, struct fuse_args *args,
|
|
||||||
const struct fuse_operations_compat25 *op,
|
|
||||||
size_t op_size);
|
|
||||||
|
|
||||||
int fuse_main_real_compat25(int argc, char *argv[],
|
|
||||||
const struct fuse_operations_compat25 *op,
|
|
||||||
size_t op_size);
|
|
||||||
|
|
||||||
struct fuse *fuse_setup_compat25(int argc, char *argv[],
|
|
||||||
const struct fuse_operations_compat25 *op,
|
|
||||||
size_t op_size, char **mountpoint,
|
|
||||||
int *multithreaded, int *fd);
|
|
||||||
|
|
||||||
void fuse_teardown_compat22(struct fuse *fuse, int fd, char *mountpoint);
|
|
||||||
|
|
||||||
#if !defined(__FreeBSD__) && !defined(__NetBSD__)
|
|
||||||
#include <sys/statfs.h>
|
|
||||||
|
|
||||||
struct fuse_operations_compat22 {
|
|
||||||
int (*getattr) (const char *, struct stat *);
|
|
||||||
int (*readlink) (const char *, char *, size_t);
|
|
||||||
int (*mknod) (const char *, mode_t, dev_t);
|
|
||||||
int (*mkdir) (const char *, mode_t);
|
|
||||||
int (*unlink) (const char *);
|
|
||||||
int (*rmdir) (const char *);
|
|
||||||
int (*symlink) (const char *, const char *);
|
|
||||||
int (*rename) (const char *, const char *);
|
|
||||||
int (*link) (const char *, const char *);
|
|
||||||
int (*chmod) (const char *, mode_t);
|
|
||||||
int (*chown) (const char *, uid_t, gid_t);
|
|
||||||
int (*truncate) (const char *, off_t);
|
|
||||||
int (*utime) (const char *, struct utimbuf *);
|
|
||||||
int (*open) (const char *, struct fuse_file_info_compat *);
|
|
||||||
int (*read) (const char *, char *, size_t, off_t,
|
|
||||||
struct fuse_file_info_compat *);
|
|
||||||
int (*write) (const char *, const char *, size_t, off_t,
|
|
||||||
struct fuse_file_info_compat *);
|
|
||||||
int (*statfs) (const char *, struct statfs *);
|
|
||||||
int (*flush) (const char *, struct fuse_file_info_compat *);
|
|
||||||
int (*release) (const char *, struct fuse_file_info_compat *);
|
|
||||||
int (*fsync) (const char *, int, struct fuse_file_info_compat *);
|
|
||||||
int (*setxattr) (const char *, const char *, const char *, size_t, int);
|
|
||||||
int (*getxattr) (const char *, const char *, char *, size_t);
|
|
||||||
int (*listxattr) (const char *, char *, size_t);
|
|
||||||
int (*removexattr) (const char *, const char *);
|
|
||||||
int (*opendir) (const char *, struct fuse_file_info_compat *);
|
|
||||||
int (*readdir) (const char *, void *, off_t,
|
|
||||||
struct fuse_file_info_compat *);
|
|
||||||
int (*releasedir) (const char *, struct fuse_file_info_compat *);
|
|
||||||
int (*fsyncdir) (const char *, int, struct fuse_file_info_compat *);
|
|
||||||
void *(*init) (void);
|
|
||||||
void (*destroy) (void *);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct fuse *fuse_new_compat22(int fd, const char *opts,
|
|
||||||
const struct fuse_operations_compat22 *op,
|
|
||||||
size_t op_size);
|
|
||||||
|
|
||||||
struct fuse *fuse_setup_compat22(int argc, char *argv[],
|
|
||||||
const struct fuse_operations_compat22 *op,
|
|
||||||
size_t op_size, char **mountpoint,
|
|
||||||
int *multithreaded, int *fd);
|
|
||||||
|
|
||||||
int fuse_main_real_compat22(int argc, char *argv[],
|
|
||||||
const struct fuse_operations_compat22 *op,
|
|
||||||
size_t op_size);
|
|
||||||
|
|
||||||
struct fuse_operations_compat2 {
|
|
||||||
int (*getattr) (const char *, struct stat *);
|
|
||||||
int (*readlink) (const char *, char *, size_t);
|
|
||||||
int (*mknod) (const char *, mode_t, dev_t);
|
|
||||||
int (*mkdir) (const char *, mode_t);
|
|
||||||
int (*unlink) (const char *);
|
|
||||||
int (*rmdir) (const char *);
|
|
||||||
int (*symlink) (const char *, const char *);
|
|
||||||
int (*rename) (const char *, const char *);
|
|
||||||
int (*link) (const char *, const char *);
|
|
||||||
int (*chmod) (const char *, mode_t);
|
|
||||||
int (*chown) (const char *, uid_t, gid_t);
|
|
||||||
int (*truncate) (const char *, off_t);
|
|
||||||
int (*utime) (const char *, struct utimbuf *);
|
|
||||||
int (*open) (const char *, int);
|
|
||||||
int (*read) (const char *, char *, size_t, off_t);
|
|
||||||
int (*write) (const char *, const char *, size_t, off_t);
|
|
||||||
int (*statfs) (const char *, struct statfs *);
|
|
||||||
int (*flush) (const char *);
|
|
||||||
int (*release) (const char *, int);
|
|
||||||
int (*fsync) (const char *, int);
|
|
||||||
int (*setxattr) (const char *, const char *, const char *,
|
|
||||||
size_t, int);
|
|
||||||
int (*getxattr) (const char *, const char *, char *, size_t);
|
|
||||||
int (*listxattr) (const char *, char *, size_t);
|
|
||||||
int (*removexattr) (const char *, const char *);
|
|
||||||
};
|
|
||||||
|
|
||||||
int fuse_main_compat2(int argc, char *argv[],
|
|
||||||
const struct fuse_operations_compat2 *op);
|
|
||||||
|
|
||||||
struct fuse *fuse_new_compat2(int fd, const char *opts,
|
|
||||||
const struct fuse_operations_compat2 *op);
|
|
||||||
|
|
||||||
struct fuse *fuse_setup_compat2(int argc, char *argv[],
|
|
||||||
const struct fuse_operations_compat2 *op,
|
|
||||||
char **mountpoint, int *multithreaded, int *fd);
|
|
||||||
|
|
||||||
struct fuse_statfs_compat1 {
|
|
||||||
long block_size;
|
|
||||||
long blocks;
|
|
||||||
long blocks_free;
|
|
||||||
long files;
|
|
||||||
long files_free;
|
|
||||||
long namelen;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct fuse_operations_compat1 {
|
|
||||||
int (*getattr) (const char *, struct stat *);
|
|
||||||
int (*readlink) (const char *, char *, size_t);
|
|
||||||
int (*mknod) (const char *, mode_t, dev_t);
|
|
||||||
int (*mkdir) (const char *, mode_t);
|
|
||||||
int (*unlink) (const char *);
|
|
||||||
int (*rmdir) (const char *);
|
|
||||||
int (*symlink) (const char *, const char *);
|
|
||||||
int (*rename) (const char *, const char *);
|
|
||||||
int (*link) (const char *, const char *);
|
|
||||||
int (*chmod) (const char *, mode_t);
|
|
||||||
int (*chown) (const char *, uid_t, gid_t);
|
|
||||||
int (*truncate) (const char *, off_t);
|
|
||||||
int (*utime) (const char *, struct utimbuf *);
|
|
||||||
int (*open) (const char *, int);
|
|
||||||
int (*read) (const char *, char *, size_t, off_t);
|
|
||||||
int (*write) (const char *, const char *, size_t, off_t);
|
|
||||||
int (*statfs) (struct fuse_statfs_compat1 *);
|
|
||||||
int (*release) (const char *, int);
|
|
||||||
int (*fsync) (const char *, int);
|
|
||||||
};
|
|
||||||
|
|
||||||
#define FUSE_DEBUG_COMPAT1 (1 << 1)
|
|
||||||
|
|
||||||
struct fuse *fuse_new_compat1(int fd, int flags,
|
|
||||||
const struct fuse_operations_compat1 *op);
|
|
||||||
|
|
||||||
void fuse_main_compat1(int argc, char *argv[],
|
|
||||||
const struct fuse_operations_compat1 *op);
|
|
||||||
|
|
||||||
#endif /* __FreeBSD__ || __NetBSD__ */
|
|
||||||
+1492
-1784
File diff suppressed because it is too large
Load Diff
@@ -141,15 +141,4 @@ struct fuse_session *fuse_lowlevel_new_compat(const char *opts,
|
|||||||
|
|
||||||
#endif /* __FreeBSD__ || __NetBSD__ */
|
#endif /* __FreeBSD__ || __NetBSD__ */
|
||||||
|
|
||||||
struct fuse_chan_ops_compat24 {
|
int fuse_chan_receive(fuse_chan_t *ch, char *buf, size_t size);
|
||||||
int (*receive)(struct fuse_chan *ch, char *buf, size_t size);
|
|
||||||
int (*send)(struct fuse_chan *ch, const struct iovec iov[],
|
|
||||||
size_t count);
|
|
||||||
void (*destroy)(struct fuse_chan *ch);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct fuse_chan *fuse_chan_new_compat24(struct fuse_chan_ops_compat24 *op,
|
|
||||||
int fd, size_t bufsize, void *data);
|
|
||||||
|
|
||||||
int fuse_chan_receive(struct fuse_chan *ch, char *buf, size_t size);
|
|
||||||
struct fuse_chan *fuse_kern_chan_new(int fd);
|
|
||||||
|
|||||||
@@ -1,42 +0,0 @@
|
|||||||
## Process this file with automake to produce Makefile.in
|
|
||||||
|
|
||||||
AUTOMAKE_OPTIONS = subdir-objects
|
|
||||||
AM_CPPFLAGS = -I$(top_srcdir)/include -DFUSERMOUNT_DIR=\"$(bindir)\" \
|
|
||||||
-D_FILE_OFFSET_BITS=64 -D_REENTRANT -DFUSE_USE_VERSION=26
|
|
||||||
|
|
||||||
lib_LTLIBRARIES = libfuse.la libulockmgr.la
|
|
||||||
|
|
||||||
if BSD
|
|
||||||
mount_source = mount_bsd.c
|
|
||||||
else
|
|
||||||
mount_source = mount.c mount_util.c mount_util.h
|
|
||||||
endif
|
|
||||||
|
|
||||||
libfuse_la_SOURCES = \
|
|
||||||
fuse.c \
|
|
||||||
fuse_i.h \
|
|
||||||
fuse_kern_chan.c \
|
|
||||||
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 \
|
|
||||||
helper.c \
|
|
||||||
$(mount_source)
|
|
||||||
|
|
||||||
libfuse_la_LDFLAGS = -pthread @libfuse_libs@ -version-number 2:9:7 \
|
|
||||||
-Wl,--version-script,$(srcdir)/fuse_versionscript
|
|
||||||
|
|
||||||
if NETBSD
|
|
||||||
libfuse_la_LIBADD = -lperfuse -lpuffs
|
|
||||||
endif
|
|
||||||
|
|
||||||
libulockmgr_la_SOURCES = ulockmgr.c
|
|
||||||
libulockmgr_la_LDFLAGS = -pthread -version-number 1:0:1
|
|
||||||
|
|
||||||
EXTRA_DIST = fuse_versionscript
|
|
||||||
+202
-202
@@ -18,140 +18,140 @@
|
|||||||
|
|
||||||
size_t fuse_buf_size(const struct fuse_bufvec *bufv)
|
size_t fuse_buf_size(const struct fuse_bufvec *bufv)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
|
|
||||||
for (i = 0; i < bufv->count; i++) {
|
for (i = 0; i < bufv->count; i++) {
|
||||||
if (bufv->buf[i].size == SIZE_MAX)
|
if (bufv->buf[i].size == SIZE_MAX)
|
||||||
size = SIZE_MAX;
|
size = SIZE_MAX;
|
||||||
else
|
else
|
||||||
size += bufv->buf[i].size;
|
size += bufv->buf[i].size;
|
||||||
}
|
}
|
||||||
|
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t min_size(size_t s1, size_t s2)
|
static size_t min_size(size_t s1, size_t s2)
|
||||||
{
|
{
|
||||||
return s1 < s2 ? s1 : s2;
|
return s1 < s2 ? s1 : s2;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t fuse_buf_write(const struct fuse_buf *dst, size_t dst_off,
|
static ssize_t fuse_buf_write(const struct fuse_buf *dst, size_t dst_off,
|
||||||
const struct fuse_buf *src, size_t src_off,
|
const struct fuse_buf *src, size_t src_off,
|
||||||
size_t len)
|
size_t len)
|
||||||
{
|
{
|
||||||
ssize_t res = 0;
|
ssize_t res = 0;
|
||||||
size_t copied = 0;
|
size_t copied = 0;
|
||||||
|
|
||||||
while (len) {
|
while (len) {
|
||||||
if (dst->flags & FUSE_BUF_FD_SEEK) {
|
if (dst->flags & FUSE_BUF_FD_SEEK) {
|
||||||
res = pwrite(dst->fd, src->mem + src_off, len,
|
res = pwrite(dst->fd, src->mem + src_off, len,
|
||||||
dst->pos + dst_off);
|
dst->pos + dst_off);
|
||||||
} else {
|
} else {
|
||||||
res = write(dst->fd, src->mem + src_off, len);
|
res = write(dst->fd, src->mem + src_off, len);
|
||||||
}
|
}
|
||||||
if (res == -1) {
|
if (res == -1) {
|
||||||
if (!copied)
|
if (!copied)
|
||||||
return -errno;
|
return -errno;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (res == 0)
|
if (res == 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
copied += res;
|
copied += res;
|
||||||
if (!(dst->flags & FUSE_BUF_FD_RETRY))
|
if (!(dst->flags & FUSE_BUF_FD_RETRY))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
src_off += res;
|
src_off += res;
|
||||||
dst_off += res;
|
dst_off += res;
|
||||||
len -= res;
|
len -= res;
|
||||||
}
|
}
|
||||||
|
|
||||||
return copied;
|
return copied;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t fuse_buf_read(const struct fuse_buf *dst, size_t dst_off,
|
static ssize_t fuse_buf_read(const struct fuse_buf *dst, size_t dst_off,
|
||||||
const struct fuse_buf *src, size_t src_off,
|
const struct fuse_buf *src, size_t src_off,
|
||||||
size_t len)
|
size_t len)
|
||||||
{
|
{
|
||||||
ssize_t res = 0;
|
ssize_t res = 0;
|
||||||
size_t copied = 0;
|
size_t copied = 0;
|
||||||
|
|
||||||
while (len) {
|
while (len) {
|
||||||
if (src->flags & FUSE_BUF_FD_SEEK) {
|
if (src->flags & FUSE_BUF_FD_SEEK) {
|
||||||
res = pread(src->fd, dst->mem + dst_off, len,
|
res = pread(src->fd, dst->mem + dst_off, len,
|
||||||
src->pos + src_off);
|
src->pos + src_off);
|
||||||
} else {
|
} else {
|
||||||
res = read(src->fd, dst->mem + dst_off, len);
|
res = read(src->fd, dst->mem + dst_off, len);
|
||||||
}
|
}
|
||||||
if (res == -1) {
|
if (res == -1) {
|
||||||
if (!copied)
|
if (!copied)
|
||||||
return -errno;
|
return -errno;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (res == 0)
|
if (res == 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
copied += res;
|
copied += res;
|
||||||
if (!(src->flags & FUSE_BUF_FD_RETRY))
|
if (!(src->flags & FUSE_BUF_FD_RETRY))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
dst_off += res;
|
dst_off += res;
|
||||||
src_off += res;
|
src_off += res;
|
||||||
len -= res;
|
len -= res;
|
||||||
}
|
}
|
||||||
|
|
||||||
return copied;
|
return copied;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t fuse_buf_fd_to_fd(const struct fuse_buf *dst, size_t dst_off,
|
static ssize_t fuse_buf_fd_to_fd(const struct fuse_buf *dst, size_t dst_off,
|
||||||
const struct fuse_buf *src, size_t src_off,
|
const struct fuse_buf *src, size_t src_off,
|
||||||
size_t len)
|
size_t len)
|
||||||
{
|
{
|
||||||
char buf[4096];
|
char buf[4096];
|
||||||
struct fuse_buf tmp = {
|
struct fuse_buf tmp = {
|
||||||
.size = sizeof(buf),
|
.size = sizeof(buf),
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
};
|
};
|
||||||
ssize_t res;
|
ssize_t res;
|
||||||
size_t copied = 0;
|
size_t copied = 0;
|
||||||
|
|
||||||
tmp.mem = buf;
|
tmp.mem = buf;
|
||||||
|
|
||||||
while (len) {
|
while (len) {
|
||||||
size_t this_len = min_size(tmp.size, len);
|
size_t this_len = min_size(tmp.size, len);
|
||||||
size_t read_len;
|
size_t read_len;
|
||||||
|
|
||||||
res = fuse_buf_read(&tmp, 0, src, src_off, this_len);
|
res = fuse_buf_read(&tmp, 0, src, src_off, this_len);
|
||||||
if (res < 0) {
|
if (res < 0) {
|
||||||
if (!copied)
|
if (!copied)
|
||||||
return res;
|
return res;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (res == 0)
|
if (res == 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
read_len = res;
|
read_len = res;
|
||||||
res = fuse_buf_write(dst, dst_off, &tmp, 0, read_len);
|
res = fuse_buf_write(dst, dst_off, &tmp, 0, read_len);
|
||||||
if (res < 0) {
|
if (res < 0) {
|
||||||
if (!copied)
|
if (!copied)
|
||||||
return res;
|
return res;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (res == 0)
|
if (res == 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
copied += res;
|
copied += res;
|
||||||
|
|
||||||
if (res < this_len)
|
if (res < this_len)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
dst_off += res;
|
dst_off += res;
|
||||||
src_off += res;
|
src_off += res;
|
||||||
len -= res;
|
len -= res;
|
||||||
}
|
}
|
||||||
|
|
||||||
return copied;
|
return copied;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_SPLICE
|
#ifdef HAVE_SPLICE
|
||||||
@@ -159,64 +159,64 @@ static ssize_t fuse_buf_splice(const struct fuse_buf *dst, size_t dst_off,
|
|||||||
const struct fuse_buf *src, size_t src_off,
|
const struct fuse_buf *src, size_t src_off,
|
||||||
size_t len, enum fuse_buf_copy_flags flags)
|
size_t len, enum fuse_buf_copy_flags flags)
|
||||||
{
|
{
|
||||||
int splice_flags = 0;
|
int splice_flags = 0;
|
||||||
off_t *srcpos = NULL;
|
off_t *srcpos = NULL;
|
||||||
off_t *dstpos = NULL;
|
off_t *dstpos = NULL;
|
||||||
off_t srcpos_val;
|
off_t srcpos_val;
|
||||||
off_t dstpos_val;
|
off_t dstpos_val;
|
||||||
ssize_t res;
|
ssize_t res;
|
||||||
size_t copied = 0;
|
size_t copied = 0;
|
||||||
|
|
||||||
if (flags & FUSE_BUF_SPLICE_MOVE)
|
if (flags & FUSE_BUF_SPLICE_MOVE)
|
||||||
splice_flags |= SPLICE_F_MOVE;
|
splice_flags |= SPLICE_F_MOVE;
|
||||||
if (flags & FUSE_BUF_SPLICE_NONBLOCK)
|
if (flags & FUSE_BUF_SPLICE_NONBLOCK)
|
||||||
splice_flags |= SPLICE_F_NONBLOCK;
|
splice_flags |= SPLICE_F_NONBLOCK;
|
||||||
|
|
||||||
if (src->flags & FUSE_BUF_FD_SEEK) {
|
if (src->flags & FUSE_BUF_FD_SEEK) {
|
||||||
srcpos_val = src->pos + src_off;
|
srcpos_val = src->pos + src_off;
|
||||||
srcpos = &srcpos_val;
|
srcpos = &srcpos_val;
|
||||||
}
|
}
|
||||||
if (dst->flags & FUSE_BUF_FD_SEEK) {
|
if (dst->flags & FUSE_BUF_FD_SEEK) {
|
||||||
dstpos_val = dst->pos + dst_off;
|
dstpos_val = dst->pos + dst_off;
|
||||||
dstpos = &dstpos_val;
|
dstpos = &dstpos_val;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (len) {
|
while (len) {
|
||||||
res = splice(src->fd, srcpos, dst->fd, dstpos, len,
|
res = splice(src->fd, srcpos, dst->fd, dstpos, len,
|
||||||
splice_flags);
|
splice_flags);
|
||||||
if (res == -1) {
|
if (res == -1) {
|
||||||
if (copied)
|
if (copied)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (errno != EINVAL || (flags & FUSE_BUF_FORCE_SPLICE))
|
if (errno != EINVAL || (flags & FUSE_BUF_FORCE_SPLICE))
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
/* Maybe splice is not supported for this combination */
|
/* Maybe splice is not supported for this combination */
|
||||||
return fuse_buf_fd_to_fd(dst, dst_off, src, src_off,
|
return fuse_buf_fd_to_fd(dst, dst_off, src, src_off,
|
||||||
len);
|
len);
|
||||||
}
|
}
|
||||||
if (res == 0)
|
if (res == 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
copied += res;
|
copied += res;
|
||||||
if (!(src->flags & FUSE_BUF_FD_RETRY) &&
|
if (!(src->flags & FUSE_BUF_FD_RETRY) &&
|
||||||
!(dst->flags & FUSE_BUF_FD_RETRY)) {
|
!(dst->flags & FUSE_BUF_FD_RETRY)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
len -= res;
|
len -= res;
|
||||||
}
|
}
|
||||||
|
|
||||||
return copied;
|
return copied;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
static ssize_t fuse_buf_splice(const struct fuse_buf *dst, size_t dst_off,
|
static ssize_t fuse_buf_splice(const struct fuse_buf *dst, size_t dst_off,
|
||||||
const struct fuse_buf *src, size_t src_off,
|
const struct fuse_buf *src, size_t src_off,
|
||||||
size_t len, enum fuse_buf_copy_flags flags)
|
size_t len, enum fuse_buf_copy_flags flags)
|
||||||
{
|
{
|
||||||
(void) flags;
|
(void) flags;
|
||||||
|
|
||||||
return fuse_buf_fd_to_fd(dst, dst_off, src, src_off, len);
|
return fuse_buf_fd_to_fd(dst, dst_off, src, src_off, len);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -225,94 +225,94 @@ static ssize_t fuse_buf_copy_one(const struct fuse_buf *dst, size_t dst_off,
|
|||||||
const struct fuse_buf *src, size_t src_off,
|
const struct fuse_buf *src, size_t src_off,
|
||||||
size_t len, enum fuse_buf_copy_flags flags)
|
size_t len, enum fuse_buf_copy_flags flags)
|
||||||
{
|
{
|
||||||
int src_is_fd = src->flags & FUSE_BUF_IS_FD;
|
int src_is_fd = src->flags & FUSE_BUF_IS_FD;
|
||||||
int dst_is_fd = dst->flags & FUSE_BUF_IS_FD;
|
int dst_is_fd = dst->flags & FUSE_BUF_IS_FD;
|
||||||
|
|
||||||
if (!src_is_fd && !dst_is_fd) {
|
if (!src_is_fd && !dst_is_fd) {
|
||||||
char *dstmem = dst->mem + dst_off;
|
char *dstmem = dst->mem + dst_off;
|
||||||
char *srcmem = src->mem + src_off;
|
char *srcmem = src->mem + src_off;
|
||||||
|
|
||||||
if (dstmem != srcmem) {
|
if (dstmem != srcmem) {
|
||||||
if (dstmem + len <= srcmem || srcmem + len <= dstmem)
|
if (dstmem + len <= srcmem || srcmem + len <= dstmem)
|
||||||
memcpy(dstmem, srcmem, len);
|
memcpy(dstmem, srcmem, len);
|
||||||
else
|
else
|
||||||
memmove(dstmem, srcmem, len);
|
memmove(dstmem, srcmem, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
} else if (!src_is_fd) {
|
} else if (!src_is_fd) {
|
||||||
return fuse_buf_write(dst, dst_off, src, src_off, len);
|
return fuse_buf_write(dst, dst_off, src, src_off, len);
|
||||||
} else if (!dst_is_fd) {
|
} else if (!dst_is_fd) {
|
||||||
return fuse_buf_read(dst, dst_off, src, src_off, len);
|
return fuse_buf_read(dst, dst_off, src, src_off, len);
|
||||||
} else if (flags & FUSE_BUF_NO_SPLICE) {
|
} else if (flags & FUSE_BUF_NO_SPLICE) {
|
||||||
return fuse_buf_fd_to_fd(dst, dst_off, src, src_off, len);
|
return fuse_buf_fd_to_fd(dst, dst_off, src, src_off, len);
|
||||||
} else {
|
} else {
|
||||||
return fuse_buf_splice(dst, dst_off, src, src_off, len, flags);
|
return fuse_buf_splice(dst, dst_off, src, src_off, len, flags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct fuse_buf *fuse_bufvec_current(struct fuse_bufvec *bufv)
|
static const struct fuse_buf *fuse_bufvec_current(struct fuse_bufvec *bufv)
|
||||||
{
|
{
|
||||||
if (bufv->idx < bufv->count)
|
if (bufv->idx < bufv->count)
|
||||||
return &bufv->buf[bufv->idx];
|
return &bufv->buf[bufv->idx];
|
||||||
else
|
else
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fuse_bufvec_advance(struct fuse_bufvec *bufv, size_t len)
|
static int fuse_bufvec_advance(struct fuse_bufvec *bufv, size_t len)
|
||||||
{
|
{
|
||||||
const struct fuse_buf *buf = fuse_bufvec_current(bufv);
|
const struct fuse_buf *buf = fuse_bufvec_current(bufv);
|
||||||
|
|
||||||
bufv->off += len;
|
bufv->off += len;
|
||||||
assert(bufv->off <= buf->size);
|
assert(bufv->off <= buf->size);
|
||||||
if (bufv->off == buf->size) {
|
if (bufv->off == buf->size) {
|
||||||
assert(bufv->idx < bufv->count);
|
assert(bufv->idx < bufv->count);
|
||||||
bufv->idx++;
|
bufv->idx++;
|
||||||
if (bufv->idx == bufv->count)
|
if (bufv->idx == bufv->count)
|
||||||
return 0;
|
return 0;
|
||||||
bufv->off = 0;
|
bufv->off = 0;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t fuse_buf_copy(struct fuse_bufvec *dstv, struct fuse_bufvec *srcv,
|
ssize_t fuse_buf_copy(struct fuse_bufvec *dstv, struct fuse_bufvec *srcv,
|
||||||
enum fuse_buf_copy_flags flags)
|
enum fuse_buf_copy_flags flags)
|
||||||
{
|
{
|
||||||
size_t copied = 0;
|
size_t copied = 0;
|
||||||
|
|
||||||
if (dstv == srcv)
|
if (dstv == srcv)
|
||||||
return fuse_buf_size(dstv);
|
return fuse_buf_size(dstv);
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
const struct fuse_buf *src = fuse_bufvec_current(srcv);
|
const struct fuse_buf *src = fuse_bufvec_current(srcv);
|
||||||
const struct fuse_buf *dst = fuse_bufvec_current(dstv);
|
const struct fuse_buf *dst = fuse_bufvec_current(dstv);
|
||||||
size_t src_len;
|
size_t src_len;
|
||||||
size_t dst_len;
|
size_t dst_len;
|
||||||
size_t len;
|
size_t len;
|
||||||
ssize_t res;
|
ssize_t res;
|
||||||
|
|
||||||
if (src == NULL || dst == NULL)
|
if (src == NULL || dst == NULL)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
src_len = src->size - srcv->off;
|
src_len = src->size - srcv->off;
|
||||||
dst_len = dst->size - dstv->off;
|
dst_len = dst->size - dstv->off;
|
||||||
len = min_size(src_len, dst_len);
|
len = min_size(src_len, dst_len);
|
||||||
|
|
||||||
res = fuse_buf_copy_one(dst, dstv->off, src, srcv->off, len, flags);
|
res = fuse_buf_copy_one(dst, dstv->off, src, srcv->off, len, flags);
|
||||||
if (res < 0) {
|
if (res < 0) {
|
||||||
if (!copied)
|
if (!copied)
|
||||||
return res;
|
return res;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
copied += res;
|
copied += res;
|
||||||
|
|
||||||
if (!fuse_bufvec_advance(srcv, res) ||
|
if (!fuse_bufvec_advance(srcv, res) ||
|
||||||
!fuse_bufvec_advance(dstv, res))
|
!fuse_bufvec_advance(dstv, res))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (res < len)
|
if (res < len)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return copied;
|
return copied;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,371 +0,0 @@
|
|||||||
/*
|
|
||||||
CUSE: Character device in Userspace
|
|
||||||
Copyright (C) 2008 SUSE Linux Products GmbH
|
|
||||||
Copyright (C) 2008 Tejun Heo <teheo@suse.de>
|
|
||||||
|
|
||||||
This program can be distributed under the terms of the GNU LGPLv2.
|
|
||||||
See the file COPYING.LIB.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "cuse_lowlevel.h"
|
|
||||||
#include "fuse_kernel.h"
|
|
||||||
#include "fuse_i.h"
|
|
||||||
#include "fuse_opt.h"
|
|
||||||
#include "fuse_misc.h"
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
struct cuse_data {
|
|
||||||
struct cuse_lowlevel_ops clop;
|
|
||||||
unsigned max_read;
|
|
||||||
unsigned dev_major;
|
|
||||||
unsigned dev_minor;
|
|
||||||
unsigned flags;
|
|
||||||
unsigned dev_info_len;
|
|
||||||
char dev_info[];
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct cuse_lowlevel_ops *req_clop(fuse_req_t req)
|
|
||||||
{
|
|
||||||
return &req->f->cuse_data->clop;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void cuse_fll_open(fuse_req_t req, fuse_ino_t ino,
|
|
||||||
struct fuse_file_info *fi)
|
|
||||||
{
|
|
||||||
(void)ino;
|
|
||||||
req_clop(req)->open(req, fi);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void cuse_fll_read(fuse_req_t req, fuse_ino_t ino, size_t size,
|
|
||||||
off_t off, struct fuse_file_info *fi)
|
|
||||||
{
|
|
||||||
(void)ino;
|
|
||||||
req_clop(req)->read(req, size, off, fi);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void cuse_fll_write(fuse_req_t req, fuse_ino_t ino, const char *buf,
|
|
||||||
size_t size, off_t off, struct fuse_file_info *fi)
|
|
||||||
{
|
|
||||||
(void)ino;
|
|
||||||
req_clop(req)->write(req, buf, size, off, fi);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void cuse_fll_flush(fuse_req_t req, fuse_ino_t ino,
|
|
||||||
struct fuse_file_info *fi)
|
|
||||||
{
|
|
||||||
(void)ino;
|
|
||||||
req_clop(req)->flush(req, fi);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void cuse_fll_release(fuse_req_t req, fuse_ino_t ino,
|
|
||||||
struct fuse_file_info *fi)
|
|
||||||
{
|
|
||||||
(void)ino;
|
|
||||||
req_clop(req)->release(req, fi);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void cuse_fll_fsync(fuse_req_t req, fuse_ino_t ino, int datasync,
|
|
||||||
struct fuse_file_info *fi)
|
|
||||||
{
|
|
||||||
(void)ino;
|
|
||||||
req_clop(req)->fsync(req, datasync, fi);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void cuse_fll_ioctl(fuse_req_t req, fuse_ino_t ino, int cmd, void *arg,
|
|
||||||
struct fuse_file_info *fi, unsigned int flags,
|
|
||||||
const void *in_buf, size_t in_bufsz, size_t out_bufsz)
|
|
||||||
{
|
|
||||||
(void)ino;
|
|
||||||
req_clop(req)->ioctl(req, cmd, arg, fi, flags, in_buf, in_bufsz,
|
|
||||||
out_bufsz);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void cuse_fll_poll(fuse_req_t req, fuse_ino_t ino,
|
|
||||||
struct fuse_file_info *fi, struct fuse_pollhandle *ph)
|
|
||||||
{
|
|
||||||
(void)ino;
|
|
||||||
req_clop(req)->poll(req, fi, ph);
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t cuse_pack_info(int argc, const char **argv, char *buf)
|
|
||||||
{
|
|
||||||
size_t size = 0;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < argc; i++) {
|
|
||||||
size_t len;
|
|
||||||
|
|
||||||
len = strlen(argv[i]) + 1;
|
|
||||||
size += len;
|
|
||||||
if (buf) {
|
|
||||||
memcpy(buf, argv[i], len);
|
|
||||||
buf += len;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct cuse_data *cuse_prep_data(const struct cuse_info *ci,
|
|
||||||
const struct cuse_lowlevel_ops *clop)
|
|
||||||
{
|
|
||||||
struct cuse_data *cd;
|
|
||||||
size_t dev_info_len;
|
|
||||||
|
|
||||||
dev_info_len = cuse_pack_info(ci->dev_info_argc, ci->dev_info_argv,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
if (dev_info_len > CUSE_INIT_INFO_MAX) {
|
|
||||||
fprintf(stderr, "cuse: dev_info (%zu) too large, limit=%u\n",
|
|
||||||
dev_info_len, CUSE_INIT_INFO_MAX);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
cd = calloc(1, sizeof(*cd) + dev_info_len);
|
|
||||||
if (!cd) {
|
|
||||||
fprintf(stderr, "cuse: failed to allocate cuse_data\n");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(&cd->clop, clop, sizeof(cd->clop));
|
|
||||||
cd->max_read = 131072;
|
|
||||||
cd->dev_major = ci->dev_major;
|
|
||||||
cd->dev_minor = ci->dev_minor;
|
|
||||||
cd->dev_info_len = dev_info_len;
|
|
||||||
cd->flags = ci->flags;
|
|
||||||
cuse_pack_info(ci->dev_info_argc, ci->dev_info_argv, cd->dev_info);
|
|
||||||
|
|
||||||
return cd;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct fuse_session *cuse_lowlevel_new(struct fuse_args *args,
|
|
||||||
const struct cuse_info *ci,
|
|
||||||
const struct cuse_lowlevel_ops *clop,
|
|
||||||
void *userdata)
|
|
||||||
{
|
|
||||||
struct fuse_lowlevel_ops lop;
|
|
||||||
struct cuse_data *cd;
|
|
||||||
struct fuse_session *se;
|
|
||||||
struct fuse_ll *ll;
|
|
||||||
|
|
||||||
cd = cuse_prep_data(ci, clop);
|
|
||||||
if (!cd)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
memset(&lop, 0, sizeof(lop));
|
|
||||||
lop.init = clop->init;
|
|
||||||
lop.destroy = clop->destroy;
|
|
||||||
lop.open = clop->open ? cuse_fll_open : NULL;
|
|
||||||
lop.read = clop->read ? cuse_fll_read : NULL;
|
|
||||||
lop.write = clop->write ? cuse_fll_write : NULL;
|
|
||||||
lop.flush = clop->flush ? cuse_fll_flush : NULL;
|
|
||||||
lop.release = clop->release ? cuse_fll_release : NULL;
|
|
||||||
lop.fsync = clop->fsync ? cuse_fll_fsync : NULL;
|
|
||||||
lop.ioctl = clop->ioctl ? cuse_fll_ioctl : NULL;
|
|
||||||
lop.poll = clop->poll ? cuse_fll_poll : NULL;
|
|
||||||
|
|
||||||
se = fuse_lowlevel_new_common(args, &lop, sizeof(lop), userdata);
|
|
||||||
if (!se) {
|
|
||||||
free(cd);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
ll = se->data;
|
|
||||||
ll->cuse_data = cd;
|
|
||||||
|
|
||||||
return se;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cuse_reply_init(fuse_req_t req, struct cuse_init_out *arg,
|
|
||||||
char *dev_info, unsigned dev_info_len)
|
|
||||||
{
|
|
||||||
struct iovec iov[3];
|
|
||||||
|
|
||||||
iov[1].iov_base = arg;
|
|
||||||
iov[1].iov_len = sizeof(struct cuse_init_out);
|
|
||||||
iov[2].iov_base = dev_info;
|
|
||||||
iov[2].iov_len = dev_info_len;
|
|
||||||
|
|
||||||
return fuse_send_reply_iov_nofree(req, 0, iov, 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cuse_lowlevel_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
|
|
||||||
{
|
|
||||||
struct fuse_init_in *arg = (struct fuse_init_in *) inarg;
|
|
||||||
struct cuse_init_out outarg;
|
|
||||||
struct fuse_ll *f = req->f;
|
|
||||||
struct cuse_data *cd = f->cuse_data;
|
|
||||||
size_t bufsize = fuse_chan_bufsize(req->ch);
|
|
||||||
struct cuse_lowlevel_ops *clop = req_clop(req);
|
|
||||||
|
|
||||||
(void) nodeid;
|
|
||||||
if (f->debug) {
|
|
||||||
fprintf(stderr, "CUSE_INIT: %u.%u\n", arg->major, arg->minor);
|
|
||||||
fprintf(stderr, "flags=0x%08x\n", arg->flags);
|
|
||||||
}
|
|
||||||
f->conn.proto_major = arg->major;
|
|
||||||
f->conn.proto_minor = arg->minor;
|
|
||||||
f->conn.capable = 0;
|
|
||||||
f->conn.want = 0;
|
|
||||||
|
|
||||||
if (arg->major < 7) {
|
|
||||||
fprintf(stderr, "cuse: unsupported protocol version: %u.%u\n",
|
|
||||||
arg->major, arg->minor);
|
|
||||||
fuse_reply_err(req, EPROTO);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bufsize < FUSE_MIN_READ_BUFFER) {
|
|
||||||
fprintf(stderr, "cuse: warning: buffer size too small: %zu\n",
|
|
||||||
bufsize);
|
|
||||||
bufsize = FUSE_MIN_READ_BUFFER;
|
|
||||||
}
|
|
||||||
|
|
||||||
bufsize -= 4096;
|
|
||||||
if (bufsize < f->conn.max_write)
|
|
||||||
f->conn.max_write = bufsize;
|
|
||||||
|
|
||||||
f->got_init = 1;
|
|
||||||
if (f->op.init)
|
|
||||||
f->op.init(f->userdata, &f->conn);
|
|
||||||
|
|
||||||
memset(&outarg, 0, sizeof(outarg));
|
|
||||||
outarg.major = FUSE_KERNEL_VERSION;
|
|
||||||
outarg.minor = FUSE_KERNEL_MINOR_VERSION;
|
|
||||||
outarg.flags = cd->flags;
|
|
||||||
outarg.max_read = cd->max_read;
|
|
||||||
outarg.max_write = f->conn.max_write;
|
|
||||||
outarg.dev_major = cd->dev_major;
|
|
||||||
outarg.dev_minor = cd->dev_minor;
|
|
||||||
|
|
||||||
if (f->debug) {
|
|
||||||
fprintf(stderr, " CUSE_INIT: %u.%u\n",
|
|
||||||
outarg.major, outarg.minor);
|
|
||||||
fprintf(stderr, " flags=0x%08x\n", outarg.flags);
|
|
||||||
fprintf(stderr, " max_read=0x%08x\n", outarg.max_read);
|
|
||||||
fprintf(stderr, " max_write=0x%08x\n", outarg.max_write);
|
|
||||||
fprintf(stderr, " dev_major=%u\n", outarg.dev_major);
|
|
||||||
fprintf(stderr, " dev_minor=%u\n", outarg.dev_minor);
|
|
||||||
fprintf(stderr, " dev_info: %.*s\n", cd->dev_info_len,
|
|
||||||
cd->dev_info);
|
|
||||||
}
|
|
||||||
|
|
||||||
cuse_reply_init(req, &outarg, cd->dev_info, cd->dev_info_len);
|
|
||||||
|
|
||||||
if (clop->init_done)
|
|
||||||
clop->init_done(f->userdata);
|
|
||||||
|
|
||||||
fuse_free_req(req);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct fuse_session *cuse_lowlevel_setup(int argc, char *argv[],
|
|
||||||
const struct cuse_info *ci,
|
|
||||||
const struct cuse_lowlevel_ops *clop,
|
|
||||||
int *multithreaded, void *userdata)
|
|
||||||
{
|
|
||||||
const char *devname = "/dev/cuse";
|
|
||||||
static const struct fuse_opt kill_subtype_opts[] = {
|
|
||||||
FUSE_OPT_KEY("subtype=", FUSE_OPT_KEY_DISCARD),
|
|
||||||
FUSE_OPT_END
|
|
||||||
};
|
|
||||||
struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
|
|
||||||
struct fuse_session *se;
|
|
||||||
struct fuse_chan *ch;
|
|
||||||
int fd;
|
|
||||||
int foreground;
|
|
||||||
int res;
|
|
||||||
|
|
||||||
res = fuse_parse_cmdline(&args, NULL, multithreaded, &foreground);
|
|
||||||
if (res == -1)
|
|
||||||
goto err_args;
|
|
||||||
|
|
||||||
res = fuse_opt_parse(&args, NULL, kill_subtype_opts, NULL);
|
|
||||||
if (res == -1)
|
|
||||||
goto err_args;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Make sure file descriptors 0, 1 and 2 are open, otherwise chaos
|
|
||||||
* would ensue.
|
|
||||||
*/
|
|
||||||
do {
|
|
||||||
fd = open("/dev/null", O_RDWR);
|
|
||||||
if (fd > 2)
|
|
||||||
close(fd);
|
|
||||||
} while (fd >= 0 && fd <= 2);
|
|
||||||
|
|
||||||
se = cuse_lowlevel_new(&args, ci, clop, userdata);
|
|
||||||
fuse_opt_free_args(&args);
|
|
||||||
if (se == NULL)
|
|
||||||
goto err_args;
|
|
||||||
|
|
||||||
fd = open(devname, O_RDWR);
|
|
||||||
if (fd == -1) {
|
|
||||||
if (errno == ENODEV || errno == ENOENT)
|
|
||||||
fprintf(stderr, "cuse: device not found, try 'modprobe cuse' first\n");
|
|
||||||
else
|
|
||||||
fprintf(stderr, "cuse: failed to open %s: %s\n",
|
|
||||||
devname, strerror(errno));
|
|
||||||
goto err_se;
|
|
||||||
}
|
|
||||||
|
|
||||||
ch = fuse_kern_chan_new(fd);
|
|
||||||
if (!ch) {
|
|
||||||
close(fd);
|
|
||||||
goto err_se;
|
|
||||||
}
|
|
||||||
|
|
||||||
fuse_session_add_chan(se, ch);
|
|
||||||
|
|
||||||
res = fuse_set_signal_handlers(se);
|
|
||||||
if (res == -1)
|
|
||||||
goto err_se;
|
|
||||||
|
|
||||||
res = fuse_daemonize(foreground);
|
|
||||||
if (res == -1)
|
|
||||||
goto err_sig;
|
|
||||||
|
|
||||||
return se;
|
|
||||||
|
|
||||||
err_sig:
|
|
||||||
fuse_remove_signal_handlers(se);
|
|
||||||
err_se:
|
|
||||||
fuse_session_destroy(se);
|
|
||||||
err_args:
|
|
||||||
fuse_opt_free_args(&args);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void cuse_lowlevel_teardown(struct fuse_session *se)
|
|
||||||
{
|
|
||||||
fuse_remove_signal_handlers(se);
|
|
||||||
fuse_session_destroy(se);
|
|
||||||
}
|
|
||||||
|
|
||||||
int cuse_lowlevel_main(int argc, char *argv[], const struct cuse_info *ci,
|
|
||||||
const struct cuse_lowlevel_ops *clop, void *userdata)
|
|
||||||
{
|
|
||||||
struct fuse_session *se;
|
|
||||||
int multithreaded;
|
|
||||||
int res;
|
|
||||||
|
|
||||||
se = cuse_lowlevel_setup(argc, argv, ci, clop, &multithreaded,
|
|
||||||
userdata);
|
|
||||||
if (se == NULL)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
if (multithreaded)
|
|
||||||
res = fuse_session_loop_mt(se, 0);
|
|
||||||
else
|
|
||||||
res = fuse_session_loop(se);
|
|
||||||
|
|
||||||
cuse_lowlevel_teardown(se);
|
|
||||||
if (res == -1)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
+2384
-2722
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,425 @@
|
|||||||
|
#define _GNU_SOURCE
|
||||||
|
|
||||||
|
#include "fuse_chan.h"
|
||||||
|
#include "fuse_lowlevel.h"
|
||||||
|
#include "fuse_kernel.h"
|
||||||
|
#include "sys.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
static const char DEV_FUSE[] = "/dev/fuse";
|
||||||
|
|
||||||
|
static
|
||||||
|
void*
|
||||||
|
aligned_mem(const uint64_t size_)
|
||||||
|
{
|
||||||
|
int rv;
|
||||||
|
void *mem;
|
||||||
|
int pagesize;
|
||||||
|
|
||||||
|
pagesize = sys_get_pagesize();
|
||||||
|
|
||||||
|
rv = posix_memalign(&mem,pagesize,size_);
|
||||||
|
if(rv == 0)
|
||||||
|
return mem;
|
||||||
|
|
||||||
|
errno = rv;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int
|
||||||
|
clone_devfuse_fd(const int devfuse_fd_)
|
||||||
|
{
|
||||||
|
#ifdef FUSE_DEV_IOC_CLONE
|
||||||
|
int rv;
|
||||||
|
int clone_fd;
|
||||||
|
|
||||||
|
clone_fd = open(DEV_FUSE,O_RDWR|O_CLOEXEC);
|
||||||
|
if(clone_fd == -1)
|
||||||
|
return devfuse_fd_;
|
||||||
|
|
||||||
|
rv = ioctl(clone_fd,FUSE_DEV_IOC_CLONE,&devfuse_fd_);
|
||||||
|
if(rv == -1)
|
||||||
|
{
|
||||||
|
perror("fuse: failed to clone /dev/fuse");
|
||||||
|
close(clone_fd);
|
||||||
|
return devfuse_fd_;
|
||||||
|
}
|
||||||
|
|
||||||
|
return clone_fd;
|
||||||
|
#else
|
||||||
|
return dup(devfuse_fd_);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
fuse_msg_bufsize(void)
|
||||||
|
{
|
||||||
|
int bufsize;
|
||||||
|
|
||||||
|
bufsize = ((FUSE_MSG_MAX_PAGES + 1) * sys_get_pagesize());
|
||||||
|
|
||||||
|
return bufsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
fuse_chan_t*
|
||||||
|
fuse_chan_new(int32_t devfuse_fd_,
|
||||||
|
uint32_t flags_)
|
||||||
|
{
|
||||||
|
int rv;
|
||||||
|
int bufsize;
|
||||||
|
fuse_chan_t *ch;
|
||||||
|
|
||||||
|
ch = (fuse_chan_t*)calloc(1,sizeof(fuse_chan_t));
|
||||||
|
if(ch == NULL)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "fuse: failed to allocate channel memory\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bufsize = fuse_msg_bufsize();
|
||||||
|
ch->fd = clone_devfuse_fd(devfuse_fd_);
|
||||||
|
ch->buf = aligned_mem(bufsize);
|
||||||
|
ch->bufsize = bufsize;
|
||||||
|
ch->flags = flags_;
|
||||||
|
if(flags_ & (FUSE_CHAN_SPLICE_READ|FUSE_CHAN_SPLICE_WRITE))
|
||||||
|
{
|
||||||
|
rv = sys_alloc_pipe(ch->splice_pipe,bufsize);
|
||||||
|
if(rv == -1)
|
||||||
|
ch->flags &= ~(FUSE_CHAN_SPLICE_READ|FUSE_CHAN_SPLICE_WRITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int64_t
|
||||||
|
fuse_chan_recv_splice(fuse_chan_t *ch_,
|
||||||
|
char *buf_,
|
||||||
|
uint64_t size_)
|
||||||
|
{
|
||||||
|
int64_t rv;
|
||||||
|
struct iovec iov;
|
||||||
|
|
||||||
|
restart_splice:
|
||||||
|
rv = splice(ch_->fd,NULL,ch_->splice_pipe[1],NULL,size_,SPLICE_F_MOVE);
|
||||||
|
switch((rv == -1) ? errno : 0)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
case ENOENT:
|
||||||
|
case EINTR:
|
||||||
|
case EAGAIN:
|
||||||
|
goto restart_splice;
|
||||||
|
case ENODEV:
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
iov.iov_base = buf_;
|
||||||
|
iov.iov_len = rv;
|
||||||
|
restart_vmsplice:
|
||||||
|
rv = vmsplice(ch_->splice_pipe[0],&iov,1,SPLICE_F_MOVE);
|
||||||
|
switch((rv == -1) ? errno : 0)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
case ENOENT:
|
||||||
|
case EINTR:
|
||||||
|
case EAGAIN:
|
||||||
|
goto restart_vmsplice;
|
||||||
|
case ENODEV:
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int
|
||||||
|
fuse_chan_recv_read(fuse_chan_t *ch_,
|
||||||
|
char *buf_,
|
||||||
|
uint64_t size_)
|
||||||
|
{
|
||||||
|
int64_t rv;
|
||||||
|
|
||||||
|
restart:
|
||||||
|
rv = read(ch_->fd,buf_,size_);
|
||||||
|
switch((rv == -1) ? errno : 0)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
case ENOENT:
|
||||||
|
case EINTR:
|
||||||
|
case EAGAIN:
|
||||||
|
goto restart;
|
||||||
|
case ENODEV:
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(rv < sizeof(struct fuse_in_header))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "fuse: short read on fuse device\n");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t
|
||||||
|
fuse_chan_recv(fuse_chan_t *ch_,
|
||||||
|
char *buf_,
|
||||||
|
size_t size_)
|
||||||
|
{
|
||||||
|
if(ch_->flags & FUSE_CHAN_SPLICE_READ)
|
||||||
|
return fuse_chan_recv_splice(ch_,buf_,size_);
|
||||||
|
return fuse_chan_recv_read(ch_,buf_,size_);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int64_t
|
||||||
|
fuse_chan_send_write(fuse_chan_t *ch_,
|
||||||
|
const struct iovec iov_[],
|
||||||
|
size_t count_)
|
||||||
|
{
|
||||||
|
int64_t rv;
|
||||||
|
|
||||||
|
if(iov_ == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
rv = writev(ch_->fd,iov_,count_);
|
||||||
|
if(rv == -1)
|
||||||
|
return -errno;
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int64_t
|
||||||
|
fuse_chan_send_splice(fuse_chan_t *ch_,
|
||||||
|
const struct iovec iov_[],
|
||||||
|
size_t count_)
|
||||||
|
{
|
||||||
|
int64_t rv;
|
||||||
|
|
||||||
|
rv = vmsplice(ch_->splice_pipe[1],iov_,count_,SPLICE_F_MOVE);
|
||||||
|
if(rv == -1)
|
||||||
|
return -errno;
|
||||||
|
|
||||||
|
rv = splice(ch_->splice_pipe[0],NULL,ch_->fd,NULL,rv,SPLICE_F_MOVE);
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t
|
||||||
|
fuse_chan_send(fuse_chan_t *ch,
|
||||||
|
const struct iovec iov[],
|
||||||
|
size_t count)
|
||||||
|
{
|
||||||
|
if(ch->flags & FUSE_CHAN_SPLICE_WRITE)
|
||||||
|
return fuse_chan_send_splice(ch,iov,count);
|
||||||
|
return fuse_chan_send_write(ch,iov,count);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int
|
||||||
|
retryable_error(const int errno_)
|
||||||
|
{
|
||||||
|
switch(errno_)
|
||||||
|
{
|
||||||
|
case EINTR:
|
||||||
|
case EAGAIN:
|
||||||
|
return 1;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int
|
||||||
|
retry_error(const int rv_,
|
||||||
|
const int errno_)
|
||||||
|
{
|
||||||
|
if(rv_ == -1)
|
||||||
|
return retryable_error(errno_);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int64_t
|
||||||
|
writen(const int fd_,
|
||||||
|
void *buf_,
|
||||||
|
const uint64_t count_)
|
||||||
|
{
|
||||||
|
char *buf;
|
||||||
|
uint64_t n_left;
|
||||||
|
int64_t n_written;
|
||||||
|
|
||||||
|
buf = buf_;
|
||||||
|
n_left = count_;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
n_written = write(fd_,buf,n_left);
|
||||||
|
if(retry_error(n_written,errno))
|
||||||
|
continue;
|
||||||
|
if(n_written == -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
n_left -= n_written;
|
||||||
|
buf += n_written;
|
||||||
|
}
|
||||||
|
while(n_left > 0);
|
||||||
|
|
||||||
|
return count_;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int64_t
|
||||||
|
readn(const int fd_,
|
||||||
|
char *buf_,
|
||||||
|
const uint64_t count_)
|
||||||
|
{
|
||||||
|
uint64_t n_left;
|
||||||
|
int64_t n_read;
|
||||||
|
|
||||||
|
n_left = count_;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
n_read = read(fd_,buf_,n_left);
|
||||||
|
if(n_read == 0)
|
||||||
|
return 0;
|
||||||
|
if(retry_error(n_read,errno))
|
||||||
|
continue;
|
||||||
|
if(n_read == -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
n_left -= n_read;
|
||||||
|
}
|
||||||
|
while(n_left > 0);
|
||||||
|
|
||||||
|
return count_;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int64_t
|
||||||
|
splicen_seek(const int fd_in_,
|
||||||
|
const loff_t off_in_,
|
||||||
|
const int fd_out_,
|
||||||
|
const uint64_t len_)
|
||||||
|
{
|
||||||
|
uint64_t n_left;
|
||||||
|
int64_t n_written;
|
||||||
|
loff_t off_in;
|
||||||
|
|
||||||
|
n_left = len_;
|
||||||
|
off_in = off_in_;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
n_written = splice(fd_in_,&off_in,fd_out_,NULL,n_left,SPLICE_F_MOVE);
|
||||||
|
if(retry_error(n_written,errno))
|
||||||
|
continue;
|
||||||
|
if(n_written == -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
n_left -= n_written;
|
||||||
|
off_in += n_written;
|
||||||
|
}
|
||||||
|
while(n_left > 0);
|
||||||
|
|
||||||
|
return len_;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int64_t
|
||||||
|
splicen_noseek(const int fd_in_,
|
||||||
|
const int fd_out_,
|
||||||
|
const uint64_t len_)
|
||||||
|
{
|
||||||
|
uint64_t n_left;
|
||||||
|
int64_t n_written;
|
||||||
|
|
||||||
|
n_left = len_;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
n_written = splice(fd_in_,NULL,fd_out_,NULL,n_left,SPLICE_F_MOVE);
|
||||||
|
if(retry_error(n_written,errno))
|
||||||
|
continue;
|
||||||
|
if(n_written == -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
n_left -= n_written;
|
||||||
|
}
|
||||||
|
while(n_left > 0);
|
||||||
|
|
||||||
|
return len_;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t
|
||||||
|
fuse_chan_send_data_splice(fuse_chan_t *ch_,
|
||||||
|
struct fuse_out_header *hdr_,
|
||||||
|
const int data_fd_,
|
||||||
|
const loff_t data_off_,
|
||||||
|
const int data_len_)
|
||||||
|
{
|
||||||
|
int64_t rv;
|
||||||
|
|
||||||
|
rv = writen(ch_->splice_pipe[1],hdr_,sizeof(struct fuse_out_header));
|
||||||
|
if(rv == -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
rv = splicen_seek(data_fd_,data_off_,ch_->splice_pipe[1],data_len_);
|
||||||
|
if(rv == -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
rv = splicen_noseek(ch_->splice_pipe[0],ch_->fd,(sizeof(struct fuse_out_header)+data_len_));
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t
|
||||||
|
fuse_chan_send_data(fuse_chan_t *ch_,
|
||||||
|
struct fuse_out_header *hdr_,
|
||||||
|
const int data_fd_,
|
||||||
|
const int data_len_)
|
||||||
|
{
|
||||||
|
int64_t rv;
|
||||||
|
char *buf;
|
||||||
|
|
||||||
|
buf = ch_->buf;
|
||||||
|
memcpy(buf,hdr_,sizeof(struct fuse_out_header));
|
||||||
|
rv = readn(data_fd_,
|
||||||
|
&buf[sizeof(struct fuse_out_header)],
|
||||||
|
data_len_);
|
||||||
|
if(rv == -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
rv = write(ch_->fd,buf,(sizeof(struct fuse_out_header) + data_len_));
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
fuse_chan_destroy(fuse_chan_t *ch)
|
||||||
|
{
|
||||||
|
close(ch->fd);
|
||||||
|
if(ch->flags & (FUSE_CHAN_SPLICE_READ|FUSE_CHAN_SPLICE_WRITE))
|
||||||
|
{
|
||||||
|
close(ch->splice_pipe[0]);
|
||||||
|
close(ch->splice_pipe[1]);
|
||||||
|
}
|
||||||
|
free(ch->buf);
|
||||||
|
free(ch);
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
#include "fuse_dev.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/uio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
fuse_dev_t*
|
||||||
|
fuse_dev_alloc(void)
|
||||||
|
{
|
||||||
|
return calloc(1,sizeof(fuse_dev_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
fuse_dev_free(fuse_dev_t *fd_)
|
||||||
|
{
|
||||||
|
if(fd_)
|
||||||
|
free(fd_);
|
||||||
|
}
|
||||||
|
|
||||||
|
fuse_dev_t*
|
||||||
|
fuse_dev_clone(fuse_dev_t *fd_)
|
||||||
|
{
|
||||||
|
return fd_;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t
|
||||||
|
fuse_dev_read(const fuse_dev_t *fd_,
|
||||||
|
void *buf_,
|
||||||
|
uint64_t count_)
|
||||||
|
{
|
||||||
|
int64_t rv;
|
||||||
|
|
||||||
|
rv = read(fd_->fd,buf_,count_);
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t
|
||||||
|
fuse_dev_write(const fuse_dev_t *fd_,
|
||||||
|
const struct iovec *iov_,
|
||||||
|
int iovcnt_)
|
||||||
|
{
|
||||||
|
int64_t rv;
|
||||||
|
|
||||||
|
rv = writev(fd_->fd,iov_,iovcnt_);
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t
|
||||||
|
fuse_dev_write_splice(const fuse_dev_t* fd_,
|
||||||
|
const struct iovec *iov_,
|
||||||
|
int iovcnt_)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
ISC License
|
||||||
|
|
||||||
|
Copyright (c) 2020, Antonio SJ Musumeci <trapexit@spawn.link>
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <sys/uio.h>
|
||||||
|
|
||||||
|
typedef struct fuse_dev_s fuse_dev_t;
|
||||||
|
struct fuse_dev_s
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
};
|
||||||
|
|
||||||
|
fuse_dev_t* fuse_dev_alloc(void);
|
||||||
|
void fuse_dev_free(fuse_dev_t *fd);
|
||||||
|
fuse_dev_t* fuse_dev_clone(fuse_dev_t *fd);
|
||||||
|
|
||||||
|
int64_t fuse_dev_read(const fuse_dev_t *fd,
|
||||||
|
void *buf,
|
||||||
|
uint64_t count);
|
||||||
|
|
||||||
|
int64_t fuse_dev_write(const fuse_dev_t *fd,
|
||||||
|
const struct iovec *iov,
|
||||||
|
int iovcnt);
|
||||||
+73
-85
@@ -9,104 +9,97 @@
|
|||||||
#include "fuse.h"
|
#include "fuse.h"
|
||||||
#include "fuse_lowlevel.h"
|
#include "fuse_lowlevel.h"
|
||||||
|
|
||||||
struct fuse_chan;
|
typedef struct fuse_chan_t fuse_chan_t;
|
||||||
struct fuse_ll;
|
struct fuse_ll;
|
||||||
|
|
||||||
struct fuse_session {
|
struct fuse_session
|
||||||
struct fuse_session_ops op;
|
{
|
||||||
|
struct fuse_session_ops op;
|
||||||
int (*receive_buf)(struct fuse_session *se, struct fuse_buf *buf,
|
void *data;
|
||||||
struct fuse_chan **chp);
|
volatile int exited;
|
||||||
|
int devfuse_fd;
|
||||||
void (*process_buf)(void *data, const struct fuse_buf *buf,
|
|
||||||
struct fuse_chan *ch);
|
|
||||||
|
|
||||||
void *data;
|
|
||||||
|
|
||||||
volatile int exited;
|
|
||||||
|
|
||||||
struct fuse_chan *ch;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct fuse_req {
|
struct fuse_req
|
||||||
struct fuse_ll *f;
|
{
|
||||||
uint64_t unique;
|
struct fuse_ll *f;
|
||||||
int ctr;
|
uint64_t unique;
|
||||||
pthread_mutex_t lock;
|
int ctr;
|
||||||
struct fuse_ctx ctx;
|
pthread_mutex_t lock;
|
||||||
struct fuse_chan *ch;
|
struct fuse_ctx ctx;
|
||||||
int interrupted;
|
fuse_chan_t *ch;
|
||||||
unsigned int ioctl_64bit : 1;
|
int interrupted;
|
||||||
union {
|
unsigned int ioctl_64bit : 1;
|
||||||
struct {
|
union {
|
||||||
uint64_t unique;
|
struct {
|
||||||
} i;
|
uint64_t unique;
|
||||||
struct {
|
} i;
|
||||||
fuse_interrupt_func_t func;
|
struct {
|
||||||
void *data;
|
fuse_interrupt_func_t func;
|
||||||
} ni;
|
void *data;
|
||||||
} u;
|
} ni;
|
||||||
struct fuse_req *next;
|
} u;
|
||||||
struct fuse_req *prev;
|
struct fuse_req *next;
|
||||||
|
struct fuse_req *prev;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct fuse_notify_req {
|
struct fuse_notify_req
|
||||||
uint64_t unique;
|
{
|
||||||
void (*reply)(struct fuse_notify_req *, fuse_req_t, fuse_ino_t,
|
uint64_t unique;
|
||||||
const void *, const struct fuse_buf *);
|
void (*reply)(struct fuse_notify_req *, fuse_req_t, fuse_ino_t,
|
||||||
struct fuse_notify_req *next;
|
const void *, const struct fuse_buf *);
|
||||||
struct fuse_notify_req *prev;
|
struct fuse_notify_req *next;
|
||||||
|
struct fuse_notify_req *prev;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct fuse_ll {
|
struct fuse_ll
|
||||||
int debug;
|
{
|
||||||
int allow_root;
|
int debug;
|
||||||
int atomic_o_trunc;
|
int allow_root;
|
||||||
int no_remote_posix_lock;
|
int atomic_o_trunc;
|
||||||
int no_remote_flock;
|
int no_remote_posix_lock;
|
||||||
int big_writes;
|
int no_remote_flock;
|
||||||
int splice_write;
|
int big_writes;
|
||||||
int splice_move;
|
int splice_write;
|
||||||
int splice_read;
|
int splice_move;
|
||||||
int no_splice_write;
|
int splice_read;
|
||||||
int no_splice_move;
|
int no_splice_write;
|
||||||
int no_splice_read;
|
int no_splice_move;
|
||||||
struct fuse_lowlevel_ops op;
|
int no_splice_read;
|
||||||
int got_init;
|
struct fuse_lowlevel_ops op;
|
||||||
struct cuse_data *cuse_data;
|
int got_init;
|
||||||
void *userdata;
|
void *userdata;
|
||||||
uid_t owner;
|
uid_t owner;
|
||||||
struct fuse_conn_info conn;
|
struct fuse_conn_info conn;
|
||||||
struct fuse_req list;
|
struct fuse_req list;
|
||||||
struct fuse_req interrupts;
|
struct fuse_req interrupts;
|
||||||
pthread_mutex_t lock;
|
pthread_mutex_t lock;
|
||||||
int got_destroy;
|
int got_destroy;
|
||||||
pthread_key_t pipe_key;
|
pthread_key_t pipe_key;
|
||||||
int broken_splice_nonblock;
|
int broken_splice_nonblock;
|
||||||
uint64_t notify_ctr;
|
uint64_t notify_ctr;
|
||||||
struct fuse_notify_req notify_list;
|
struct fuse_notify_req notify_list;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct fuse_cmd {
|
struct fuse_cmd
|
||||||
char *buf;
|
{
|
||||||
size_t buflen;
|
char *buf;
|
||||||
struct fuse_chan *ch;
|
size_t buflen;
|
||||||
|
fuse_chan_t *ch;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct fuse *fuse_new_common(struct fuse_chan *ch, struct fuse_args *args,
|
struct fuse *fuse_new_common(int devfuse_fd, struct fuse_args *args,
|
||||||
const struct fuse_operations *op,
|
const struct fuse_operations *op,
|
||||||
size_t op_size, void *user_data, int compat);
|
size_t op_size, void *user_data);
|
||||||
|
|
||||||
int fuse_sync_compat_args(struct fuse_args *args);
|
int fuse_sync_compat_args(struct fuse_args *args);
|
||||||
|
|
||||||
struct fuse_chan *fuse_kern_chan_new(int fd);
|
|
||||||
|
|
||||||
struct fuse_session *fuse_lowlevel_new_common(struct fuse_args *args,
|
struct fuse_session *fuse_lowlevel_new_common(struct fuse_args *args,
|
||||||
const struct fuse_lowlevel_ops *op,
|
const struct fuse_lowlevel_ops *op,
|
||||||
size_t op_size, void *userdata);
|
size_t op_size, void *userdata);
|
||||||
|
|
||||||
void fuse_kern_unmount_compat22(const char *mountpoint);
|
void fuse_kern_unmount_compat22(const char *mountpoint);
|
||||||
int fuse_chan_clearfd(struct fuse_chan *ch);
|
int fuse_chan_clearfd(fuse_chan_t *ch);
|
||||||
|
|
||||||
void fuse_kern_unmount(const char *mountpoint, int fd);
|
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 fuse_args *args);
|
||||||
@@ -120,11 +113,6 @@ struct fuse *fuse_setup_common(int argc, char *argv[],
|
|||||||
const struct fuse_operations *op,
|
const struct fuse_operations *op,
|
||||||
size_t op_size,
|
size_t op_size,
|
||||||
char **mountpoint,
|
char **mountpoint,
|
||||||
int *multithreaded,
|
void *user_data);
|
||||||
int *fd,
|
|
||||||
void *user_data,
|
|
||||||
int compat);
|
|
||||||
|
|
||||||
void cuse_lowlevel_init(fuse_req_t req, fuse_ino_t nodeide, const void *inarg);
|
|
||||||
|
|
||||||
int fuse_start_thread(pthread_t *thread_id, void *(*func)(void *), void *arg);
|
int fuse_start_thread(pthread_t *thread_id, void *(*func)(void *), void *arg);
|
||||||
|
|||||||
@@ -1,103 +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 "fuse_lowlevel.h"
|
|
||||||
#include "fuse_kernel.h"
|
|
||||||
#include "fuse_i.h"
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
static int fuse_kern_chan_receive(struct fuse_chan **chp, char *buf,
|
|
||||||
size_t size)
|
|
||||||
{
|
|
||||||
struct fuse_chan *ch = *chp;
|
|
||||||
int err;
|
|
||||||
ssize_t res;
|
|
||||||
struct fuse_session *se = fuse_chan_session(ch);
|
|
||||||
assert(se != NULL);
|
|
||||||
|
|
||||||
restart:
|
|
||||||
res = read(fuse_chan_fd(ch), buf, size);
|
|
||||||
err = errno;
|
|
||||||
|
|
||||||
if (fuse_session_exited(se))
|
|
||||||
return 0;
|
|
||||||
if (res == -1) {
|
|
||||||
/* ENOENT means the operation was interrupted, it's safe
|
|
||||||
to restart */
|
|
||||||
if (err == ENOENT)
|
|
||||||
goto restart;
|
|
||||||
|
|
||||||
if (err == ENODEV) {
|
|
||||||
fuse_session_exit(se);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/* Errors occurring during normal operation: EINTR (read
|
|
||||||
interrupted), EAGAIN (nonblocking I/O), ENODEV (filesystem
|
|
||||||
umounted) */
|
|
||||||
if (err != EINTR && err != EAGAIN)
|
|
||||||
perror("fuse: reading device");
|
|
||||||
return -err;
|
|
||||||
}
|
|
||||||
if ((size_t) res < sizeof(struct fuse_in_header)) {
|
|
||||||
fprintf(stderr, "short read on fuse device\n");
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int fuse_kern_chan_send(struct fuse_chan *ch, const struct iovec iov[],
|
|
||||||
size_t count)
|
|
||||||
{
|
|
||||||
if (iov) {
|
|
||||||
ssize_t res = writev(fuse_chan_fd(ch), 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 */
|
|
||||||
if (!fuse_session_exited(se) && err != ENOENT)
|
|
||||||
perror("fuse: writing device");
|
|
||||||
return -err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void fuse_kern_chan_destroy(struct fuse_chan *ch)
|
|
||||||
{
|
|
||||||
int fd = fuse_chan_fd(ch);
|
|
||||||
|
|
||||||
if (fd != -1)
|
|
||||||
close(fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct fuse_chan *
|
|
||||||
fuse_kern_chan_new(int fd_)
|
|
||||||
{
|
|
||||||
long pagesize;
|
|
||||||
size_t bufsize;
|
|
||||||
struct fuse_chan_ops op =
|
|
||||||
{
|
|
||||||
.receive = fuse_kern_chan_receive,
|
|
||||||
.send = fuse_kern_chan_send,
|
|
||||||
.destroy = fuse_kern_chan_destroy,
|
|
||||||
};
|
|
||||||
|
|
||||||
pagesize = sysconf(_SC_PAGESIZE);
|
|
||||||
|
|
||||||
bufsize = ((FUSE_MAX_MAX_PAGES * pagesize) + 0x1000);
|
|
||||||
|
|
||||||
return fuse_chan_new(&op, fd_, bufsize, NULL);
|
|
||||||
}
|
|
||||||
@@ -1,46 +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 "fuse_lowlevel.h"
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
int fuse_session_loop(struct fuse_session *se)
|
|
||||||
{
|
|
||||||
int res = 0;
|
|
||||||
struct fuse_chan *ch = fuse_session_next_chan(se, NULL);
|
|
||||||
size_t bufsize = fuse_chan_bufsize(ch);
|
|
||||||
char *buf = (char*)calloc(bufsize,1);
|
|
||||||
if (!buf) {
|
|
||||||
fprintf(stderr, "fuse: failed to allocate read buffer\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (!fuse_session_exited(se)) {
|
|
||||||
struct fuse_chan *tmpch = ch;
|
|
||||||
struct fuse_buf fbuf = {
|
|
||||||
.mem = buf,
|
|
||||||
.size = bufsize,
|
|
||||||
};
|
|
||||||
|
|
||||||
res = fuse_session_receive_buf(se, &fbuf, &tmpch);
|
|
||||||
|
|
||||||
if (res == -EINTR)
|
|
||||||
continue;
|
|
||||||
if (res <= 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
fuse_session_process_buf(se, &fbuf, tmpch);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(buf);
|
|
||||||
fuse_session_reset(se);
|
|
||||||
return res < 0 ? -1 : 0;
|
|
||||||
}
|
|
||||||
+176
-153
@@ -6,166 +6,189 @@
|
|||||||
See the file COPYING.LIB.
|
See the file COPYING.LIB.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "fuse_chan.h"
|
||||||
|
#include "fuse_i.h"
|
||||||
|
#include "fuse_kernel.h"
|
||||||
#include "fuse_lowlevel.h"
|
#include "fuse_lowlevel.h"
|
||||||
#include "fuse_misc.h"
|
#include "fuse_misc.h"
|
||||||
#include "fuse_kernel.h"
|
|
||||||
#include "fuse_i.h"
|
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <semaphore.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
|
||||||
#include <signal.h>
|
|
||||||
#include <semaphore.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
/* Environment var controlling the thread stack size */
|
/* Environment var controlling the thread stack size */
|
||||||
#define ENVNAME_THREAD_STACK "FUSE_THREAD_STACK"
|
#define ENVNAME_THREAD_STACK "FUSE_THREAD_STACK"
|
||||||
|
|
||||||
struct fuse_worker {
|
struct fuse_worker
|
||||||
struct fuse_worker *prev;
|
|
||||||
struct fuse_worker *next;
|
|
||||||
pthread_t thread_id;
|
|
||||||
size_t bufsize;
|
|
||||||
char *buf;
|
|
||||||
struct fuse_mt *mt;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct fuse_mt {
|
|
||||||
struct fuse_session *se;
|
|
||||||
struct fuse_chan *prevch;
|
|
||||||
struct fuse_worker main;
|
|
||||||
sem_t finish;
|
|
||||||
int exit;
|
|
||||||
int error;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void list_add_worker(struct fuse_worker *w, struct fuse_worker *next)
|
|
||||||
{
|
{
|
||||||
struct fuse_worker *prev = next->prev;
|
struct fuse_worker *prev;
|
||||||
w->next = next;
|
struct fuse_worker *next;
|
||||||
w->prev = prev;
|
struct fuse_mt *mt;
|
||||||
prev->next = w;
|
pthread_t thread_id;
|
||||||
next->prev = w;
|
fuse_chan_t *ch;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct fuse_mt
|
||||||
|
{
|
||||||
|
struct fuse_session *se;
|
||||||
|
struct fuse_worker main;
|
||||||
|
sem_t finish;
|
||||||
|
int exit;
|
||||||
|
int error;
|
||||||
|
};
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
list_add_worker(struct fuse_worker *w,
|
||||||
|
struct fuse_worker *next)
|
||||||
|
{
|
||||||
|
struct fuse_worker *prev = next->prev;
|
||||||
|
w->next = next;
|
||||||
|
w->prev = prev;
|
||||||
|
prev->next = w;
|
||||||
|
next->prev = w;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void list_del_worker(struct fuse_worker *w)
|
static
|
||||||
|
void
|
||||||
|
list_del_worker(struct fuse_worker *w)
|
||||||
{
|
{
|
||||||
struct fuse_worker *prev = w->prev;
|
struct fuse_worker *prev = w->prev;
|
||||||
struct fuse_worker *next = w->next;
|
struct fuse_worker *next = w->next;
|
||||||
prev->next = next;
|
prev->next = next;
|
||||||
next->prev = prev;
|
next->prev = prev;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fuse_loop_start_thread(struct fuse_mt *mt);
|
static int fuse_loop_start_thread(struct fuse_mt *mt);
|
||||||
|
|
||||||
static void *fuse_do_work(void *data)
|
static
|
||||||
|
void*
|
||||||
|
fuse_do_work(void *data)
|
||||||
{
|
{
|
||||||
struct fuse_worker *w = (struct fuse_worker *) data;
|
struct fuse_mt *mt;
|
||||||
struct fuse_mt *mt = w->mt;
|
fuse_chan_t *ch;
|
||||||
|
struct fuse_worker *w;
|
||||||
|
|
||||||
while (!fuse_session_exited(mt->se)) {
|
w = (struct fuse_worker*)data;
|
||||||
struct fuse_chan *ch = mt->prevch;
|
mt = w->mt;
|
||||||
struct fuse_buf fbuf = {
|
ch = w->ch;
|
||||||
.mem = w->buf,
|
while(!fuse_session_exited(mt->se))
|
||||||
.size = w->bufsize,
|
{
|
||||||
};
|
int res;
|
||||||
int res;
|
struct fuse_buf fbuf = { .mem = ch->buf, .size = ch->bufsize };
|
||||||
|
|
||||||
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
|
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
|
||||||
res = fuse_session_receive_buf(mt->se, &fbuf, &ch);
|
res = fuse_ll_receive_buf(mt->se,&fbuf,ch);
|
||||||
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
|
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
|
||||||
if (res == -EINTR)
|
if(res == -EINTR)
|
||||||
continue;
|
continue;
|
||||||
if (res <= 0) {
|
if(res == 0)
|
||||||
if (res < 0) {
|
break;
|
||||||
fuse_session_exit(mt->se);
|
if(res < 0)
|
||||||
mt->error = -1;
|
{
|
||||||
}
|
fuse_session_exit(mt->se);
|
||||||
break;
|
mt->error = -1;
|
||||||
}
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (mt->exit)
|
if(mt->exit)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
fuse_session_process_buf(mt->se, &fbuf, ch);
|
fuse_ll_process_buf(mt->se->data,&fbuf,ch);
|
||||||
}
|
}
|
||||||
|
|
||||||
sem_post(&mt->finish);
|
sem_post(&mt->finish);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fuse_start_thread(pthread_t *thread_id, void *(*func)(void *), void *arg)
|
int
|
||||||
|
fuse_start_thread(pthread_t *thread_id,
|
||||||
|
void *(*func)(void *),
|
||||||
|
void *arg)
|
||||||
{
|
{
|
||||||
sigset_t oldset;
|
int res;
|
||||||
sigset_t newset;
|
sigset_t oldset;
|
||||||
int res;
|
sigset_t newset;
|
||||||
pthread_attr_t attr;
|
pthread_attr_t attr;
|
||||||
char *stack_size;
|
char *stack_size;
|
||||||
|
|
||||||
/* Override default stack size */
|
/* Override default stack size */
|
||||||
pthread_attr_init(&attr);
|
pthread_attr_init(&attr);
|
||||||
stack_size = getenv(ENVNAME_THREAD_STACK);
|
stack_size = getenv(ENVNAME_THREAD_STACK);
|
||||||
if (stack_size && pthread_attr_setstacksize(&attr, atoi(stack_size)))
|
if(stack_size && pthread_attr_setstacksize(&attr,atoi(stack_size)))
|
||||||
fprintf(stderr, "fuse: invalid stack size: %s\n", stack_size);
|
fprintf(stderr, "fuse: invalid stack size: %s\n", stack_size);
|
||||||
|
|
||||||
/* Disallow signal reception in worker threads */
|
/* Disallow signal reception in worker threads */
|
||||||
sigemptyset(&newset);
|
sigemptyset(&newset);
|
||||||
sigaddset(&newset, SIGTERM);
|
sigaddset(&newset, SIGTERM);
|
||||||
sigaddset(&newset, SIGINT);
|
sigaddset(&newset, SIGINT);
|
||||||
sigaddset(&newset, SIGHUP);
|
sigaddset(&newset, SIGHUP);
|
||||||
sigaddset(&newset, SIGQUIT);
|
sigaddset(&newset, SIGQUIT);
|
||||||
pthread_sigmask(SIG_BLOCK, &newset, &oldset);
|
pthread_sigmask(SIG_BLOCK, &newset, &oldset);
|
||||||
res = pthread_create(thread_id, &attr, func, arg);
|
res = pthread_create(thread_id, &attr, func, arg);
|
||||||
pthread_sigmask(SIG_SETMASK, &oldset, NULL);
|
pthread_sigmask(SIG_SETMASK, &oldset, NULL);
|
||||||
pthread_attr_destroy(&attr);
|
pthread_attr_destroy(&attr);
|
||||||
if (res != 0) {
|
|
||||||
fprintf(stderr, "fuse: error creating thread: %s\n",
|
|
||||||
strerror(res));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
if(res != 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "fuse: error creating thread: %s\n",
|
||||||
|
strerror(res));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fuse_loop_start_thread(struct fuse_mt *mt)
|
static
|
||||||
|
int
|
||||||
|
fuse_loop_start_thread(struct fuse_mt *mt)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
struct fuse_worker *w = malloc(sizeof(struct fuse_worker));
|
struct fuse_worker *w;
|
||||||
if (!w) {
|
|
||||||
fprintf(stderr, "fuse: failed to allocate worker structure\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
memset(w, 0, sizeof(struct fuse_worker));
|
|
||||||
w->bufsize = fuse_chan_bufsize(mt->prevch);
|
|
||||||
w->buf = calloc(w->bufsize,1);
|
|
||||||
w->mt = mt;
|
|
||||||
if (!w->buf) {
|
|
||||||
fprintf(stderr, "fuse: failed to allocate read buffer\n");
|
|
||||||
free(w);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
res = fuse_start_thread(&w->thread_id, fuse_do_work, w);
|
w = malloc(sizeof(struct fuse_worker));
|
||||||
if (res == -1) {
|
if(!w)
|
||||||
free(w->buf);
|
{
|
||||||
free(w);
|
fprintf(stderr, "fuse: failed to allocate worker structure\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
list_add_worker(w, &mt->main);
|
|
||||||
|
|
||||||
return 0;
|
memset(w,0,sizeof(struct fuse_worker));
|
||||||
|
|
||||||
|
w->mt = mt;
|
||||||
|
w->ch = fuse_chan_new(mt->se->devfuse_fd,FUSE_CHAN_SPLICE_READ|FUSE_CHAN_SPLICE_WRITE);
|
||||||
|
if(w->ch == NULL)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "fuse: failed to allocate fuse channel\n");
|
||||||
|
free(w);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = fuse_start_thread(&w->thread_id, fuse_do_work, w);
|
||||||
|
if(res == -1)
|
||||||
|
{
|
||||||
|
free(w);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
list_add_worker(w,&mt->main);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fuse_join_worker(struct fuse_worker *w)
|
static void fuse_join_worker(struct fuse_worker *w)
|
||||||
{
|
{
|
||||||
pthread_join(w->thread_id, NULL);
|
pthread_join(w->thread_id, NULL);
|
||||||
list_del_worker(w);
|
list_del_worker(w);
|
||||||
free(w->buf);
|
fuse_chan_destroy(w->ch);
|
||||||
free(w);
|
free(w);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int number_of_threads(void)
|
static int number_of_threads(void)
|
||||||
@@ -178,48 +201,48 @@ static int number_of_threads(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int fuse_session_loop_mt(struct fuse_session *se,
|
int fuse_session_loop_mt(struct fuse_session *se,
|
||||||
const int _threads)
|
const int threads_)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
int err;
|
int err;
|
||||||
int threads;
|
int threads;
|
||||||
struct fuse_mt mt;
|
struct fuse_mt mt;
|
||||||
struct fuse_worker *w;
|
struct fuse_worker *w;
|
||||||
|
|
||||||
memset(&mt, 0, sizeof(struct fuse_mt));
|
memset(&mt, 0, sizeof(struct fuse_mt));
|
||||||
mt.se = se;
|
mt.se = se;
|
||||||
mt.prevch = fuse_session_next_chan(se, NULL);
|
mt.error = 0;
|
||||||
mt.error = 0;
|
mt.main.thread_id = pthread_self();
|
||||||
mt.main.thread_id = pthread_self();
|
mt.main.prev = mt.main.next = &mt.main;
|
||||||
mt.main.prev = mt.main.next = &mt.main;
|
sem_init(&mt.finish, 0, 0);
|
||||||
sem_init(&mt.finish, 0, 0);
|
|
||||||
|
|
||||||
threads = ((_threads > 0) ? _threads : number_of_threads());
|
threads = ((threads_ > 0) ? threads_ : number_of_threads());
|
||||||
if(_threads < 0)
|
if(threads_ < 0)
|
||||||
threads /= -_threads;
|
threads /= -threads_;
|
||||||
if(threads == 0)
|
if(threads == 0)
|
||||||
threads = 1;
|
threads = 1;
|
||||||
|
|
||||||
err = 0;
|
err = 0;
|
||||||
for(i = 0; (i < threads) && !err; i++)
|
for(i = 0; (i < threads) && !err; i++)
|
||||||
err = fuse_loop_start_thread(&mt);
|
err = fuse_loop_start_thread(&mt);
|
||||||
|
|
||||||
if (!err) {
|
if(!err)
|
||||||
/* sem_wait() is interruptible */
|
{
|
||||||
while (!fuse_session_exited(se))
|
/* sem_wait() is interruptible */
|
||||||
sem_wait(&mt.finish);
|
while(!fuse_session_exited(se))
|
||||||
|
sem_wait(&mt.finish);
|
||||||
|
|
||||||
for (w = mt.main.next; w != &mt.main; w = w->next)
|
for(w = mt.main.next; w != &mt.main; w = w->next)
|
||||||
pthread_cancel(w->thread_id);
|
pthread_cancel(w->thread_id);
|
||||||
mt.exit = 1;
|
mt.exit = 1;
|
||||||
|
|
||||||
while (mt.main.next != &mt.main)
|
while(mt.main.next != &mt.main)
|
||||||
fuse_join_worker(mt.main.next);
|
fuse_join_worker(mt.main.next);
|
||||||
|
|
||||||
err = mt.error;
|
err = mt.error;
|
||||||
}
|
}
|
||||||
|
|
||||||
sem_destroy(&mt.finish);
|
sem_destroy(&mt.finish);
|
||||||
fuse_session_reset(se);
|
fuse_session_reset(se);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|||||||
+1506
-2114
File diff suppressed because it is too large
Load Diff
+9
-101
@@ -16,109 +16,17 @@
|
|||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
struct procdata {
|
|
||||||
struct fuse *f;
|
|
||||||
struct fuse_chan *prevch;
|
|
||||||
struct fuse_session *prevse;
|
|
||||||
fuse_processor_t proc;
|
|
||||||
void *data;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void mt_session_proc(void *data, const char *buf, size_t len,
|
|
||||||
struct fuse_chan *ch)
|
|
||||||
{
|
|
||||||
struct procdata *pd = (struct procdata *) data;
|
|
||||||
struct fuse_cmd *cmd = *(struct fuse_cmd **) buf;
|
|
||||||
|
|
||||||
(void) len;
|
|
||||||
(void) ch;
|
|
||||||
pd->proc(pd->f, cmd, pd->data);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void mt_session_exit(void *data, int val)
|
|
||||||
{
|
|
||||||
struct procdata *pd = (struct procdata *) data;
|
|
||||||
if (val)
|
|
||||||
fuse_session_exit(pd->prevse);
|
|
||||||
else
|
|
||||||
fuse_session_reset(pd->prevse);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int mt_session_exited(void *data)
|
|
||||||
{
|
|
||||||
struct procdata *pd = (struct procdata *) data;
|
|
||||||
return fuse_session_exited(pd->prevse);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int mt_chan_receive(struct fuse_chan **chp, char *buf, size_t size)
|
|
||||||
{
|
|
||||||
struct fuse_cmd *cmd;
|
|
||||||
struct procdata *pd = (struct procdata *) fuse_chan_data(*chp);
|
|
||||||
|
|
||||||
assert(size >= sizeof(cmd));
|
|
||||||
|
|
||||||
cmd = fuse_read_cmd(pd->f);
|
|
||||||
if (cmd == NULL)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
*(struct fuse_cmd **) buf = cmd;
|
|
||||||
|
|
||||||
return sizeof(cmd);
|
|
||||||
}
|
|
||||||
|
|
||||||
int fuse_loop_mt_proc(struct fuse *f, fuse_processor_t proc, void *data)
|
|
||||||
{
|
|
||||||
int res;
|
|
||||||
struct procdata pd;
|
|
||||||
struct fuse_session *prevse = fuse_get_session(f);
|
|
||||||
struct fuse_session *se;
|
|
||||||
struct fuse_chan *prevch = fuse_session_next_chan(prevse, NULL);
|
|
||||||
struct fuse_chan *ch;
|
|
||||||
struct fuse_session_ops sop = {
|
|
||||||
.exit = mt_session_exit,
|
|
||||||
.exited = mt_session_exited,
|
|
||||||
.process = mt_session_proc,
|
|
||||||
};
|
|
||||||
struct fuse_chan_ops cop = {
|
|
||||||
.receive = mt_chan_receive,
|
|
||||||
};
|
|
||||||
|
|
||||||
pd.f = f;
|
|
||||||
pd.prevch = prevch;
|
|
||||||
pd.prevse = prevse;
|
|
||||||
pd.proc = proc;
|
|
||||||
pd.data = data;
|
|
||||||
|
|
||||||
se = fuse_session_new(&sop, &pd);
|
|
||||||
if (se == NULL)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
ch = fuse_chan_new(&cop, fuse_chan_fd(prevch),
|
|
||||||
sizeof(struct fuse_cmd *), &pd);
|
|
||||||
if (ch == NULL) {
|
|
||||||
fuse_session_destroy(se);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
fuse_session_add_chan(se, ch);
|
|
||||||
res = fuse_session_loop_mt(se,
|
|
||||||
fuse_config_num_threads(f));
|
|
||||||
fuse_session_destroy(se);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
int fuse_loop_mt(struct fuse *f)
|
int fuse_loop_mt(struct fuse *f)
|
||||||
{
|
{
|
||||||
if (f == NULL)
|
if (f == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
int res = fuse_start_cleanup_thread(f);
|
int res = fuse_start_cleanup_thread(f);
|
||||||
if (res)
|
if (res)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
res = fuse_session_loop_mt(fuse_get_session(f),
|
res = fuse_session_loop_mt(fuse_get_session(f),
|
||||||
fuse_config_num_threads(f));
|
fuse_config_num_threads(f));
|
||||||
fuse_stop_cleanup_thread(f);
|
fuse_stop_cleanup_thread(f);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
FUSE_SYMVER(".symver fuse_loop_mt_proc,__fuse_loop_mt@");
|
|
||||||
|
|||||||
+267
-267
@@ -15,411 +15,411 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
struct fuse_opt_context {
|
struct fuse_opt_context {
|
||||||
void *data;
|
void *data;
|
||||||
const struct fuse_opt *opt;
|
const struct fuse_opt *opt;
|
||||||
fuse_opt_proc_t proc;
|
fuse_opt_proc_t proc;
|
||||||
int argctr;
|
int argctr;
|
||||||
int argc;
|
int argc;
|
||||||
char **argv;
|
char **argv;
|
||||||
struct fuse_args outargs;
|
struct fuse_args outargs;
|
||||||
char *opts;
|
char *opts;
|
||||||
int nonopt;
|
int nonopt;
|
||||||
};
|
};
|
||||||
|
|
||||||
void fuse_opt_free_args(struct fuse_args *args)
|
void fuse_opt_free_args(struct fuse_args *args)
|
||||||
{
|
{
|
||||||
if (args) {
|
if (args) {
|
||||||
if (args->argv && args->allocated) {
|
if (args->argv && args->allocated) {
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < args->argc; i++)
|
for (i = 0; i < args->argc; i++)
|
||||||
free(args->argv[i]);
|
free(args->argv[i]);
|
||||||
free(args->argv);
|
free(args->argv);
|
||||||
}
|
}
|
||||||
args->argc = 0;
|
args->argc = 0;
|
||||||
args->argv = NULL;
|
args->argv = NULL;
|
||||||
args->allocated = 0;
|
args->allocated = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int alloc_failed(void)
|
static int alloc_failed(void)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "fuse: memory allocation failed\n");
|
fprintf(stderr, "fuse: memory allocation failed\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fuse_opt_add_arg(struct fuse_args *args, const char *arg)
|
int fuse_opt_add_arg(struct fuse_args *args, const char *arg)
|
||||||
{
|
{
|
||||||
char **newargv;
|
char **newargv;
|
||||||
char *newarg;
|
char *newarg;
|
||||||
|
|
||||||
assert(!args->argv || args->allocated);
|
assert(!args->argv || args->allocated);
|
||||||
|
|
||||||
newarg = strdup(arg);
|
newarg = strdup(arg);
|
||||||
if (!newarg)
|
if (!newarg)
|
||||||
return alloc_failed();
|
return alloc_failed();
|
||||||
|
|
||||||
newargv = realloc(args->argv, (args->argc + 2) * sizeof(char *));
|
newargv = realloc(args->argv, (args->argc + 2) * sizeof(char *));
|
||||||
if (!newargv) {
|
if (!newargv) {
|
||||||
free(newarg);
|
free(newarg);
|
||||||
return alloc_failed();
|
return alloc_failed();
|
||||||
}
|
}
|
||||||
|
|
||||||
args->argv = newargv;
|
args->argv = newargv;
|
||||||
args->allocated = 1;
|
args->allocated = 1;
|
||||||
args->argv[args->argc++] = newarg;
|
args->argv[args->argc++] = newarg;
|
||||||
args->argv[args->argc] = NULL;
|
args->argv[args->argc] = NULL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fuse_opt_insert_arg_common(struct fuse_args *args, int pos,
|
static int fuse_opt_insert_arg_common(struct fuse_args *args, int pos,
|
||||||
const char *arg)
|
const char *arg)
|
||||||
{
|
{
|
||||||
assert(pos <= args->argc);
|
assert(pos <= args->argc);
|
||||||
if (fuse_opt_add_arg(args, arg) == -1)
|
if (fuse_opt_add_arg(args, arg) == -1)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (pos != args->argc - 1) {
|
if (pos != args->argc - 1) {
|
||||||
char *newarg = args->argv[args->argc - 1];
|
char *newarg = args->argv[args->argc - 1];
|
||||||
memmove(&args->argv[pos + 1], &args->argv[pos],
|
memmove(&args->argv[pos + 1], &args->argv[pos],
|
||||||
sizeof(char *) * (args->argc - pos - 1));
|
sizeof(char *) * (args->argc - pos - 1));
|
||||||
args->argv[pos] = newarg;
|
args->argv[pos] = newarg;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fuse_opt_insert_arg(struct fuse_args *args, int pos, const char *arg)
|
int fuse_opt_insert_arg(struct fuse_args *args, int pos, const char *arg)
|
||||||
{
|
{
|
||||||
return fuse_opt_insert_arg_common(args, pos, arg);
|
return fuse_opt_insert_arg_common(args, pos, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
int fuse_opt_insert_arg_compat(struct fuse_args *args, int pos,
|
int fuse_opt_insert_arg_compat(struct fuse_args *args, int pos,
|
||||||
const char *arg);
|
const char *arg);
|
||||||
int fuse_opt_insert_arg_compat(struct fuse_args *args, int pos, const char *arg)
|
int fuse_opt_insert_arg_compat(struct fuse_args *args, int pos, const char *arg)
|
||||||
{
|
{
|
||||||
return fuse_opt_insert_arg_common(args, pos, arg);
|
return fuse_opt_insert_arg_common(args, pos, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int next_arg(struct fuse_opt_context *ctx, const char *opt)
|
static int next_arg(struct fuse_opt_context *ctx, const char *opt)
|
||||||
{
|
{
|
||||||
if (ctx->argctr + 1 >= ctx->argc) {
|
if (ctx->argctr + 1 >= ctx->argc) {
|
||||||
fprintf(stderr, "fuse: missing argument after `%s'\n", opt);
|
fprintf(stderr, "fuse: missing argument after `%s'\n", opt);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
ctx->argctr++;
|
ctx->argctr++;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int add_arg(struct fuse_opt_context *ctx, const char *arg)
|
static int add_arg(struct fuse_opt_context *ctx, const char *arg)
|
||||||
{
|
{
|
||||||
return fuse_opt_add_arg(&ctx->outargs, arg);
|
return fuse_opt_add_arg(&ctx->outargs, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int add_opt_common(char **opts, const char *opt, int esc)
|
static int add_opt_common(char **opts, const char *opt, int esc)
|
||||||
{
|
{
|
||||||
unsigned oldlen = *opts ? strlen(*opts) : 0;
|
unsigned oldlen = *opts ? strlen(*opts) : 0;
|
||||||
char *d = realloc(*opts, oldlen + 1 + strlen(opt) * 2 + 1);
|
char *d = realloc(*opts, oldlen + 1 + strlen(opt) * 2 + 1);
|
||||||
|
|
||||||
if (!d)
|
if (!d)
|
||||||
return alloc_failed();
|
return alloc_failed();
|
||||||
|
|
||||||
*opts = d;
|
*opts = d;
|
||||||
if (oldlen) {
|
if (oldlen) {
|
||||||
d += oldlen;
|
d += oldlen;
|
||||||
*d++ = ',';
|
*d++ = ',';
|
||||||
}
|
}
|
||||||
|
|
||||||
for (; *opt; opt++) {
|
for (; *opt; opt++) {
|
||||||
if (esc && (*opt == ',' || *opt == '\\'))
|
if (esc && (*opt == ',' || *opt == '\\'))
|
||||||
*d++ = '\\';
|
*d++ = '\\';
|
||||||
*d++ = *opt;
|
*d++ = *opt;
|
||||||
}
|
}
|
||||||
*d = '\0';
|
*d = '\0';
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fuse_opt_add_opt(char **opts, const char *opt)
|
int fuse_opt_add_opt(char **opts, const char *opt)
|
||||||
{
|
{
|
||||||
return add_opt_common(opts, opt, 0);
|
return add_opt_common(opts, opt, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int fuse_opt_add_opt_escaped(char **opts, const char *opt)
|
int fuse_opt_add_opt_escaped(char **opts, const char *opt)
|
||||||
{
|
{
|
||||||
return add_opt_common(opts, opt, 1);
|
return add_opt_common(opts, opt, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int add_opt(struct fuse_opt_context *ctx, const char *opt)
|
static int add_opt(struct fuse_opt_context *ctx, const char *opt)
|
||||||
{
|
{
|
||||||
return add_opt_common(&ctx->opts, opt, 1);
|
return add_opt_common(&ctx->opts, opt, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int call_proc(struct fuse_opt_context *ctx, const char *arg, int key,
|
static int call_proc(struct fuse_opt_context *ctx, const char *arg, int key,
|
||||||
int iso)
|
int iso)
|
||||||
{
|
{
|
||||||
if (key == FUSE_OPT_KEY_DISCARD)
|
if (key == FUSE_OPT_KEY_DISCARD)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (key != FUSE_OPT_KEY_KEEP && ctx->proc) {
|
if (key != FUSE_OPT_KEY_KEEP && ctx->proc) {
|
||||||
int res = ctx->proc(ctx->data, arg, key, &ctx->outargs);
|
int res = ctx->proc(ctx->data, arg, key, &ctx->outargs);
|
||||||
if (res == -1 || !res)
|
if (res == -1 || !res)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
if (iso)
|
if (iso)
|
||||||
return add_opt(ctx, arg);
|
return add_opt(ctx, arg);
|
||||||
else
|
else
|
||||||
return add_arg(ctx, arg);
|
return add_arg(ctx, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int match_template(const char *t, const char *arg, unsigned *sepp)
|
static int match_template(const char *t, const char *arg, unsigned *sepp)
|
||||||
{
|
{
|
||||||
int arglen = strlen(arg);
|
int arglen = strlen(arg);
|
||||||
const char *sep = strchr(t, '=');
|
const char *sep = strchr(t, '=');
|
||||||
sep = sep ? sep : strchr(t, ' ');
|
sep = sep ? sep : strchr(t, ' ');
|
||||||
if (sep && (!sep[1] || sep[1] == '%')) {
|
if (sep && (!sep[1] || sep[1] == '%')) {
|
||||||
int tlen = sep - t;
|
int tlen = sep - t;
|
||||||
if (sep[0] == '=')
|
if (sep[0] == '=')
|
||||||
tlen ++;
|
tlen ++;
|
||||||
if (arglen >= tlen && strncmp(arg, t, tlen) == 0) {
|
if (arglen >= tlen && strncmp(arg, t, tlen) == 0) {
|
||||||
*sepp = sep - t;
|
*sepp = sep - t;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (strcmp(t, arg) == 0) {
|
if (strcmp(t, arg) == 0) {
|
||||||
*sepp = 0;
|
*sepp = 0;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct fuse_opt *find_opt(const struct fuse_opt *opt,
|
static const struct fuse_opt *find_opt(const struct fuse_opt *opt,
|
||||||
const char *arg, unsigned *sepp)
|
const char *arg, unsigned *sepp)
|
||||||
{
|
{
|
||||||
for (; opt && opt->templ; opt++)
|
for (; opt && opt->templ; opt++)
|
||||||
if (match_template(opt->templ, arg, sepp))
|
if (match_template(opt->templ, arg, sepp))
|
||||||
return opt;
|
return opt;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fuse_opt_match(const struct fuse_opt *opts, const char *opt)
|
int fuse_opt_match(const struct fuse_opt *opts, const char *opt)
|
||||||
{
|
{
|
||||||
unsigned dummy;
|
unsigned dummy;
|
||||||
return find_opt(opts, opt, &dummy) ? 1 : 0;
|
return find_opt(opts, opt, &dummy) ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int process_opt_param(void *var, const char *format, const char *param,
|
static int process_opt_param(void *var, const char *format, const char *param,
|
||||||
const char *arg)
|
const char *arg)
|
||||||
{
|
{
|
||||||
assert(format[0] == '%');
|
assert(format[0] == '%');
|
||||||
if (format[1] == 's') {
|
if (format[1] == 's') {
|
||||||
char *copy = strdup(param);
|
char *copy = strdup(param);
|
||||||
if (!copy)
|
if (!copy)
|
||||||
return alloc_failed();
|
return alloc_failed();
|
||||||
|
|
||||||
*(char **) var = copy;
|
*(char **) var = copy;
|
||||||
} else {
|
} else {
|
||||||
if (sscanf(param, format, var) != 1) {
|
if (sscanf(param, format, var) != 1) {
|
||||||
fprintf(stderr, "fuse: invalid parameter in option `%s'\n", arg);
|
fprintf(stderr, "fuse: invalid parameter in option `%s'\n", arg);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int process_opt(struct fuse_opt_context *ctx,
|
static int process_opt(struct fuse_opt_context *ctx,
|
||||||
const struct fuse_opt *opt, unsigned sep,
|
const struct fuse_opt *opt, unsigned sep,
|
||||||
const char *arg, int iso)
|
const char *arg, int iso)
|
||||||
{
|
{
|
||||||
if (opt->offset == -1U) {
|
if (opt->offset == -1U) {
|
||||||
if (call_proc(ctx, arg, opt->value, iso) == -1)
|
if (call_proc(ctx, arg, opt->value, iso) == -1)
|
||||||
return -1;
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
void *var = ctx->data + opt->offset;
|
void *var = ctx->data + opt->offset;
|
||||||
if (sep && opt->templ[sep + 1]) {
|
if (sep && opt->templ[sep + 1]) {
|
||||||
const char *param = arg + sep;
|
const char *param = arg + sep;
|
||||||
if (opt->templ[sep] == '=')
|
if (opt->templ[sep] == '=')
|
||||||
param ++;
|
param ++;
|
||||||
if (process_opt_param(var, opt->templ + sep + 1,
|
if (process_opt_param(var, opt->templ + sep + 1,
|
||||||
param, arg) == -1)
|
param, arg) == -1)
|
||||||
return -1;
|
return -1;
|
||||||
} else
|
} else
|
||||||
*(int *)var = opt->value;
|
*(int *)var = opt->value;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int process_opt_sep_arg(struct fuse_opt_context *ctx,
|
static int process_opt_sep_arg(struct fuse_opt_context *ctx,
|
||||||
const struct fuse_opt *opt, unsigned sep,
|
const struct fuse_opt *opt, unsigned sep,
|
||||||
const char *arg, int iso)
|
const char *arg, int iso)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
char *newarg;
|
char *newarg;
|
||||||
char *param;
|
char *param;
|
||||||
|
|
||||||
if (next_arg(ctx, arg) == -1)
|
if (next_arg(ctx, arg) == -1)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
param = ctx->argv[ctx->argctr];
|
param = ctx->argv[ctx->argctr];
|
||||||
newarg = malloc(sep + strlen(param) + 1);
|
newarg = malloc(sep + strlen(param) + 1);
|
||||||
if (!newarg)
|
if (!newarg)
|
||||||
return alloc_failed();
|
return alloc_failed();
|
||||||
|
|
||||||
memcpy(newarg, arg, sep);
|
memcpy(newarg, arg, sep);
|
||||||
strcpy(newarg + sep, param);
|
strcpy(newarg + sep, param);
|
||||||
res = process_opt(ctx, opt, sep, newarg, iso);
|
res = process_opt(ctx, opt, sep, newarg, iso);
|
||||||
free(newarg);
|
free(newarg);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int process_gopt(struct fuse_opt_context *ctx, const char *arg, int iso)
|
static int process_gopt(struct fuse_opt_context *ctx, const char *arg, int iso)
|
||||||
{
|
{
|
||||||
unsigned sep;
|
unsigned sep;
|
||||||
const struct fuse_opt *opt = find_opt(ctx->opt, arg, &sep);
|
const struct fuse_opt *opt = find_opt(ctx->opt, arg, &sep);
|
||||||
if (opt) {
|
if (opt) {
|
||||||
for (; opt; opt = find_opt(opt + 1, arg, &sep)) {
|
for (; opt; opt = find_opt(opt + 1, arg, &sep)) {
|
||||||
int res;
|
int res;
|
||||||
if (sep && opt->templ[sep] == ' ' && !arg[sep])
|
if (sep && opt->templ[sep] == ' ' && !arg[sep])
|
||||||
res = process_opt_sep_arg(ctx, opt, sep, arg,
|
res = process_opt_sep_arg(ctx, opt, sep, arg,
|
||||||
iso);
|
iso);
|
||||||
else
|
else
|
||||||
res = process_opt(ctx, opt, sep, arg, iso);
|
res = process_opt(ctx, opt, sep, arg, iso);
|
||||||
if (res == -1)
|
if (res == -1)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
} else
|
} else
|
||||||
return call_proc(ctx, arg, FUSE_OPT_KEY_OPT, iso);
|
return call_proc(ctx, arg, FUSE_OPT_KEY_OPT, iso);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int process_real_option_group(struct fuse_opt_context *ctx, char *opts)
|
static int process_real_option_group(struct fuse_opt_context *ctx, char *opts)
|
||||||
{
|
{
|
||||||
char *s = opts;
|
char *s = opts;
|
||||||
char *d = s;
|
char *d = s;
|
||||||
int end = 0;
|
int end = 0;
|
||||||
|
|
||||||
while (!end) {
|
while (!end) {
|
||||||
if (*s == '\0')
|
if (*s == '\0')
|
||||||
end = 1;
|
end = 1;
|
||||||
if (*s == ',' || end) {
|
if (*s == ',' || end) {
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
*d = '\0';
|
*d = '\0';
|
||||||
res = process_gopt(ctx, opts, 1);
|
res = process_gopt(ctx, opts, 1);
|
||||||
if (res == -1)
|
if (res == -1)
|
||||||
return -1;
|
return -1;
|
||||||
d = opts;
|
d = opts;
|
||||||
} else {
|
} else {
|
||||||
if (s[0] == '\\' && s[1] != '\0') {
|
if (s[0] == '\\' && s[1] != '\0') {
|
||||||
s++;
|
s++;
|
||||||
if (s[0] >= '0' && s[0] <= '3' &&
|
if (s[0] >= '0' && s[0] <= '3' &&
|
||||||
s[1] >= '0' && s[1] <= '7' &&
|
s[1] >= '0' && s[1] <= '7' &&
|
||||||
s[2] >= '0' && s[2] <= '7') {
|
s[2] >= '0' && s[2] <= '7') {
|
||||||
*d++ = (s[0] - '0') * 0100 +
|
*d++ = (s[0] - '0') * 0100 +
|
||||||
(s[1] - '0') * 0010 +
|
(s[1] - '0') * 0010 +
|
||||||
(s[2] - '0');
|
(s[2] - '0');
|
||||||
s += 2;
|
s += 2;
|
||||||
} else {
|
} else {
|
||||||
*d++ = *s;
|
*d++ = *s;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
*d++ = *s;
|
*d++ = *s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s++;
|
s++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int process_option_group(struct fuse_opt_context *ctx, const char *opts)
|
static int process_option_group(struct fuse_opt_context *ctx, const char *opts)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
char *copy = strdup(opts);
|
char *copy = strdup(opts);
|
||||||
|
|
||||||
if (!copy) {
|
if (!copy) {
|
||||||
fprintf(stderr, "fuse: memory allocation failed\n");
|
fprintf(stderr, "fuse: memory allocation failed\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
res = process_real_option_group(ctx, copy);
|
res = process_real_option_group(ctx, copy);
|
||||||
free(copy);
|
free(copy);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int process_one(struct fuse_opt_context *ctx, const char *arg)
|
static int process_one(struct fuse_opt_context *ctx, const char *arg)
|
||||||
{
|
{
|
||||||
if (ctx->nonopt || arg[0] != '-')
|
if (ctx->nonopt || arg[0] != '-')
|
||||||
return call_proc(ctx, arg, FUSE_OPT_KEY_NONOPT, 0);
|
return call_proc(ctx, arg, FUSE_OPT_KEY_NONOPT, 0);
|
||||||
else if (arg[1] == 'o') {
|
else if (arg[1] == 'o') {
|
||||||
if (arg[2])
|
if (arg[2])
|
||||||
return process_option_group(ctx, arg + 2);
|
return process_option_group(ctx, arg + 2);
|
||||||
else {
|
else {
|
||||||
if (next_arg(ctx, arg) == -1)
|
if (next_arg(ctx, arg) == -1)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
return process_option_group(ctx,
|
return process_option_group(ctx,
|
||||||
ctx->argv[ctx->argctr]);
|
ctx->argv[ctx->argctr]);
|
||||||
}
|
}
|
||||||
} else if (arg[1] == '-' && !arg[2]) {
|
} else if (arg[1] == '-' && !arg[2]) {
|
||||||
if (add_arg(ctx, arg) == -1)
|
if (add_arg(ctx, arg) == -1)
|
||||||
return -1;
|
return -1;
|
||||||
ctx->nonopt = ctx->outargs.argc;
|
ctx->nonopt = ctx->outargs.argc;
|
||||||
return 0;
|
return 0;
|
||||||
} else
|
} else
|
||||||
return process_gopt(ctx, arg, 0);
|
return process_gopt(ctx, arg, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int opt_parse(struct fuse_opt_context *ctx)
|
static int opt_parse(struct fuse_opt_context *ctx)
|
||||||
{
|
{
|
||||||
if (ctx->argc) {
|
if (ctx->argc) {
|
||||||
if (add_arg(ctx, ctx->argv[0]) == -1)
|
if (add_arg(ctx, ctx->argv[0]) == -1)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (ctx->argctr = 1; ctx->argctr < ctx->argc; ctx->argctr++)
|
for (ctx->argctr = 1; ctx->argctr < ctx->argc; ctx->argctr++)
|
||||||
if (process_one(ctx, ctx->argv[ctx->argctr]) == -1)
|
if (process_one(ctx, ctx->argv[ctx->argctr]) == -1)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (ctx->opts) {
|
if (ctx->opts) {
|
||||||
if (fuse_opt_insert_arg(&ctx->outargs, 1, "-o") == -1 ||
|
if (fuse_opt_insert_arg(&ctx->outargs, 1, "-o") == -1 ||
|
||||||
fuse_opt_insert_arg(&ctx->outargs, 2, ctx->opts) == -1)
|
fuse_opt_insert_arg(&ctx->outargs, 2, ctx->opts) == -1)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If option separator ("--") is the last argument, remove it */
|
/* If option separator ("--") is the last argument, remove it */
|
||||||
if (ctx->nonopt && ctx->nonopt == ctx->outargs.argc &&
|
if (ctx->nonopt && ctx->nonopt == ctx->outargs.argc &&
|
||||||
strcmp(ctx->outargs.argv[ctx->outargs.argc - 1], "--") == 0) {
|
strcmp(ctx->outargs.argv[ctx->outargs.argc - 1], "--") == 0) {
|
||||||
free(ctx->outargs.argv[ctx->outargs.argc - 1]);
|
free(ctx->outargs.argv[ctx->outargs.argc - 1]);
|
||||||
ctx->outargs.argv[--ctx->outargs.argc] = NULL;
|
ctx->outargs.argv[--ctx->outargs.argc] = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fuse_opt_parse(struct fuse_args *args, void *data,
|
int fuse_opt_parse(struct fuse_args *args, void *data,
|
||||||
const struct fuse_opt opts[], fuse_opt_proc_t proc)
|
const struct fuse_opt opts[], fuse_opt_proc_t proc)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
struct fuse_opt_context ctx = {
|
struct fuse_opt_context ctx = {
|
||||||
.data = data,
|
.data = data,
|
||||||
.opt = opts,
|
.opt = opts,
|
||||||
.proc = proc,
|
.proc = proc,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!args || !args->argv || !args->argc)
|
if (!args || !args->argv || !args->argc)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
ctx.argc = args->argc;
|
ctx.argc = args->argc;
|
||||||
ctx.argv = args->argv;
|
ctx.argv = args->argv;
|
||||||
|
|
||||||
res = opt_parse(&ctx);
|
res = opt_parse(&ctx);
|
||||||
if (res != -1) {
|
if (res != -1) {
|
||||||
struct fuse_args tmp = *args;
|
struct fuse_args tmp = *args;
|
||||||
*args = ctx.outargs;
|
*args = ctx.outargs;
|
||||||
ctx.outargs = tmp;
|
ctx.outargs = tmp;
|
||||||
}
|
}
|
||||||
free(ctx.opts);
|
free(ctx.opts);
|
||||||
fuse_opt_free_args(&ctx.outargs);
|
fuse_opt_free_args(&ctx.outargs);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This symbol version was mistakenly added to the version script */
|
/* This symbol version was mistakenly added to the version script */
|
||||||
|
|||||||
+31
-200
@@ -6,235 +6,66 @@
|
|||||||
See the file COPYING.LIB
|
See the file COPYING.LIB
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "fuse_i.h"
|
#include "fuse_chan.h"
|
||||||
#include "fuse_misc.h"
|
|
||||||
#include "fuse_common_compat.h"
|
#include "fuse_common_compat.h"
|
||||||
|
#include "fuse_i.h"
|
||||||
|
#include "fuse_kernel.h"
|
||||||
#include "fuse_lowlevel_compat.h"
|
#include "fuse_lowlevel_compat.h"
|
||||||
|
#include "fuse_misc.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <assert.h>
|
#include <sys/ioctl.h>
|
||||||
#include <errno.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
struct fuse_chan {
|
|
||||||
struct fuse_chan_ops op;
|
|
||||||
|
|
||||||
struct fuse_session *se;
|
|
||||||
|
|
||||||
int fd;
|
|
||||||
|
|
||||||
size_t bufsize;
|
|
||||||
|
|
||||||
void *data;
|
|
||||||
|
|
||||||
int compat;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct fuse_session *fuse_session_new(struct fuse_session_ops *op, void *data)
|
struct fuse_session *fuse_session_new(struct fuse_session_ops *op, void *data)
|
||||||
{
|
{
|
||||||
struct fuse_session *se = (struct fuse_session *) malloc(sizeof(*se));
|
struct fuse_session *se = (struct fuse_session *) malloc(sizeof(*se));
|
||||||
if (se == NULL) {
|
if (se == NULL) {
|
||||||
fprintf(stderr, "fuse: failed to allocate session\n");
|
fprintf(stderr, "fuse: failed to allocate session\n");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(se, 0, sizeof(*se));
|
memset(se, 0, sizeof(*se));
|
||||||
se->op = *op;
|
se->op = *op;
|
||||||
se->data = data;
|
se->data = data;
|
||||||
|
|
||||||
return se;
|
return se;
|
||||||
}
|
}
|
||||||
|
|
||||||
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_next_chan(struct fuse_session *se,
|
|
||||||
struct fuse_chan *ch)
|
|
||||||
{
|
|
||||||
assert(ch == NULL || ch == se->ch);
|
|
||||||
if (ch == NULL)
|
|
||||||
return se->ch;
|
|
||||||
else
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void fuse_session_process(struct fuse_session *se, const char *buf, size_t len,
|
|
||||||
struct fuse_chan *ch)
|
|
||||||
{
|
|
||||||
se->op.process(se->data, buf, len, ch);
|
|
||||||
}
|
|
||||||
|
|
||||||
void fuse_session_process_buf(struct fuse_session *se,
|
|
||||||
const struct fuse_buf *buf, struct fuse_chan *ch)
|
|
||||||
{
|
|
||||||
if (se->process_buf) {
|
|
||||||
se->process_buf(se->data, buf, ch);
|
|
||||||
} else {
|
|
||||||
assert(!(buf->flags & FUSE_BUF_IS_FD));
|
|
||||||
fuse_session_process(se->data, buf->mem, buf->size, ch);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int fuse_session_receive_buf(struct fuse_session *se, struct fuse_buf *buf,
|
|
||||||
struct fuse_chan **chp)
|
|
||||||
{
|
|
||||||
int res;
|
|
||||||
|
|
||||||
if (se->receive_buf) {
|
|
||||||
res = se->receive_buf(se, buf, chp);
|
|
||||||
} else {
|
|
||||||
res = fuse_chan_recv(chp, buf->mem, buf->size);
|
|
||||||
if (res > 0)
|
|
||||||
buf->size = res;
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void fuse_session_destroy(struct fuse_session *se)
|
void fuse_session_destroy(struct fuse_session *se)
|
||||||
{
|
{
|
||||||
if (se->op.destroy)
|
if (se->op.destroy)
|
||||||
se->op.destroy(se->data);
|
se->op.destroy(se->data);
|
||||||
if (se->ch != NULL)
|
free(se);
|
||||||
fuse_chan_destroy(se->ch);
|
|
||||||
free(se);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void fuse_session_exit(struct fuse_session *se)
|
void fuse_session_exit(struct fuse_session *se)
|
||||||
{
|
{
|
||||||
if (se->op.exit)
|
if (se->op.exit)
|
||||||
se->op.exit(se->data, 1);
|
se->op.exit(se->data, 1);
|
||||||
se->exited = 1;
|
se->exited = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void fuse_session_reset(struct fuse_session *se)
|
void fuse_session_reset(struct fuse_session *se)
|
||||||
{
|
{
|
||||||
if (se->op.exit)
|
if (se->op.exit)
|
||||||
se->op.exit(se->data, 0);
|
se->op.exit(se->data, 0);
|
||||||
se->exited = 0;
|
se->exited = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fuse_session_exited(struct fuse_session *se)
|
int fuse_session_exited(struct fuse_session *se)
|
||||||
{
|
{
|
||||||
if (se->op.exited)
|
if (se->op.exited)
|
||||||
return se->op.exited(se->data);
|
return se->op.exited(se->data);
|
||||||
else
|
else
|
||||||
return se->exited;
|
return se->exited;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *fuse_session_data(struct fuse_session *se)
|
void *fuse_session_data(struct fuse_session *se)
|
||||||
{
|
{
|
||||||
return se->data;
|
return se->data;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct fuse_chan *fuse_chan_new_common(struct fuse_chan_ops *op, int fd,
|
|
||||||
size_t bufsize, void *data,
|
|
||||||
int compat)
|
|
||||||
{
|
|
||||||
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->op = *op;
|
|
||||||
ch->fd = fd;
|
|
||||||
ch->bufsize = bufsize;
|
|
||||||
ch->data = data;
|
|
||||||
ch->compat = compat;
|
|
||||||
|
|
||||||
return ch;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct fuse_chan *fuse_chan_new(struct fuse_chan_ops *op, int fd,
|
|
||||||
size_t bufsize, void *data)
|
|
||||||
{
|
|
||||||
return fuse_chan_new_common(op, fd, bufsize, data, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct fuse_chan *fuse_chan_new_compat24(struct fuse_chan_ops_compat24 *op,
|
|
||||||
int fd, size_t bufsize, void *data)
|
|
||||||
{
|
|
||||||
return fuse_chan_new_common((struct fuse_chan_ops *) op, fd, bufsize,
|
|
||||||
data, 24);
|
|
||||||
}
|
|
||||||
|
|
||||||
int fuse_chan_fd(struct fuse_chan *ch)
|
|
||||||
{
|
|
||||||
return ch->fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
int fuse_chan_clearfd(struct fuse_chan *ch)
|
|
||||||
{
|
|
||||||
int fd = ch->fd;
|
|
||||||
ch->fd = -1;
|
|
||||||
return fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t fuse_chan_bufsize(struct fuse_chan *ch)
|
|
||||||
{
|
|
||||||
return ch->bufsize;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *fuse_chan_data(struct fuse_chan *ch)
|
|
||||||
{
|
|
||||||
return ch->data;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct fuse_session *fuse_chan_session(struct fuse_chan *ch)
|
|
||||||
{
|
|
||||||
return ch->se;
|
|
||||||
}
|
|
||||||
|
|
||||||
int fuse_chan_recv(struct fuse_chan **chp, char *buf, size_t size)
|
|
||||||
{
|
|
||||||
struct fuse_chan *ch = *chp;
|
|
||||||
if (ch->compat)
|
|
||||||
return ((struct fuse_chan_ops_compat24 *) &ch->op)
|
|
||||||
->receive(ch, buf, size);
|
|
||||||
else
|
|
||||||
return ch->op.receive(chp, buf, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
int fuse_chan_receive(struct fuse_chan *ch, char *buf, size_t size)
|
|
||||||
{
|
|
||||||
int res;
|
|
||||||
|
|
||||||
res = fuse_chan_recv(&ch, buf, size);
|
|
||||||
return res >= 0 ? res : (res != -EINTR && res != -EAGAIN) ? -1 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int fuse_chan_send(struct fuse_chan *ch, const struct iovec iov[], size_t count)
|
|
||||||
{
|
|
||||||
return ch->op.send(ch, iov, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
void fuse_chan_destroy(struct fuse_chan *ch)
|
|
||||||
{
|
|
||||||
fuse_session_remove_chan(ch);
|
|
||||||
if (ch->op.destroy)
|
|
||||||
ch->op.destroy(ch);
|
|
||||||
free(ch);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef __FreeBSD__
|
|
||||||
FUSE_SYMVER(".symver fuse_chan_new_compat24,fuse_chan_new@FUSE_2.4");
|
|
||||||
#endif
|
|
||||||
|
|||||||
+35
-35
@@ -16,57 +16,57 @@ static struct fuse_session *fuse_instance;
|
|||||||
|
|
||||||
static void exit_handler(int sig)
|
static void exit_handler(int sig)
|
||||||
{
|
{
|
||||||
(void) sig;
|
(void) sig;
|
||||||
if (fuse_instance)
|
if (fuse_instance)
|
||||||
fuse_session_exit(fuse_instance);
|
fuse_session_exit(fuse_instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int set_one_signal_handler(int sig, void (*handler)(int), int remove)
|
static int set_one_signal_handler(int sig, void (*handler)(int), int remove)
|
||||||
{
|
{
|
||||||
struct sigaction sa;
|
struct sigaction sa;
|
||||||
struct sigaction old_sa;
|
struct sigaction old_sa;
|
||||||
|
|
||||||
memset(&sa, 0, sizeof(struct sigaction));
|
memset(&sa, 0, sizeof(struct sigaction));
|
||||||
sa.sa_handler = remove ? SIG_DFL : handler;
|
sa.sa_handler = remove ? SIG_DFL : handler;
|
||||||
sigemptyset(&(sa.sa_mask));
|
sigemptyset(&(sa.sa_mask));
|
||||||
sa.sa_flags = 0;
|
sa.sa_flags = 0;
|
||||||
|
|
||||||
if (sigaction(sig, NULL, &old_sa) == -1) {
|
if (sigaction(sig, NULL, &old_sa) == -1) {
|
||||||
perror("fuse: cannot get old signal handler");
|
perror("fuse: cannot get old signal handler");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (old_sa.sa_handler == (remove ? handler : SIG_DFL) &&
|
if (old_sa.sa_handler == (remove ? handler : SIG_DFL) &&
|
||||||
sigaction(sig, &sa, NULL) == -1) {
|
sigaction(sig, &sa, NULL) == -1) {
|
||||||
perror("fuse: cannot set signal handler");
|
perror("fuse: cannot set signal handler");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fuse_set_signal_handlers(struct fuse_session *se)
|
int fuse_set_signal_handlers(struct fuse_session *se)
|
||||||
{
|
{
|
||||||
if (set_one_signal_handler(SIGHUP, exit_handler, 0) == -1 ||
|
if (set_one_signal_handler(SIGHUP, exit_handler, 0) == -1 ||
|
||||||
set_one_signal_handler(SIGINT, exit_handler, 0) == -1 ||
|
set_one_signal_handler(SIGINT, exit_handler, 0) == -1 ||
|
||||||
set_one_signal_handler(SIGTERM, exit_handler, 0) == -1 ||
|
set_one_signal_handler(SIGTERM, exit_handler, 0) == -1 ||
|
||||||
set_one_signal_handler(SIGPIPE, SIG_IGN, 0) == -1)
|
set_one_signal_handler(SIGPIPE, SIG_IGN, 0) == -1)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
fuse_instance = se;
|
fuse_instance = se;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void fuse_remove_signal_handlers(struct fuse_session *se)
|
void fuse_remove_signal_handlers(struct fuse_session *se)
|
||||||
{
|
{
|
||||||
if (fuse_instance != se)
|
if (fuse_instance != se)
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"fuse: fuse_remove_signal_handlers: unknown session\n");
|
"fuse: fuse_remove_signal_handlers: unknown session\n");
|
||||||
else
|
else
|
||||||
fuse_instance = NULL;
|
fuse_instance = NULL;
|
||||||
|
|
||||||
set_one_signal_handler(SIGHUP, exit_handler, 1);
|
set_one_signal_handler(SIGHUP, exit_handler, 1);
|
||||||
set_one_signal_handler(SIGINT, exit_handler, 1);
|
set_one_signal_handler(SIGINT, exit_handler, 1);
|
||||||
set_one_signal_handler(SIGTERM, exit_handler, 1);
|
set_one_signal_handler(SIGTERM, exit_handler, 1);
|
||||||
set_one_signal_handler(SIGPIPE, SIG_IGN, 1);
|
set_one_signal_handler(SIGPIPE, SIG_IGN, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,207 +0,0 @@
|
|||||||
FUSE_2.2 {
|
|
||||||
global:
|
|
||||||
fuse_destroy;
|
|
||||||
fuse_exit;
|
|
||||||
fuse_exited;
|
|
||||||
fuse_invalidate;
|
|
||||||
fuse_is_lib_option;
|
|
||||||
fuse_loop;
|
|
||||||
fuse_loop_mt;
|
|
||||||
fuse_loop_mt_proc;
|
|
||||||
fuse_main;
|
|
||||||
fuse_main_compat1;
|
|
||||||
fuse_main_compat2;
|
|
||||||
fuse_mount_compat1;
|
|
||||||
fuse_new_compat1;
|
|
||||||
fuse_new_compat2;
|
|
||||||
fuse_process_cmd;
|
|
||||||
fuse_read_cmd;
|
|
||||||
fuse_set_getcontext_func;
|
|
||||||
fuse_setup_compat2;
|
|
||||||
};
|
|
||||||
|
|
||||||
FUSE_2.4 {
|
|
||||||
global:
|
|
||||||
fuse_add_dirent;
|
|
||||||
fuse_chan_bufsize;
|
|
||||||
fuse_chan_data;
|
|
||||||
fuse_chan_destroy;
|
|
||||||
fuse_chan_fd;
|
|
||||||
fuse_chan_receive;
|
|
||||||
fuse_chan_send;
|
|
||||||
fuse_chan_session;
|
|
||||||
fuse_dirent_size;
|
|
||||||
fuse_kern_chan_new;
|
|
||||||
fuse_lowlevel_is_lib_option;
|
|
||||||
fuse_reply_attr;
|
|
||||||
fuse_reply_buf;
|
|
||||||
fuse_reply_entry;
|
|
||||||
fuse_reply_err;
|
|
||||||
fuse_reply_none;
|
|
||||||
fuse_reply_readlink;
|
|
||||||
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_new;
|
|
||||||
fuse_session_next_chan;
|
|
||||||
fuse_session_process;
|
|
||||||
fuse_session_reset;
|
|
||||||
} FUSE_2.2;
|
|
||||||
|
|
||||||
FUSE_2.5 {
|
|
||||||
global:
|
|
||||||
fuse_lowlevel_new_compat;
|
|
||||||
fuse_main_real_compat22;
|
|
||||||
fuse_mount_compat22;
|
|
||||||
fuse_new_compat22;
|
|
||||||
fuse_opt_parse;
|
|
||||||
fuse_opt_add_opt;
|
|
||||||
fuse_opt_add_arg;
|
|
||||||
fuse_opt_free_args;
|
|
||||||
fuse_opt_match;
|
|
||||||
fuse_parse_cmdline;
|
|
||||||
fuse_remove_signal_handlers;
|
|
||||||
fuse_reply_create;
|
|
||||||
fuse_reply_open;
|
|
||||||
fuse_reply_open_compat;
|
|
||||||
fuse_reply_statfs;
|
|
||||||
fuse_reply_statfs_compat;
|
|
||||||
fuse_setup_compat22;
|
|
||||||
fuse_set_signal_handlers;
|
|
||||||
} FUSE_2.4;
|
|
||||||
|
|
||||||
FUSE_2.6 {
|
|
||||||
global:
|
|
||||||
fuse_add_direntry;
|
|
||||||
fuse_chan_new;
|
|
||||||
fuse_chan_new_compat24;
|
|
||||||
fuse_chan_recv;
|
|
||||||
fuse_daemonize;
|
|
||||||
fuse_get_session;
|
|
||||||
fuse_interrupted;
|
|
||||||
fuse_lowlevel_new;
|
|
||||||
fuse_lowlevel_new_compat25;
|
|
||||||
fuse_main_real;
|
|
||||||
fuse_main_real_compat25;
|
|
||||||
fuse_mount;
|
|
||||||
fuse_mount_compat25;
|
|
||||||
fuse_new;
|
|
||||||
fuse_new_compat25;
|
|
||||||
fuse_opt_insert_arg;
|
|
||||||
fuse_reply_lock;
|
|
||||||
fuse_req_interrupt_func;
|
|
||||||
fuse_req_interrupted;
|
|
||||||
fuse_session_remove_chan;
|
|
||||||
fuse_setup;
|
|
||||||
fuse_setup_compat25;
|
|
||||||
fuse_teardown;
|
|
||||||
fuse_teardown_compat22;
|
|
||||||
fuse_unmount;
|
|
||||||
fuse_unmount_compat22;
|
|
||||||
} FUSE_2.5;
|
|
||||||
|
|
||||||
FUSE_2.7 {
|
|
||||||
global:
|
|
||||||
fuse_fs_access;
|
|
||||||
fuse_fs_bmap;
|
|
||||||
fuse_fs_chmod;
|
|
||||||
fuse_fs_chown;
|
|
||||||
fuse_fs_create;
|
|
||||||
fuse_fs_destroy;
|
|
||||||
fuse_fs_fgetattr;
|
|
||||||
fuse_fs_flush;
|
|
||||||
fuse_fs_fsync;
|
|
||||||
fuse_fs_fsyncdir;
|
|
||||||
fuse_fs_ftruncate;
|
|
||||||
fuse_fs_getattr;
|
|
||||||
fuse_fs_getxattr;
|
|
||||||
fuse_fs_init;
|
|
||||||
fuse_fs_link;
|
|
||||||
fuse_fs_listxattr;
|
|
||||||
fuse_fs_lock;
|
|
||||||
fuse_fs_mkdir;
|
|
||||||
fuse_fs_mknod;
|
|
||||||
fuse_fs_new;
|
|
||||||
fuse_fs_open;
|
|
||||||
fuse_fs_opendir;
|
|
||||||
fuse_fs_read;
|
|
||||||
fuse_fs_readdir;
|
|
||||||
fuse_fs_readlink;
|
|
||||||
fuse_fs_release;
|
|
||||||
fuse_fs_releasedir;
|
|
||||||
fuse_fs_removexattr;
|
|
||||||
fuse_fs_rename;
|
|
||||||
fuse_fs_rmdir;
|
|
||||||
fuse_fs_setxattr;
|
|
||||||
fuse_fs_statfs;
|
|
||||||
fuse_fs_symlink;
|
|
||||||
fuse_fs_truncate;
|
|
||||||
fuse_fs_unlink;
|
|
||||||
fuse_fs_utimens;
|
|
||||||
fuse_fs_write;
|
|
||||||
fuse_register_module;
|
|
||||||
fuse_reply_iov;
|
|
||||||
fuse_version;
|
|
||||||
} FUSE_2.6;
|
|
||||||
|
|
||||||
FUSE_2.7.5 {
|
|
||||||
global:
|
|
||||||
fuse_reply_bmap;
|
|
||||||
} FUSE_2.7;
|
|
||||||
|
|
||||||
FUSE_2.8 {
|
|
||||||
global:
|
|
||||||
cuse_lowlevel_new;
|
|
||||||
cuse_lowlevel_main;
|
|
||||||
cuse_lowlevel_setup;
|
|
||||||
cuse_lowlevel_teardown;
|
|
||||||
fuse_fs_ioctl;
|
|
||||||
fuse_fs_poll;
|
|
||||||
fuse_get_context;
|
|
||||||
fuse_getgroups;
|
|
||||||
fuse_lowlevel_notify_inval_entry;
|
|
||||||
fuse_lowlevel_notify_inval_inode;
|
|
||||||
fuse_lowlevel_notify_poll;
|
|
||||||
fuse_notify_poll;
|
|
||||||
fuse_opt_add_opt_escaped;
|
|
||||||
fuse_pollhandle_destroy;
|
|
||||||
fuse_reply_ioctl;
|
|
||||||
fuse_reply_ioctl_iov;
|
|
||||||
fuse_reply_ioctl_retry;
|
|
||||||
fuse_reply_poll;
|
|
||||||
fuse_req_ctx;
|
|
||||||
fuse_req_getgroups;
|
|
||||||
fuse_session_data;
|
|
||||||
} FUSE_2.7.5;
|
|
||||||
|
|
||||||
FUSE_2.9 {
|
|
||||||
global:
|
|
||||||
fuse_buf_copy;
|
|
||||||
fuse_buf_size;
|
|
||||||
fuse_fs_read_buf;
|
|
||||||
fuse_fs_write_buf;
|
|
||||||
fuse_lowlevel_notify_retrieve;
|
|
||||||
fuse_lowlevel_notify_store;
|
|
||||||
fuse_reply_data;
|
|
||||||
fuse_session_process_buf;
|
|
||||||
fuse_session_receive_buf;
|
|
||||||
fuse_start_cleanup_thread;
|
|
||||||
fuse_stop_cleanup_thread;
|
|
||||||
fuse_clean_cache;
|
|
||||||
fuse_lowlevel_notify_delete;
|
|
||||||
fuse_fs_flock;
|
|
||||||
} FUSE_2.8;
|
|
||||||
|
|
||||||
FUSE_2.9.1 {
|
|
||||||
global:
|
|
||||||
fuse_fs_fallocate;
|
|
||||||
|
|
||||||
local:
|
|
||||||
*;
|
|
||||||
} FUSE_2.9;
|
|
||||||
+213
-327
@@ -7,11 +7,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "fuse_chan.h"
|
||||||
#include "fuse_i.h"
|
#include "fuse_i.h"
|
||||||
|
#include "fuse_lowlevel.h"
|
||||||
#include "fuse_misc.h"
|
#include "fuse_misc.h"
|
||||||
#include "fuse_opt.h"
|
#include "fuse_opt.h"
|
||||||
#include "fuse_lowlevel.h"
|
|
||||||
#include "fuse_common_compat.h"
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@@ -23,9 +23,9 @@
|
|||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
KEY_HELP,
|
KEY_HELP,
|
||||||
KEY_HELP_NOHEADER,
|
KEY_HELP_NOHEADER,
|
||||||
KEY_VERSION,
|
KEY_VERSION,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct helper_opts
|
struct helper_opts
|
||||||
@@ -42,115 +42,113 @@ static
|
|||||||
const
|
const
|
||||||
struct fuse_opt fuse_helper_opts[] =
|
struct fuse_opt fuse_helper_opts[] =
|
||||||
{
|
{
|
||||||
FUSE_HELPER_OPT("-d", foreground),
|
FUSE_HELPER_OPT("-d", foreground),
|
||||||
FUSE_HELPER_OPT("debug", foreground),
|
FUSE_HELPER_OPT("debug", foreground),
|
||||||
FUSE_HELPER_OPT("-f", foreground),
|
FUSE_HELPER_OPT("-f", foreground),
|
||||||
FUSE_HELPER_OPT("-s", singlethread),
|
FUSE_HELPER_OPT("-s", singlethread),
|
||||||
FUSE_HELPER_OPT("fsname=", nodefault_subtype),
|
FUSE_HELPER_OPT("fsname=", nodefault_subtype),
|
||||||
FUSE_HELPER_OPT("subtype=", nodefault_subtype),
|
FUSE_HELPER_OPT("subtype=", nodefault_subtype),
|
||||||
FUSE_OPT_KEY("-h", KEY_HELP),
|
FUSE_OPT_KEY("-h", KEY_HELP),
|
||||||
FUSE_OPT_KEY("--help", KEY_HELP),
|
FUSE_OPT_KEY("--help", KEY_HELP),
|
||||||
FUSE_OPT_KEY("-ho", KEY_HELP_NOHEADER),
|
FUSE_OPT_KEY("-ho", KEY_HELP_NOHEADER),
|
||||||
FUSE_OPT_KEY("-V", KEY_VERSION),
|
FUSE_OPT_KEY("-V", KEY_VERSION),
|
||||||
FUSE_OPT_KEY("--version", KEY_VERSION),
|
FUSE_OPT_KEY("--version", KEY_VERSION),
|
||||||
FUSE_OPT_KEY("-d", FUSE_OPT_KEY_KEEP),
|
FUSE_OPT_KEY("-d", FUSE_OPT_KEY_KEEP),
|
||||||
FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP),
|
FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP),
|
||||||
FUSE_OPT_KEY("fsname=", FUSE_OPT_KEY_KEEP),
|
FUSE_OPT_KEY("fsname=", FUSE_OPT_KEY_KEEP),
|
||||||
FUSE_OPT_KEY("subtype=", FUSE_OPT_KEY_KEEP),
|
FUSE_OPT_KEY("subtype=", FUSE_OPT_KEY_KEEP),
|
||||||
FUSE_OPT_END
|
FUSE_OPT_END
|
||||||
};
|
};
|
||||||
|
|
||||||
static void usage(const char *progname)
|
static void usage(const char *progname)
|
||||||
{
|
{
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"usage: %s mountpoint [options]\n\n", progname);
|
"usage: %s mountpoint [options]\n\n", progname);
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"general options:\n"
|
"general options:\n"
|
||||||
" -o opt,[opt...] mount options\n"
|
" -o opt,[opt...] mount options\n"
|
||||||
" -h --help print help\n"
|
" -h --help print help\n"
|
||||||
" -V --version print version\n"
|
" -V --version print version\n"
|
||||||
"\n");
|
"\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void helper_help(void)
|
static void helper_help(void)
|
||||||
{
|
{
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"FUSE options:\n"
|
"FUSE options:\n"
|
||||||
" -d -o debug enable debug output (implies -f)\n"
|
" -d -o debug enable debug output (implies -f)\n"
|
||||||
" -f foreground operation\n"
|
" -f foreground operation\n"
|
||||||
" -s disable multi-threaded operation\n"
|
"\n"
|
||||||
"\n"
|
);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void helper_version(void)
|
static void helper_version(void)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "FUSE library version: %s\n", PACKAGE_VERSION);
|
fprintf(stderr, "FUSE library version: %s\n", PACKAGE_VERSION);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fuse_helper_opt_proc(void *data, const char *arg, int key,
|
static int fuse_helper_opt_proc(void *data, const char *arg, int key,
|
||||||
struct fuse_args *outargs)
|
struct fuse_args *outargs)
|
||||||
{
|
{
|
||||||
struct helper_opts *hopts = data;
|
struct helper_opts *hopts = data;
|
||||||
|
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case KEY_HELP:
|
case KEY_HELP:
|
||||||
usage(outargs->argv[0]);
|
usage(outargs->argv[0]);
|
||||||
/* fall through */
|
/* fall through */
|
||||||
|
|
||||||
case KEY_HELP_NOHEADER:
|
case KEY_HELP_NOHEADER:
|
||||||
helper_help();
|
helper_help();
|
||||||
return fuse_opt_add_arg(outargs, "-h");
|
return fuse_opt_add_arg(outargs, "-h");
|
||||||
|
|
||||||
case KEY_VERSION:
|
case KEY_VERSION:
|
||||||
helper_version();
|
helper_version();
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
case FUSE_OPT_KEY_NONOPT:
|
case FUSE_OPT_KEY_NONOPT:
|
||||||
if (!hopts->mountpoint) {
|
if (!hopts->mountpoint) {
|
||||||
char mountpoint[PATH_MAX];
|
char mountpoint[PATH_MAX];
|
||||||
if (realpath(arg, mountpoint) == NULL) {
|
if (realpath(arg, mountpoint) == NULL) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"fuse: bad mount point `%s': %s\n",
|
"fuse: bad mount point `%s': %s\n",
|
||||||
arg, strerror(errno));
|
arg, strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return fuse_opt_add_opt(&hopts->mountpoint, mountpoint);
|
return fuse_opt_add_opt(&hopts->mountpoint, mountpoint);
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "fuse: invalid argument `%s'\n", arg);
|
fprintf(stderr, "fuse: invalid argument `%s'\n", arg);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int add_default_subtype(const char *progname, struct fuse_args *args)
|
static int add_default_subtype(const char *progname, struct fuse_args *args)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
char *subtype_opt;
|
char *subtype_opt;
|
||||||
const char *basename = strrchr(progname, '/');
|
const char *basename = strrchr(progname, '/');
|
||||||
if (basename == NULL)
|
if (basename == NULL)
|
||||||
basename = progname;
|
basename = progname;
|
||||||
else if (basename[1] != '\0')
|
else if (basename[1] != '\0')
|
||||||
basename++;
|
basename++;
|
||||||
|
|
||||||
subtype_opt = (char *) malloc(strlen(basename) + 64);
|
subtype_opt = (char *) malloc(strlen(basename) + 64);
|
||||||
if (subtype_opt == NULL) {
|
if (subtype_opt == NULL) {
|
||||||
fprintf(stderr, "fuse: memory allocation failed\n");
|
fprintf(stderr, "fuse: memory allocation failed\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
sprintf(subtype_opt, "-osubtype=%s", basename);
|
sprintf(subtype_opt, "-osubtype=%s", basename);
|
||||||
res = fuse_opt_add_arg(args, subtype_opt);
|
res = fuse_opt_add_arg(args, subtype_opt);
|
||||||
free(subtype_opt);
|
free(subtype_opt);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
fuse_parse_cmdline(struct fuse_args *args_,
|
fuse_parse_cmdline(struct fuse_args *args_,
|
||||||
char **mountpoint_,
|
char **mountpoint_,
|
||||||
int *multithreaded_,
|
|
||||||
int *foreground_)
|
int *foreground_)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
@@ -177,8 +175,6 @@ fuse_parse_cmdline(struct fuse_args *args_,
|
|||||||
else
|
else
|
||||||
free(hopts.mountpoint);
|
free(hopts.mountpoint);
|
||||||
|
|
||||||
if(multithreaded_)
|
|
||||||
*multithreaded_ = !hopts.singlethread;
|
|
||||||
if(foreground_)
|
if(foreground_)
|
||||||
*foreground_ = hopts.foreground;
|
*foreground_ = hopts.foreground;
|
||||||
|
|
||||||
@@ -191,62 +187,61 @@ fuse_parse_cmdline(struct fuse_args *args_,
|
|||||||
|
|
||||||
int fuse_daemonize(int foreground)
|
int fuse_daemonize(int foreground)
|
||||||
{
|
{
|
||||||
if (!foreground) {
|
if (!foreground) {
|
||||||
int nullfd;
|
int nullfd;
|
||||||
int waiter[2];
|
int waiter[2];
|
||||||
char completed;
|
char completed;
|
||||||
|
|
||||||
if (pipe(waiter)) {
|
if (pipe(waiter)) {
|
||||||
perror("fuse_daemonize: pipe");
|
perror("fuse_daemonize: pipe");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* demonize current process by forking it and killing the
|
* demonize current process by forking it and killing the
|
||||||
* parent. This makes current process as a child of 'init'.
|
* parent. This makes current process as a child of 'init'.
|
||||||
*/
|
*/
|
||||||
switch(fork()) {
|
switch(fork()) {
|
||||||
case -1:
|
case -1:
|
||||||
perror("fuse_daemonize: fork");
|
perror("fuse_daemonize: fork");
|
||||||
return -1;
|
return -1;
|
||||||
case 0:
|
case 0:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
read(waiter[0], &completed, sizeof(completed));
|
read(waiter[0], &completed, sizeof(completed));
|
||||||
_exit(0);
|
_exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (setsid() == -1) {
|
if (setsid() == -1) {
|
||||||
perror("fuse_daemonize: setsid");
|
perror("fuse_daemonize: setsid");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
(void) chdir("/");
|
(void) chdir("/");
|
||||||
|
|
||||||
nullfd = open("/dev/null", O_RDWR, 0);
|
nullfd = open("/dev/null", O_RDWR, 0);
|
||||||
if (nullfd != -1) {
|
if (nullfd != -1) {
|
||||||
(void) dup2(nullfd, 0);
|
(void) dup2(nullfd, 0);
|
||||||
(void) dup2(nullfd, 1);
|
(void) dup2(nullfd, 1);
|
||||||
(void) dup2(nullfd, 2);
|
(void) dup2(nullfd, 2);
|
||||||
if (nullfd > 2)
|
if (nullfd > 2)
|
||||||
close(nullfd);
|
close(nullfd);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Propagate completion of daemon initializatation */
|
/* Propagate completion of daemon initializatation */
|
||||||
completed = 1;
|
completed = 1;
|
||||||
write(waiter[1], &completed, sizeof(completed));
|
write(waiter[1], &completed, sizeof(completed));
|
||||||
close(waiter[0]);
|
close(waiter[0]);
|
||||||
close(waiter[1]);
|
close(waiter[1]);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
struct fuse_chan *
|
int
|
||||||
fuse_mount_common(const char *mountpoint_,
|
fuse_mount_common(const char *mountpoint_,
|
||||||
struct fuse_args *args_)
|
struct fuse_args *args_)
|
||||||
{
|
{
|
||||||
struct fuse_chan *ch;
|
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -260,252 +255,143 @@ fuse_mount_common(const char *mountpoint_,
|
|||||||
close(fd);
|
close(fd);
|
||||||
} while(fd >= 0 && fd <= 2);
|
} while(fd >= 0 && fd <= 2);
|
||||||
|
|
||||||
fd = fuse_mount_compat25(mountpoint_, args_);
|
fd = fuse_kern_mount(mountpoint_,args_);
|
||||||
if(fd == -1)
|
if(fd == -1)
|
||||||
return NULL;
|
return -1;
|
||||||
|
|
||||||
ch = fuse_kern_chan_new(fd);
|
return fd;
|
||||||
if(!ch)
|
|
||||||
fuse_kern_unmount(mountpoint_, fd);
|
|
||||||
|
|
||||||
return ch;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct fuse_chan *
|
int
|
||||||
fuse_mount(const char *mountpoint_,
|
fuse_mount(const char *mountpoint_,
|
||||||
struct fuse_args *args_)
|
struct fuse_args *args_)
|
||||||
{
|
{
|
||||||
return fuse_mount_common(mountpoint_,args_);
|
return fuse_mount_common(mountpoint_,args_);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fuse_unmount_common(const char *mountpoint, struct fuse_chan *ch)
|
void
|
||||||
|
fuse_unmount(const char *mountpoint,
|
||||||
|
int devfuse_fd)
|
||||||
{
|
{
|
||||||
if (mountpoint) {
|
if(mountpoint == NULL)
|
||||||
int fd = ch ? fuse_chan_clearfd(ch) : -1;
|
return;
|
||||||
fuse_kern_unmount(mountpoint, fd);
|
fuse_kern_unmount(mountpoint,devfuse_fd);
|
||||||
if (ch)
|
|
||||||
fuse_chan_destroy(ch);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void fuse_unmount(const char *mountpoint, struct fuse_chan *ch)
|
struct fuse *
|
||||||
|
fuse_setup_common(int argc,
|
||||||
|
char *argv[],
|
||||||
|
const struct fuse_operations *op,
|
||||||
|
size_t op_size,
|
||||||
|
char **mountpoint,
|
||||||
|
void *user_data)
|
||||||
{
|
{
|
||||||
fuse_unmount_common(mountpoint, ch);
|
struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
|
||||||
}
|
int res;
|
||||||
|
int foreground;
|
||||||
|
int devfuse_fd;
|
||||||
|
struct fuse *fuse;
|
||||||
|
|
||||||
struct fuse *fuse_setup_common(int argc, char *argv[],
|
res = fuse_parse_cmdline(&args, mountpoint, &foreground);
|
||||||
const struct fuse_operations *op,
|
if (res == -1)
|
||||||
size_t op_size,
|
return NULL;
|
||||||
char **mountpoint,
|
|
||||||
int *multithreaded,
|
|
||||||
int *fd,
|
|
||||||
void *user_data,
|
|
||||||
int compat)
|
|
||||||
{
|
|
||||||
struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
|
|
||||||
struct fuse_chan *ch;
|
|
||||||
struct fuse *fuse;
|
|
||||||
int foreground;
|
|
||||||
int res;
|
|
||||||
|
|
||||||
res = fuse_parse_cmdline(&args, mountpoint, multithreaded, &foreground);
|
devfuse_fd = fuse_mount_common(*mountpoint, &args);
|
||||||
if (res == -1)
|
if(devfuse_fd == -1)
|
||||||
return NULL;
|
{
|
||||||
|
fuse_opt_free_args(&args);
|
||||||
|
goto err_free;
|
||||||
|
}
|
||||||
|
|
||||||
ch = fuse_mount_common(*mountpoint, &args);
|
fuse = fuse_new_common(devfuse_fd, &args, op, op_size, user_data);
|
||||||
if (!ch) {
|
fuse_opt_free_args(&args);
|
||||||
fuse_opt_free_args(&args);
|
if (fuse == NULL)
|
||||||
goto err_free;
|
goto err_unmount;
|
||||||
}
|
|
||||||
|
|
||||||
fuse = fuse_new_common(ch, &args, op, op_size, user_data, compat);
|
res = fuse_daemonize(foreground);
|
||||||
fuse_opt_free_args(&args);
|
if (res == -1)
|
||||||
if (fuse == NULL)
|
goto err_unmount;
|
||||||
goto err_unmount;
|
|
||||||
|
|
||||||
res = fuse_daemonize(foreground);
|
res = fuse_set_signal_handlers(fuse_get_session(fuse));
|
||||||
if (res == -1)
|
if (res == -1)
|
||||||
goto err_unmount;
|
goto err_unmount;
|
||||||
|
|
||||||
res = fuse_set_signal_handlers(fuse_get_session(fuse));
|
return fuse;
|
||||||
if (res == -1)
|
|
||||||
goto err_unmount;
|
|
||||||
|
|
||||||
if (fd)
|
err_unmount:
|
||||||
*fd = fuse_chan_fd(ch);
|
fuse_kern_unmount(*mountpoint,devfuse_fd);
|
||||||
|
if(fuse)
|
||||||
return fuse;
|
fuse_destroy(fuse);
|
||||||
|
err_free:
|
||||||
err_unmount:
|
free(*mountpoint);
|
||||||
fuse_unmount_common(*mountpoint, ch);
|
return NULL;
|
||||||
if (fuse)
|
|
||||||
fuse_destroy(fuse);
|
|
||||||
err_free:
|
|
||||||
free(*mountpoint);
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct fuse *fuse_setup(int argc, char *argv[],
|
struct fuse *fuse_setup(int argc, char *argv[],
|
||||||
const struct fuse_operations *op, size_t op_size,
|
const struct fuse_operations *op, size_t op_size,
|
||||||
char **mountpoint, int *multithreaded, void *user_data)
|
char **mountpoint, void *user_data)
|
||||||
{
|
{
|
||||||
return fuse_setup_common(argc, argv, op, op_size, mountpoint,
|
return fuse_setup_common(argc, argv, op, op_size, mountpoint, user_data);
|
||||||
multithreaded, NULL, user_data, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fuse_teardown_common(struct fuse *fuse, char *mountpoint)
|
static void fuse_teardown_common(struct fuse *fuse, char *mountpoint)
|
||||||
{
|
{
|
||||||
struct fuse_session *se = fuse_get_session(fuse);
|
struct fuse_session *se = fuse_get_session(fuse);
|
||||||
struct fuse_chan *ch = fuse_session_next_chan(se, NULL);
|
fuse_remove_signal_handlers(se);
|
||||||
fuse_remove_signal_handlers(se);
|
fuse_kern_unmount(mountpoint,se->devfuse_fd);
|
||||||
fuse_unmount_common(mountpoint, ch);
|
fuse_destroy(fuse);
|
||||||
fuse_destroy(fuse);
|
free(mountpoint);
|
||||||
free(mountpoint);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void fuse_teardown(struct fuse *fuse, char *mountpoint)
|
void
|
||||||
|
fuse_teardown(struct fuse *fuse,
|
||||||
|
char *mountpoint)
|
||||||
{
|
{
|
||||||
fuse_teardown_common(fuse, mountpoint);
|
fuse_teardown_common(fuse,mountpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fuse_main_common(int argc, char *argv[],
|
static
|
||||||
const struct fuse_operations *op, size_t op_size,
|
int
|
||||||
void *user_data, int compat)
|
fuse_main_common(int argc, char *argv[],
|
||||||
|
const struct fuse_operations *op, size_t op_size,
|
||||||
|
void *user_data)
|
||||||
{
|
{
|
||||||
struct fuse *fuse;
|
struct fuse *fuse;
|
||||||
char *mountpoint;
|
char *mountpoint;
|
||||||
int multithreaded;
|
int res;
|
||||||
int res;
|
|
||||||
|
|
||||||
fuse = fuse_setup_common(argc, argv, op, op_size, &mountpoint,
|
fuse = fuse_setup_common(argc, argv, op, op_size, &mountpoint,
|
||||||
&multithreaded, NULL, user_data, compat);
|
user_data);
|
||||||
if (fuse == NULL)
|
if(fuse == NULL)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
if (multithreaded)
|
res = fuse_loop_mt(fuse);
|
||||||
res = fuse_loop_mt(fuse);
|
|
||||||
else
|
|
||||||
res = fuse_loop(fuse);
|
|
||||||
|
|
||||||
fuse_teardown_common(fuse, mountpoint);
|
fuse_teardown_common(fuse,mountpoint);
|
||||||
if (res == -1)
|
if (res == -1)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fuse_main_real(int argc, char *argv[], const struct fuse_operations *op,
|
int
|
||||||
size_t op_size, void *user_data)
|
fuse_main_real(int argc, char *argv[],
|
||||||
|
const struct fuse_operations *op,
|
||||||
|
size_t op_size, void *user_data)
|
||||||
{
|
{
|
||||||
return fuse_main_common(argc, argv, op, op_size, user_data, 0);
|
return fuse_main_common(argc, argv, op, op_size, user_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef fuse_main
|
int
|
||||||
int fuse_main(void);
|
fuse_main(int argc,
|
||||||
int fuse_main(void)
|
char *argv[],
|
||||||
|
const struct fuse_operations *op,
|
||||||
|
void *user_data)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "fuse_main(): This function does not exist\n");
|
return fuse_main_real(argc, argv, op, sizeof(*(op)), user_data);
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int fuse_version(void)
|
int fuse_version(void)
|
||||||
{
|
{
|
||||||
return FUSE_VERSION;
|
return FUSE_VERSION;
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "fuse_compat.h"
|
|
||||||
|
|
||||||
#if !defined(__FreeBSD__) && !defined(__NetBSD__)
|
|
||||||
|
|
||||||
struct fuse *fuse_setup_compat22(int argc, char *argv[],
|
|
||||||
const struct fuse_operations_compat22 *op,
|
|
||||||
size_t op_size, char **mountpoint,
|
|
||||||
int *multithreaded, int *fd)
|
|
||||||
{
|
|
||||||
return fuse_setup_common(argc, argv, (struct fuse_operations *) op,
|
|
||||||
op_size, mountpoint, multithreaded, fd, NULL,
|
|
||||||
22);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct fuse *fuse_setup_compat2(int argc, char *argv[],
|
|
||||||
const struct fuse_operations_compat2 *op,
|
|
||||||
char **mountpoint, int *multithreaded,
|
|
||||||
int *fd)
|
|
||||||
{
|
|
||||||
return fuse_setup_common(argc, argv, (struct fuse_operations *) op,
|
|
||||||
sizeof(struct fuse_operations_compat2),
|
|
||||||
mountpoint, multithreaded, fd, NULL, 21);
|
|
||||||
}
|
|
||||||
|
|
||||||
int fuse_main_real_compat22(int argc, char *argv[],
|
|
||||||
const struct fuse_operations_compat22 *op,
|
|
||||||
size_t op_size)
|
|
||||||
{
|
|
||||||
return fuse_main_common(argc, argv, (struct fuse_operations *) op,
|
|
||||||
op_size, NULL, 22);
|
|
||||||
}
|
|
||||||
|
|
||||||
void fuse_main_compat1(int argc, char *argv[],
|
|
||||||
const struct fuse_operations_compat1 *op)
|
|
||||||
{
|
|
||||||
fuse_main_common(argc, argv, (struct fuse_operations *) op,
|
|
||||||
sizeof(struct fuse_operations_compat1), NULL, 11);
|
|
||||||
}
|
|
||||||
|
|
||||||
int fuse_main_compat2(int argc, char *argv[],
|
|
||||||
const struct fuse_operations_compat2 *op)
|
|
||||||
{
|
|
||||||
return fuse_main_common(argc, argv, (struct fuse_operations *) op,
|
|
||||||
sizeof(struct fuse_operations_compat2), NULL,
|
|
||||||
21);
|
|
||||||
}
|
|
||||||
|
|
||||||
int fuse_mount_compat1(const char *mountpoint, const char *args[])
|
|
||||||
{
|
|
||||||
/* just ignore mount args for now */
|
|
||||||
(void) args;
|
|
||||||
return fuse_mount_compat22(mountpoint, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
FUSE_SYMVER(".symver fuse_setup_compat2,__fuse_setup@");
|
|
||||||
FUSE_SYMVER(".symver fuse_setup_compat22,fuse_setup@FUSE_2.2");
|
|
||||||
FUSE_SYMVER(".symver fuse_teardown,__fuse_teardown@");
|
|
||||||
FUSE_SYMVER(".symver fuse_main_compat2,fuse_main@");
|
|
||||||
FUSE_SYMVER(".symver fuse_main_real_compat22,fuse_main_real@FUSE_2.2");
|
|
||||||
|
|
||||||
#endif /* __FreeBSD__ || __NetBSD__ */
|
|
||||||
|
|
||||||
|
|
||||||
struct fuse *fuse_setup_compat25(int argc, char *argv[],
|
|
||||||
const struct fuse_operations_compat25 *op,
|
|
||||||
size_t op_size, char **mountpoint,
|
|
||||||
int *multithreaded, int *fd)
|
|
||||||
{
|
|
||||||
return fuse_setup_common(argc, argv, (struct fuse_operations *) op,
|
|
||||||
op_size, mountpoint, multithreaded, fd, NULL,
|
|
||||||
25);
|
|
||||||
}
|
|
||||||
|
|
||||||
int fuse_main_real_compat25(int argc, char *argv[],
|
|
||||||
const struct fuse_operations_compat25 *op,
|
|
||||||
size_t op_size)
|
|
||||||
{
|
|
||||||
return fuse_main_common(argc, argv, (struct fuse_operations *) op,
|
|
||||||
op_size, NULL, 25);
|
|
||||||
}
|
|
||||||
|
|
||||||
void fuse_teardown_compat22(struct fuse *fuse, int fd, char *mountpoint)
|
|
||||||
{
|
|
||||||
(void) fd;
|
|
||||||
fuse_teardown_common(fuse, mountpoint);
|
|
||||||
}
|
|
||||||
|
|
||||||
int fuse_mount_compat25(const char *mountpoint, struct fuse_args *args)
|
|
||||||
{
|
|
||||||
return fuse_kern_mount(mountpoint, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
FUSE_SYMVER(".symver fuse_setup_compat25,fuse_setup@FUSE_2.5");
|
|
||||||
FUSE_SYMVER(".symver fuse_teardown_compat22,fuse_teardown@FUSE_2.2");
|
|
||||||
FUSE_SYMVER(".symver fuse_main_real_compat25,fuse_main_real@FUSE_2.5");
|
|
||||||
FUSE_SYMVER(".symver fuse_mount_compat25,fuse_mount@FUSE_2.5");
|
|
||||||
|
|||||||
+260
-260
@@ -28,364 +28,364 @@
|
|||||||
#define FUSE_DEV_TRUNK "/dev/fuse"
|
#define FUSE_DEV_TRUNK "/dev/fuse"
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
KEY_ALLOW_ROOT,
|
KEY_ALLOW_ROOT,
|
||||||
KEY_RO,
|
KEY_RO,
|
||||||
KEY_HELP,
|
KEY_HELP,
|
||||||
KEY_VERSION,
|
KEY_VERSION,
|
||||||
KEY_KERN
|
KEY_KERN
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mount_opts {
|
struct mount_opts {
|
||||||
int allow_other;
|
int allow_other;
|
||||||
int allow_root;
|
int allow_root;
|
||||||
int ishelp;
|
int ishelp;
|
||||||
char *kernel_opts;
|
char *kernel_opts;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define FUSE_DUAL_OPT_KEY(templ, key) \
|
#define FUSE_DUAL_OPT_KEY(templ, key) \
|
||||||
FUSE_OPT_KEY(templ, key), FUSE_OPT_KEY("no" templ, key)
|
FUSE_OPT_KEY(templ, key), FUSE_OPT_KEY("no" templ, key)
|
||||||
|
|
||||||
static const struct fuse_opt fuse_mount_opts[] = {
|
static const struct fuse_opt fuse_mount_opts[] = {
|
||||||
{ "allow_other", offsetof(struct mount_opts, allow_other), 1 },
|
{ "allow_other", offsetof(struct mount_opts, allow_other), 1 },
|
||||||
{ "allow_root", offsetof(struct mount_opts, allow_root), 1 },
|
{ "allow_root", offsetof(struct mount_opts, allow_root), 1 },
|
||||||
FUSE_OPT_KEY("allow_root", KEY_ALLOW_ROOT),
|
FUSE_OPT_KEY("allow_root", KEY_ALLOW_ROOT),
|
||||||
FUSE_OPT_KEY("-r", KEY_RO),
|
FUSE_OPT_KEY("-r", KEY_RO),
|
||||||
FUSE_OPT_KEY("-h", KEY_HELP),
|
FUSE_OPT_KEY("-h", KEY_HELP),
|
||||||
FUSE_OPT_KEY("--help", KEY_HELP),
|
FUSE_OPT_KEY("--help", KEY_HELP),
|
||||||
FUSE_OPT_KEY("-V", KEY_VERSION),
|
FUSE_OPT_KEY("-V", KEY_VERSION),
|
||||||
FUSE_OPT_KEY("--version", KEY_VERSION),
|
FUSE_OPT_KEY("--version", KEY_VERSION),
|
||||||
/* standard FreeBSD mount options */
|
/* standard FreeBSD mount options */
|
||||||
FUSE_DUAL_OPT_KEY("dev", KEY_KERN),
|
FUSE_DUAL_OPT_KEY("dev", KEY_KERN),
|
||||||
FUSE_DUAL_OPT_KEY("async", KEY_KERN),
|
FUSE_DUAL_OPT_KEY("async", KEY_KERN),
|
||||||
FUSE_DUAL_OPT_KEY("atime", KEY_KERN),
|
FUSE_DUAL_OPT_KEY("atime", KEY_KERN),
|
||||||
FUSE_DUAL_OPT_KEY("dev", KEY_KERN),
|
FUSE_DUAL_OPT_KEY("dev", KEY_KERN),
|
||||||
FUSE_DUAL_OPT_KEY("exec", KEY_KERN),
|
FUSE_DUAL_OPT_KEY("exec", KEY_KERN),
|
||||||
FUSE_DUAL_OPT_KEY("suid", KEY_KERN),
|
FUSE_DUAL_OPT_KEY("suid", KEY_KERN),
|
||||||
FUSE_DUAL_OPT_KEY("symfollow", KEY_KERN),
|
FUSE_DUAL_OPT_KEY("symfollow", KEY_KERN),
|
||||||
FUSE_DUAL_OPT_KEY("rdonly", KEY_KERN),
|
FUSE_DUAL_OPT_KEY("rdonly", KEY_KERN),
|
||||||
FUSE_DUAL_OPT_KEY("sync", KEY_KERN),
|
FUSE_DUAL_OPT_KEY("sync", KEY_KERN),
|
||||||
FUSE_DUAL_OPT_KEY("union", KEY_KERN),
|
FUSE_DUAL_OPT_KEY("union", KEY_KERN),
|
||||||
FUSE_DUAL_OPT_KEY("userquota", KEY_KERN),
|
FUSE_DUAL_OPT_KEY("userquota", KEY_KERN),
|
||||||
FUSE_DUAL_OPT_KEY("groupquota", KEY_KERN),
|
FUSE_DUAL_OPT_KEY("groupquota", KEY_KERN),
|
||||||
FUSE_DUAL_OPT_KEY("clusterr", KEY_KERN),
|
FUSE_DUAL_OPT_KEY("clusterr", KEY_KERN),
|
||||||
FUSE_DUAL_OPT_KEY("clusterw", KEY_KERN),
|
FUSE_DUAL_OPT_KEY("clusterw", KEY_KERN),
|
||||||
FUSE_DUAL_OPT_KEY("suiddir", KEY_KERN),
|
FUSE_DUAL_OPT_KEY("suiddir", KEY_KERN),
|
||||||
FUSE_DUAL_OPT_KEY("snapshot", KEY_KERN),
|
FUSE_DUAL_OPT_KEY("snapshot", KEY_KERN),
|
||||||
FUSE_DUAL_OPT_KEY("multilabel", KEY_KERN),
|
FUSE_DUAL_OPT_KEY("multilabel", KEY_KERN),
|
||||||
FUSE_DUAL_OPT_KEY("acls", KEY_KERN),
|
FUSE_DUAL_OPT_KEY("acls", KEY_KERN),
|
||||||
FUSE_DUAL_OPT_KEY("force", KEY_KERN),
|
FUSE_DUAL_OPT_KEY("force", KEY_KERN),
|
||||||
FUSE_DUAL_OPT_KEY("update", KEY_KERN),
|
FUSE_DUAL_OPT_KEY("update", KEY_KERN),
|
||||||
FUSE_DUAL_OPT_KEY("ro", KEY_KERN),
|
FUSE_DUAL_OPT_KEY("ro", KEY_KERN),
|
||||||
FUSE_DUAL_OPT_KEY("rw", KEY_KERN),
|
FUSE_DUAL_OPT_KEY("rw", KEY_KERN),
|
||||||
FUSE_DUAL_OPT_KEY("auto", KEY_KERN),
|
FUSE_DUAL_OPT_KEY("auto", KEY_KERN),
|
||||||
/* options supported under both Linux and FBSD */
|
/* options supported under both Linux and FBSD */
|
||||||
FUSE_DUAL_OPT_KEY("allow_other", KEY_KERN),
|
FUSE_DUAL_OPT_KEY("allow_other", KEY_KERN),
|
||||||
FUSE_DUAL_OPT_KEY("default_permissions",KEY_KERN),
|
FUSE_DUAL_OPT_KEY("default_permissions",KEY_KERN),
|
||||||
FUSE_OPT_KEY("max_read=", KEY_KERN),
|
FUSE_OPT_KEY("max_read=", KEY_KERN),
|
||||||
FUSE_OPT_KEY("subtype=", KEY_KERN),
|
FUSE_OPT_KEY("subtype=", KEY_KERN),
|
||||||
/* FBSD FUSE specific mount options */
|
/* FBSD FUSE specific mount options */
|
||||||
FUSE_DUAL_OPT_KEY("private", KEY_KERN),
|
FUSE_DUAL_OPT_KEY("private", KEY_KERN),
|
||||||
FUSE_DUAL_OPT_KEY("neglect_shares", KEY_KERN),
|
FUSE_DUAL_OPT_KEY("neglect_shares", KEY_KERN),
|
||||||
FUSE_DUAL_OPT_KEY("push_symlinks_in", KEY_KERN),
|
FUSE_DUAL_OPT_KEY("push_symlinks_in", KEY_KERN),
|
||||||
FUSE_OPT_KEY("nosync_unmount", KEY_KERN),
|
FUSE_OPT_KEY("nosync_unmount", KEY_KERN),
|
||||||
/* stock FBSD mountopt parsing routine lets anything be negated... */
|
/* stock FBSD mountopt parsing routine lets anything be negated... */
|
||||||
/*
|
/*
|
||||||
* Linux specific mount options, but let just the mount util
|
* Linux specific mount options, but let just the mount util
|
||||||
* handle them
|
* handle them
|
||||||
*/
|
*/
|
||||||
FUSE_OPT_KEY("fsname=", KEY_KERN),
|
FUSE_OPT_KEY("fsname=", KEY_KERN),
|
||||||
FUSE_OPT_KEY("nonempty", KEY_KERN),
|
FUSE_OPT_KEY("nonempty", KEY_KERN),
|
||||||
FUSE_OPT_KEY("large_read", KEY_KERN),
|
FUSE_OPT_KEY("large_read", KEY_KERN),
|
||||||
FUSE_OPT_END
|
FUSE_OPT_END
|
||||||
};
|
};
|
||||||
|
|
||||||
static void mount_help(void)
|
static void mount_help(void)
|
||||||
{
|
{
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
" -o allow_root allow access to root\n"
|
" -o allow_root allow access to root\n"
|
||||||
);
|
);
|
||||||
system(FUSERMOUNT_PROG " --help");
|
system(FUSERMOUNT_PROG " --help");
|
||||||
fputc('\n', stderr);
|
fputc('\n', stderr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mount_version(void)
|
static void mount_version(void)
|
||||||
{
|
{
|
||||||
system(FUSERMOUNT_PROG " --version");
|
system(FUSERMOUNT_PROG " --version");
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fuse_mount_opt_proc(void *data, const char *arg, int key,
|
static int fuse_mount_opt_proc(void *data, const char *arg, int key,
|
||||||
struct fuse_args *outargs)
|
struct fuse_args *outargs)
|
||||||
{
|
{
|
||||||
struct mount_opts *mo = data;
|
struct mount_opts *mo = data;
|
||||||
|
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case KEY_ALLOW_ROOT:
|
case KEY_ALLOW_ROOT:
|
||||||
if (fuse_opt_add_opt(&mo->kernel_opts, "allow_other") == -1 ||
|
if (fuse_opt_add_opt(&mo->kernel_opts, "allow_other") == -1 ||
|
||||||
fuse_opt_add_arg(outargs, "-oallow_root") == -1)
|
fuse_opt_add_arg(outargs, "-oallow_root") == -1)
|
||||||
return -1;
|
return -1;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case KEY_RO:
|
case KEY_RO:
|
||||||
arg = "ro";
|
arg = "ro";
|
||||||
/* fall through */
|
/* fall through */
|
||||||
|
|
||||||
case KEY_KERN:
|
case KEY_KERN:
|
||||||
return fuse_opt_add_opt(&mo->kernel_opts, arg);
|
return fuse_opt_add_opt(&mo->kernel_opts, arg);
|
||||||
|
|
||||||
case KEY_HELP:
|
case KEY_HELP:
|
||||||
mount_help();
|
mount_help();
|
||||||
mo->ishelp = 1;
|
mo->ishelp = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case KEY_VERSION:
|
case KEY_VERSION:
|
||||||
mount_version();
|
mount_version();
|
||||||
mo->ishelp = 1;
|
mo->ishelp = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void fuse_unmount_compat22(const char *mountpoint)
|
void fuse_unmount_compat22(const char *mountpoint)
|
||||||
{
|
{
|
||||||
char dev[128];
|
char dev[128];
|
||||||
char *ssc, *umount_cmd;
|
char *ssc, *umount_cmd;
|
||||||
FILE *sf;
|
FILE *sf;
|
||||||
int rv;
|
int rv;
|
||||||
char seekscript[] =
|
char seekscript[] =
|
||||||
/* error message is annoying in help output */
|
/* error message is annoying in help output */
|
||||||
"exec 2>/dev/null; "
|
"exec 2>/dev/null; "
|
||||||
"/usr/bin/fstat " FUSE_DEV_TRUNK "* | "
|
"/usr/bin/fstat " FUSE_DEV_TRUNK "* | "
|
||||||
"/usr/bin/awk 'BEGIN{ getline; if (! ($3 == \"PID\" && $10 == \"NAME\")) exit 1; }; "
|
"/usr/bin/awk 'BEGIN{ getline; if (! ($3 == \"PID\" && $10 == \"NAME\")) exit 1; }; "
|
||||||
" { if ($3 == %d) print $10; }' | "
|
" { if ($3 == %d) print $10; }' | "
|
||||||
"/usr/bin/sort | "
|
"/usr/bin/sort | "
|
||||||
"/usr/bin/uniq | "
|
"/usr/bin/uniq | "
|
||||||
"/usr/bin/awk '{ i += 1; if (i > 1){ exit 1; }; printf; }; END{ if (i == 0) exit 1; }'";
|
"/usr/bin/awk '{ i += 1; if (i > 1){ exit 1; }; printf; }; END{ if (i == 0) exit 1; }'";
|
||||||
|
|
||||||
(void) mountpoint;
|
(void) mountpoint;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we don't know the fd, we have to resort to the scripted
|
* If we don't know the fd, we have to resort to the scripted
|
||||||
* solution -- iterating over the fd-s is unpractical, as we
|
* solution -- iterating over the fd-s is unpractical, as we
|
||||||
* don't know how many of open files we have. (This could be
|
* don't know how many of open files we have. (This could be
|
||||||
* looked up in procfs -- however, that's optional on FBSD; or
|
* looked up in procfs -- however, that's optional on FBSD; or
|
||||||
* read out from the kmem -- however, that's bound to
|
* read out from the kmem -- however, that's bound to
|
||||||
* privileges (in fact, that's what happens when we call the
|
* privileges (in fact, that's what happens when we call the
|
||||||
* setgid kmem fstat(1) utility).
|
* setgid kmem fstat(1) utility).
|
||||||
*/
|
*/
|
||||||
if (asprintf(&ssc, seekscript, getpid()) == -1)
|
if (asprintf(&ssc, seekscript, getpid()) == -1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
sf = popen(ssc, "r");
|
sf = popen(ssc, "r");
|
||||||
free(ssc);
|
free(ssc);
|
||||||
if (! sf)
|
if (! sf)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
fgets(dev, sizeof(dev), sf);
|
fgets(dev, sizeof(dev), sf);
|
||||||
rv = pclose(sf);
|
rv = pclose(sf);
|
||||||
if (rv)
|
if (rv)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (asprintf(&umount_cmd, "/sbin/umount %s", dev) == -1)
|
if (asprintf(&umount_cmd, "/sbin/umount %s", dev) == -1)
|
||||||
return;
|
return;
|
||||||
system(umount_cmd);
|
system(umount_cmd);
|
||||||
free(umount_cmd);
|
free(umount_cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void do_unmount(char *dev, int fd)
|
static void do_unmount(char *dev, int fd)
|
||||||
{
|
{
|
||||||
char device_path[SPECNAMELEN + 12];
|
char device_path[SPECNAMELEN + 12];
|
||||||
const char *argv[4];
|
const char *argv[4];
|
||||||
const char umount_cmd[] = "/sbin/umount";
|
const char umount_cmd[] = "/sbin/umount";
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
|
||||||
snprintf(device_path, SPECNAMELEN + 12, _PATH_DEV "%s", dev);
|
snprintf(device_path, SPECNAMELEN + 12, _PATH_DEV "%s", dev);
|
||||||
|
|
||||||
argv[0] = umount_cmd;
|
argv[0] = umount_cmd;
|
||||||
argv[1] = "-f";
|
argv[1] = "-f";
|
||||||
argv[2] = device_path;
|
argv[2] = device_path;
|
||||||
argv[3] = NULL;
|
argv[3] = NULL;
|
||||||
|
|
||||||
pid = fork();
|
pid = fork();
|
||||||
|
|
||||||
if (pid == -1)
|
if (pid == -1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (pid == 0) {
|
if (pid == 0) {
|
||||||
close(fd);
|
close(fd);
|
||||||
execvp(umount_cmd, (char **)argv);
|
execvp(umount_cmd, (char **)argv);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
waitpid(pid, NULL, 0);
|
waitpid(pid, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void fuse_kern_unmount(const char *mountpoint, int fd)
|
void fuse_kern_unmount(const char *mountpoint, int fd)
|
||||||
{
|
{
|
||||||
char *ep, dev[128];
|
char *ep, dev[128];
|
||||||
struct stat sbuf;
|
struct stat sbuf;
|
||||||
|
|
||||||
(void)mountpoint;
|
(void)mountpoint;
|
||||||
|
|
||||||
if (fstat(fd, &sbuf) == -1)
|
if (fstat(fd, &sbuf) == -1)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
devname_r(sbuf.st_rdev, S_IFCHR, dev, 128);
|
devname_r(sbuf.st_rdev, S_IFCHR, dev, 128);
|
||||||
|
|
||||||
if (strncmp(dev, "fuse", 4))
|
if (strncmp(dev, "fuse", 4))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
strtol(dev + 4, &ep, 10);
|
strtol(dev + 4, &ep, 10);
|
||||||
if (*ep != '\0')
|
if (*ep != '\0')
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
do_unmount(dev, fd);
|
do_unmount(dev, fd);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if kernel is doing init in background */
|
/* Check if kernel is doing init in background */
|
||||||
static int init_backgrounded(void)
|
static int init_backgrounded(void)
|
||||||
{
|
{
|
||||||
unsigned ibg, len;
|
unsigned ibg, len;
|
||||||
|
|
||||||
len = sizeof(ibg);
|
len = sizeof(ibg);
|
||||||
|
|
||||||
if (sysctlbyname("vfs.fuse.init_backgrounded", &ibg, &len, NULL, 0))
|
if (sysctlbyname("vfs.fuse.init_backgrounded", &ibg, &len, NULL, 0))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return ibg;
|
return ibg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int fuse_mount_core(const char *mountpoint, const char *opts)
|
static int fuse_mount_core(const char *mountpoint, const char *opts)
|
||||||
{
|
{
|
||||||
const char *mountprog = FUSERMOUNT_PROG;
|
const char *mountprog = FUSERMOUNT_PROG;
|
||||||
int fd;
|
int fd;
|
||||||
char *fdnam, *dev;
|
char *fdnam, *dev;
|
||||||
pid_t pid, cpid;
|
pid_t pid, cpid;
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
fdnam = getenv("FUSE_DEV_FD");
|
fdnam = getenv("FUSE_DEV_FD");
|
||||||
|
|
||||||
if (fdnam) {
|
if (fdnam) {
|
||||||
char *ep;
|
char *ep;
|
||||||
|
|
||||||
fd = strtol(fdnam, &ep, 10);
|
fd = strtol(fdnam, &ep, 10);
|
||||||
|
|
||||||
if (*ep != '\0') {
|
if (*ep != '\0') {
|
||||||
fprintf(stderr, "invalid value given in FUSE_DEV_FD\n");
|
fprintf(stderr, "invalid value given in FUSE_DEV_FD\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
goto mount;
|
goto mount;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev = getenv("FUSE_DEV_NAME");
|
dev = getenv("FUSE_DEV_NAME");
|
||||||
|
|
||||||
if (! dev)
|
if (! dev)
|
||||||
dev = (char *)FUSE_DEV_TRUNK;
|
dev = (char *)FUSE_DEV_TRUNK;
|
||||||
|
|
||||||
if ((fd = open(dev, O_RDWR)) < 0) {
|
if ((fd = open(dev, O_RDWR)) < 0) {
|
||||||
perror("fuse: failed to open fuse device");
|
perror("fuse: failed to open fuse device");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
mount:
|
mount:
|
||||||
if (getenv("FUSE_NO_MOUNT") || ! mountpoint)
|
if (getenv("FUSE_NO_MOUNT") || ! mountpoint)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
pid = fork();
|
pid = fork();
|
||||||
cpid = pid;
|
cpid = pid;
|
||||||
|
|
||||||
if (pid == -1) {
|
if (pid == -1) {
|
||||||
perror("fuse: fork() failed");
|
perror("fuse: fork() failed");
|
||||||
close(fd);
|
close(fd);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pid == 0) {
|
if (pid == 0) {
|
||||||
if (! init_backgrounded()) {
|
if (! init_backgrounded()) {
|
||||||
/*
|
/*
|
||||||
* If init is not backgrounded, we have to
|
* If init is not backgrounded, we have to
|
||||||
* call the mount util backgrounded, to avoid
|
* call the mount util backgrounded, to avoid
|
||||||
* deadlock.
|
* deadlock.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pid = fork();
|
pid = fork();
|
||||||
|
|
||||||
if (pid == -1) {
|
if (pid == -1) {
|
||||||
perror("fuse: fork() failed");
|
perror("fuse: fork() failed");
|
||||||
close(fd);
|
close(fd);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pid == 0) {
|
if (pid == 0) {
|
||||||
const char *argv[32];
|
const char *argv[32];
|
||||||
int a = 0;
|
int a = 0;
|
||||||
|
|
||||||
if (! fdnam && asprintf(&fdnam, "%d", fd) == -1) {
|
if (! fdnam && asprintf(&fdnam, "%d", fd) == -1) {
|
||||||
perror("fuse: failed to assemble mount arguments");
|
perror("fuse: failed to assemble mount arguments");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
argv[a++] = mountprog;
|
argv[a++] = mountprog;
|
||||||
if (opts) {
|
if (opts) {
|
||||||
argv[a++] = "-o";
|
argv[a++] = "-o";
|
||||||
argv[a++] = opts;
|
argv[a++] = opts;
|
||||||
}
|
}
|
||||||
argv[a++] = fdnam;
|
argv[a++] = fdnam;
|
||||||
argv[a++] = mountpoint;
|
argv[a++] = mountpoint;
|
||||||
argv[a++] = NULL;
|
argv[a++] = NULL;
|
||||||
execvp(mountprog, (char **) argv);
|
execvp(mountprog, (char **) argv);
|
||||||
perror("fuse: failed to exec mount program");
|
perror("fuse: failed to exec mount program");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (waitpid(cpid, &status, 0) == -1 || WEXITSTATUS(status) != 0) {
|
if (waitpid(cpid, &status, 0) == -1 || WEXITSTATUS(status) != 0) {
|
||||||
perror("fuse: failed to mount file system");
|
perror("fuse: failed to mount file system");
|
||||||
close(fd);
|
close(fd);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fuse_kern_mount(const char *mountpoint, struct fuse_args *args)
|
int fuse_kern_mount(const char *mountpoint, struct fuse_args *args)
|
||||||
{
|
{
|
||||||
struct mount_opts mo;
|
struct mount_opts mo;
|
||||||
int res = -1;
|
int res = -1;
|
||||||
|
|
||||||
memset(&mo, 0, sizeof(mo));
|
memset(&mo, 0, sizeof(mo));
|
||||||
/* mount util should not try to spawn the daemon */
|
/* mount util should not try to spawn the daemon */
|
||||||
setenv("MOUNT_FUSEFS_SAFE", "1", 1);
|
setenv("MOUNT_FUSEFS_SAFE", "1", 1);
|
||||||
/* to notify the mount util it's called from lib */
|
/* to notify the mount util it's called from lib */
|
||||||
setenv("MOUNT_FUSEFS_CALL_BY_LIB", "1", 1);
|
setenv("MOUNT_FUSEFS_CALL_BY_LIB", "1", 1);
|
||||||
|
|
||||||
if (args &&
|
if (args &&
|
||||||
fuse_opt_parse(args, &mo, fuse_mount_opts, fuse_mount_opt_proc) == -1)
|
fuse_opt_parse(args, &mo, fuse_mount_opts, fuse_mount_opt_proc) == -1)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
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");
|
fprintf(stderr, "fuse: 'allow_other' and 'allow_root' options are mutually exclusive\n");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if (mo.ishelp)
|
if (mo.ishelp)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
res = fuse_mount_core(mountpoint, mo.kernel_opts);
|
res = fuse_mount_core(mountpoint, mo.kernel_opts);
|
||||||
out:
|
out:
|
||||||
free(mo.kernel_opts);
|
free(mo.kernel_opts);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
FUSE_SYMVER(".symver fuse_unmount_compat22,fuse_unmount@FUSE_2.2");
|
FUSE_SYMVER(".symver fuse_unmount_compat22,fuse_unmount@FUSE_2.2");
|
||||||
|
|||||||
+441
-450
File diff suppressed because it is too large
Load Diff
+240
-257
@@ -31,333 +31,316 @@
|
|||||||
#else
|
#else
|
||||||
static int mtab_needs_update(const char *mnt)
|
static int mtab_needs_update(const char *mnt)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
struct stat stbuf;
|
struct stat stbuf;
|
||||||
|
|
||||||
/* If mtab is within new mount, don't touch it */
|
/* If mtab is within new mount, don't touch it */
|
||||||
if (strncmp(mnt, _PATH_MOUNTED, strlen(mnt)) == 0 &&
|
if (strncmp(mnt, _PATH_MOUNTED, strlen(mnt)) == 0 &&
|
||||||
_PATH_MOUNTED[strlen(mnt)] == '/')
|
_PATH_MOUNTED[strlen(mnt)] == '/')
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Skip mtab update if /etc/mtab:
|
* Skip mtab update if /etc/mtab:
|
||||||
*
|
*
|
||||||
* - doesn't exist,
|
* - doesn't exist,
|
||||||
* - is a symlink,
|
* - is a symlink,
|
||||||
* - is on a read-only filesystem.
|
* - is on a read-only filesystem.
|
||||||
*/
|
*/
|
||||||
res = lstat(_PATH_MOUNTED, &stbuf);
|
res = lstat(_PATH_MOUNTED, &stbuf);
|
||||||
if (res == -1) {
|
if (res == -1) {
|
||||||
if (errno == ENOENT)
|
if (errno == ENOENT)
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
uid_t ruid;
|
uid_t ruid;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (S_ISLNK(stbuf.st_mode))
|
if (S_ISLNK(stbuf.st_mode))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
ruid = getuid();
|
ruid = getuid();
|
||||||
if (ruid != 0)
|
if (ruid != 0)
|
||||||
setreuid(0, -1);
|
setreuid(0, -1);
|
||||||
|
|
||||||
res = access(_PATH_MOUNTED, W_OK);
|
res = access(_PATH_MOUNTED, W_OK);
|
||||||
err = (res == -1) ? errno : 0;
|
err = (res == -1) ? errno : 0;
|
||||||
if (ruid != 0)
|
if (ruid != 0)
|
||||||
setreuid(ruid, -1);
|
setreuid(ruid, -1);
|
||||||
|
|
||||||
if (err == EROFS)
|
if (err == EROFS)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
#endif /* __NetBSD__ */
|
#endif /* __NetBSD__ */
|
||||||
|
|
||||||
static int add_mount(const char *progname, const char *fsname,
|
static int add_mount(const char *progname, const char *fsname,
|
||||||
const char *mnt, const char *type, const char *opts)
|
const char *mnt, const char *type, const char *opts)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
int status;
|
int status;
|
||||||
sigset_t blockmask;
|
sigset_t blockmask;
|
||||||
sigset_t oldmask;
|
sigset_t oldmask;
|
||||||
|
|
||||||
sigemptyset(&blockmask);
|
sigemptyset(&blockmask);
|
||||||
sigaddset(&blockmask, SIGCHLD);
|
sigaddset(&blockmask, SIGCHLD);
|
||||||
res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask);
|
res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask);
|
||||||
if (res == -1) {
|
if (res == -1) {
|
||||||
fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno));
|
fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
res = fork();
|
res = fork();
|
||||||
if (res == -1) {
|
if (res == -1) {
|
||||||
fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
|
fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
|
||||||
goto out_restore;
|
goto out_restore;
|
||||||
}
|
}
|
||||||
if (res == 0) {
|
if (res == 0) {
|
||||||
char *env = NULL;
|
char *env = NULL;
|
||||||
|
|
||||||
sigprocmask(SIG_SETMASK, &oldmask, NULL);
|
sigprocmask(SIG_SETMASK, &oldmask, NULL);
|
||||||
setuid(geteuid());
|
setuid(geteuid());
|
||||||
execle("/bin/mount", "/bin/mount", "--no-canonicalize", "-i",
|
execle("/bin/mount", "/bin/mount", "--no-canonicalize", "-i",
|
||||||
"-f", "-t", type, "-o", opts, fsname, mnt, NULL, &env);
|
"-f", "-t", type, "-o", opts, fsname, mnt, NULL, &env);
|
||||||
fprintf(stderr, "%s: failed to execute /bin/mount: %s\n",
|
fprintf(stderr, "%s: failed to execute /bin/mount: %s\n",
|
||||||
progname, strerror(errno));
|
progname, strerror(errno));
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
res = waitpid(res, &status, 0);
|
res = waitpid(res, &status, 0);
|
||||||
if (res == -1)
|
if (res == -1)
|
||||||
fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno));
|
fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno));
|
||||||
|
|
||||||
if (status != 0)
|
if (status != 0)
|
||||||
res = -1;
|
res = -1;
|
||||||
|
|
||||||
out_restore:
|
out_restore:
|
||||||
sigprocmask(SIG_SETMASK, &oldmask, NULL);
|
sigprocmask(SIG_SETMASK, &oldmask, NULL);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fuse_mnt_add_mount(const char *progname, const char *fsname,
|
int fuse_mnt_add_mount(const char *progname, const char *fsname,
|
||||||
const char *mnt, const char *type, const char *opts)
|
const char *mnt, const char *type, const char *opts)
|
||||||
{
|
{
|
||||||
if (!mtab_needs_update(mnt))
|
if (!mtab_needs_update(mnt))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return add_mount(progname, fsname, mnt, type, opts);
|
return add_mount(progname, fsname, mnt, type, opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int exec_umount(const char *progname, const char *rel_mnt, int lazy)
|
static int exec_umount(const char *progname, const char *rel_mnt, int lazy)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
int status;
|
int status;
|
||||||
sigset_t blockmask;
|
sigset_t blockmask;
|
||||||
sigset_t oldmask;
|
sigset_t oldmask;
|
||||||
|
|
||||||
sigemptyset(&blockmask);
|
sigemptyset(&blockmask);
|
||||||
sigaddset(&blockmask, SIGCHLD);
|
sigaddset(&blockmask, SIGCHLD);
|
||||||
res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask);
|
res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask);
|
||||||
if (res == -1) {
|
if (res == -1) {
|
||||||
fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno));
|
fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
res = fork();
|
res = fork();
|
||||||
if (res == -1) {
|
if (res == -1) {
|
||||||
fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
|
fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
|
||||||
goto out_restore;
|
goto out_restore;
|
||||||
}
|
}
|
||||||
if (res == 0) {
|
if (res == 0) {
|
||||||
char *env = NULL;
|
char *env = NULL;
|
||||||
|
|
||||||
sigprocmask(SIG_SETMASK, &oldmask, NULL);
|
sigprocmask(SIG_SETMASK, &oldmask, NULL);
|
||||||
setuid(geteuid());
|
setuid(geteuid());
|
||||||
if (lazy) {
|
if (lazy) {
|
||||||
execle("/bin/umount", "/bin/umount", "-i", rel_mnt,
|
execle("/bin/umount", "/bin/umount", "-i", rel_mnt,
|
||||||
"-l", NULL, &env);
|
"-l", NULL, &env);
|
||||||
} else {
|
} else {
|
||||||
execle("/bin/umount", "/bin/umount", "-i", rel_mnt,
|
execle("/bin/umount", "/bin/umount", "-i", rel_mnt,
|
||||||
NULL, &env);
|
NULL, &env);
|
||||||
}
|
}
|
||||||
fprintf(stderr, "%s: failed to execute /bin/umount: %s\n",
|
fprintf(stderr, "%s: failed to execute /bin/umount: %s\n",
|
||||||
progname, strerror(errno));
|
progname, strerror(errno));
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
res = waitpid(res, &status, 0);
|
res = waitpid(res, &status, 0);
|
||||||
if (res == -1)
|
if (res == -1)
|
||||||
fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno));
|
fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno));
|
||||||
|
|
||||||
if (status != 0) {
|
if (status != 0) {
|
||||||
res = -1;
|
res = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
out_restore:
|
out_restore:
|
||||||
sigprocmask(SIG_SETMASK, &oldmask, NULL);
|
sigprocmask(SIG_SETMASK, &oldmask, NULL);
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int fuse_mnt_umount(const char *progname, const char *abs_mnt,
|
int fuse_mnt_umount(const char *progname, const char *abs_mnt,
|
||||||
const char *rel_mnt, int lazy)
|
const char *rel_mnt, int lazy)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
if (!mtab_needs_update(abs_mnt)) {
|
if (!mtab_needs_update(abs_mnt)) {
|
||||||
res = umount2(rel_mnt, lazy ? 2 : 0);
|
res = umount2(rel_mnt, lazy ? 2 : 0);
|
||||||
if (res == -1)
|
if (res == -1)
|
||||||
fprintf(stderr, "%s: failed to unmount %s: %s\n",
|
fprintf(stderr, "%s: failed to unmount %s: %s\n",
|
||||||
progname, abs_mnt, strerror(errno));
|
progname, abs_mnt, strerror(errno));
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
return exec_umount(progname, rel_mnt, lazy);
|
return exec_umount(progname, rel_mnt, lazy);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int remove_mount(const char *progname, const char *mnt)
|
static int remove_mount(const char *progname, const char *mnt)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
int status;
|
int status;
|
||||||
sigset_t blockmask;
|
sigset_t blockmask;
|
||||||
sigset_t oldmask;
|
sigset_t oldmask;
|
||||||
|
|
||||||
sigemptyset(&blockmask);
|
sigemptyset(&blockmask);
|
||||||
sigaddset(&blockmask, SIGCHLD);
|
sigaddset(&blockmask, SIGCHLD);
|
||||||
res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask);
|
res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask);
|
||||||
if (res == -1) {
|
if (res == -1) {
|
||||||
fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno));
|
fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
res = fork();
|
res = fork();
|
||||||
if (res == -1) {
|
if (res == -1) {
|
||||||
fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
|
fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
|
||||||
goto out_restore;
|
goto out_restore;
|
||||||
}
|
}
|
||||||
if (res == 0) {
|
if (res == 0) {
|
||||||
char *env = NULL;
|
char *env = NULL;
|
||||||
|
|
||||||
sigprocmask(SIG_SETMASK, &oldmask, NULL);
|
sigprocmask(SIG_SETMASK, &oldmask, NULL);
|
||||||
setuid(geteuid());
|
setuid(geteuid());
|
||||||
execle("/bin/umount", "/bin/umount", "--no-canonicalize", "-i",
|
execle("/bin/umount", "/bin/umount", "--no-canonicalize", "-i",
|
||||||
"--fake", mnt, NULL, &env);
|
"--fake", mnt, NULL, &env);
|
||||||
fprintf(stderr, "%s: failed to execute /bin/umount: %s\n",
|
fprintf(stderr, "%s: failed to execute /bin/umount: %s\n",
|
||||||
progname, strerror(errno));
|
progname, strerror(errno));
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
res = waitpid(res, &status, 0);
|
res = waitpid(res, &status, 0);
|
||||||
if (res == -1)
|
if (res == -1)
|
||||||
fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno));
|
fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno));
|
||||||
|
|
||||||
if (status != 0)
|
if (status != 0)
|
||||||
res = -1;
|
res = -1;
|
||||||
|
|
||||||
out_restore:
|
out_restore:
|
||||||
sigprocmask(SIG_SETMASK, &oldmask, NULL);
|
sigprocmask(SIG_SETMASK, &oldmask, NULL);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fuse_mnt_remove_mount(const char *progname, const char *mnt)
|
int fuse_mnt_remove_mount(const char *progname, const char *mnt)
|
||||||
{
|
{
|
||||||
if (!mtab_needs_update(mnt))
|
if (!mtab_needs_update(mnt))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return remove_mount(progname, mnt);
|
return remove_mount(progname, mnt);
|
||||||
}
|
}
|
||||||
|
|
||||||
char *fuse_mnt_resolve_path(const char *progname, const char *orig)
|
char *fuse_mnt_resolve_path(const char *progname, const char *orig)
|
||||||
{
|
{
|
||||||
char buf[PATH_MAX];
|
char buf[PATH_MAX];
|
||||||
char *copy;
|
char *copy;
|
||||||
char *dst;
|
char *dst;
|
||||||
char *end;
|
char *end;
|
||||||
char *lastcomp;
|
char *lastcomp;
|
||||||
const char *toresolv;
|
const char *toresolv;
|
||||||
|
|
||||||
if (!orig[0]) {
|
if (!orig[0]) {
|
||||||
fprintf(stderr, "%s: invalid mountpoint '%s'\n", progname,
|
fprintf(stderr, "%s: invalid mountpoint '%s'\n", progname,
|
||||||
orig);
|
orig);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
copy = strdup(orig);
|
copy = strdup(orig);
|
||||||
if (copy == NULL) {
|
if (copy == NULL) {
|
||||||
fprintf(stderr, "%s: failed to allocate memory\n", progname);
|
fprintf(stderr, "%s: failed to allocate memory\n", progname);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
toresolv = copy;
|
toresolv = copy;
|
||||||
lastcomp = NULL;
|
lastcomp = NULL;
|
||||||
for (end = copy + strlen(copy) - 1; end > copy && *end == '/'; end --);
|
for (end = copy + strlen(copy) - 1; end > copy && *end == '/'; end --);
|
||||||
if (end[0] != '/') {
|
if (end[0] != '/') {
|
||||||
char *tmp;
|
char *tmp;
|
||||||
end[1] = '\0';
|
end[1] = '\0';
|
||||||
tmp = strrchr(copy, '/');
|
tmp = strrchr(copy, '/');
|
||||||
if (tmp == NULL) {
|
if (tmp == NULL) {
|
||||||
lastcomp = copy;
|
lastcomp = copy;
|
||||||
toresolv = ".";
|
toresolv = ".";
|
||||||
} else {
|
} else {
|
||||||
lastcomp = tmp + 1;
|
lastcomp = tmp + 1;
|
||||||
if (tmp == copy)
|
if (tmp == copy)
|
||||||
toresolv = "/";
|
toresolv = "/";
|
||||||
}
|
}
|
||||||
if (strcmp(lastcomp, ".") == 0 || strcmp(lastcomp, "..") == 0) {
|
if (strcmp(lastcomp, ".") == 0 || strcmp(lastcomp, "..") == 0) {
|
||||||
lastcomp = NULL;
|
lastcomp = NULL;
|
||||||
toresolv = copy;
|
toresolv = copy;
|
||||||
}
|
}
|
||||||
else if (tmp)
|
else if (tmp)
|
||||||
tmp[0] = '\0';
|
tmp[0] = '\0';
|
||||||
}
|
}
|
||||||
if (realpath(toresolv, buf) == NULL) {
|
if (realpath(toresolv, buf) == NULL) {
|
||||||
fprintf(stderr, "%s: bad mount point %s: %s\n", progname, orig,
|
fprintf(stderr, "%s: bad mount point %s: %s\n", progname, orig,
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
free(copy);
|
free(copy);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (lastcomp == NULL)
|
if (lastcomp == NULL)
|
||||||
dst = strdup(buf);
|
dst = strdup(buf);
|
||||||
else {
|
else {
|
||||||
dst = (char *) malloc(strlen(buf) + 1 + strlen(lastcomp) + 1);
|
dst = (char *) malloc(strlen(buf) + 1 + strlen(lastcomp) + 1);
|
||||||
if (dst) {
|
if (dst) {
|
||||||
unsigned buflen = strlen(buf);
|
unsigned buflen = strlen(buf);
|
||||||
if (buflen && buf[buflen-1] == '/')
|
if (buflen && buf[buflen-1] == '/')
|
||||||
sprintf(dst, "%s%s", buf, lastcomp);
|
sprintf(dst, "%s%s", buf, lastcomp);
|
||||||
else
|
else
|
||||||
sprintf(dst, "%s/%s", buf, lastcomp);
|
sprintf(dst, "%s/%s", buf, lastcomp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
free(copy);
|
free(copy);
|
||||||
if (dst == NULL)
|
if (dst == NULL)
|
||||||
fprintf(stderr, "%s: failed to allocate memory\n", progname);
|
fprintf(stderr, "%s: failed to allocate memory\n", progname);
|
||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fuse_mnt_check_empty(const char *progname, const char *mnt,
|
int fuse_mnt_check_empty(const char *progname, const char *mnt,
|
||||||
mode_t rootmode, off_t rootsize)
|
mode_t rootmode, off_t rootsize)
|
||||||
{
|
{
|
||||||
int isempty = 1;
|
int isempty = 1;
|
||||||
|
|
||||||
if (S_ISDIR(rootmode)) {
|
if (S_ISDIR(rootmode)) {
|
||||||
struct dirent *ent;
|
struct dirent *ent;
|
||||||
DIR *dp = opendir(mnt);
|
DIR *dp = opendir(mnt);
|
||||||
if (dp == NULL) {
|
if (dp == NULL) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"%s: failed to open mountpoint for reading: %s\n",
|
"%s: failed to open mountpoint for reading: %s\n",
|
||||||
progname, strerror(errno));
|
progname, strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
while ((ent = readdir(dp)) != NULL) {
|
while ((ent = readdir(dp)) != NULL) {
|
||||||
if (strcmp(ent->d_name, ".") != 0 &&
|
if (strcmp(ent->d_name, ".") != 0 &&
|
||||||
strcmp(ent->d_name, "..") != 0) {
|
strcmp(ent->d_name, "..") != 0) {
|
||||||
isempty = 0;
|
isempty = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
closedir(dp);
|
closedir(dp);
|
||||||
} else if (rootsize)
|
} else if (rootsize)
|
||||||
isempty = 0;
|
isempty = 0;
|
||||||
|
|
||||||
if (!isempty) {
|
if (!isempty) {
|
||||||
fprintf(stderr, "%s: mountpoint is not empty\n", progname);
|
fprintf(stderr, "%s: mountpoint is not empty\n", progname);
|
||||||
fprintf(stderr, "%s: if you are sure this is safe, use the 'nonempty' mount option\n", progname);
|
fprintf(stderr, "%s: if you are sure this is safe, use the 'nonempty' mount option\n", progname);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
int fuse_mnt_check_fuseblk(void)
|
|
||||||
{
|
|
||||||
char buf[256];
|
|
||||||
FILE *f = fopen("/proc/filesystems", "r");
|
|
||||||
if (!f)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
while (fgets(buf, sizeof(buf), f))
|
|
||||||
if (strstr(buf, "fuseblk\n")) {
|
|
||||||
fclose(f);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(f);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,4 +16,3 @@ int fuse_mnt_umount(const char *progname, const char *abs_mnt,
|
|||||||
char *fuse_mnt_resolve_path(const char *progname, const char *orig);
|
char *fuse_mnt_resolve_path(const char *progname, const char *orig);
|
||||||
int fuse_mnt_check_empty(const char *progname, const char *mnt,
|
int fuse_mnt_check_empty(const char *progname, const char *mnt,
|
||||||
mode_t rootmode, off_t rootsize);
|
mode_t rootmode, off_t rootsize);
|
||||||
int fuse_mnt_check_fuseblk(void);
|
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
#define _GNU_SOURCE
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
static
|
||||||
|
int
|
||||||
|
sys_get_pagesize_(void)
|
||||||
|
{
|
||||||
|
#ifdef _SC_PAGESIZE
|
||||||
|
return sysconf(_SC_PAGESIZE);
|
||||||
|
#else
|
||||||
|
return getpagesize();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
sys_get_pagesize(void)
|
||||||
|
{
|
||||||
|
static int pagesize = 0;
|
||||||
|
|
||||||
|
if(pagesize == 0)
|
||||||
|
pagesize = sys_get_pagesize_();
|
||||||
|
|
||||||
|
return pagesize;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
sys_alloc_pipe(int pipe_[2],
|
||||||
|
int bufsize_)
|
||||||
|
{
|
||||||
|
#ifdef F_SETPIPE_SZ
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
rv = pipe(pipe_);
|
||||||
|
if(rv == -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
rv = fcntl(pipe_[0],F_SETPIPE_SZ,bufsize_);
|
||||||
|
if(rv == -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
#else
|
||||||
|
errno = ENOSYS;
|
||||||
|
return -1;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
int sys_get_pagesize(void);
|
||||||
|
int sys_alloc_pipe(int p[2], int bufsize);
|
||||||
+319
-319
@@ -22,28 +22,28 @@
|
|||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
|
|
||||||
struct message {
|
struct message {
|
||||||
unsigned intr : 1;
|
unsigned intr : 1;
|
||||||
unsigned nofd : 1;
|
unsigned nofd : 1;
|
||||||
pthread_t thr;
|
pthread_t thr;
|
||||||
int cmd;
|
int cmd;
|
||||||
int fd;
|
int fd;
|
||||||
struct flock lock;
|
struct flock lock;
|
||||||
int error;
|
int error;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct fd_store {
|
struct fd_store {
|
||||||
struct fd_store *next;
|
struct fd_store *next;
|
||||||
int fd;
|
int fd;
|
||||||
int inuse;
|
int inuse;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct owner {
|
struct owner {
|
||||||
struct owner *next;
|
struct owner *next;
|
||||||
struct owner *prev;
|
struct owner *prev;
|
||||||
struct fd_store *fds;
|
struct fd_store *fds;
|
||||||
void *id;
|
void *id;
|
||||||
size_t id_len;
|
size_t id_len;
|
||||||
int cfd;
|
int cfd;
|
||||||
};
|
};
|
||||||
|
|
||||||
static pthread_mutex_t ulockmgr_lock;
|
static pthread_mutex_t ulockmgr_lock;
|
||||||
@@ -54,19 +54,19 @@ static struct owner owner_list = { .next = &owner_list, .prev = &owner_list };
|
|||||||
|
|
||||||
static void list_del_owner(struct owner *owner)
|
static void list_del_owner(struct owner *owner)
|
||||||
{
|
{
|
||||||
struct owner *prev = owner->prev;
|
struct owner *prev = owner->prev;
|
||||||
struct owner *next = owner->next;
|
struct owner *next = owner->next;
|
||||||
prev->next = next;
|
prev->next = next;
|
||||||
next->prev = prev;
|
next->prev = prev;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void list_add_owner(struct owner *owner, struct owner *next)
|
static void list_add_owner(struct owner *owner, struct owner *next)
|
||||||
{
|
{
|
||||||
struct owner *prev = next->prev;
|
struct owner *prev = next->prev;
|
||||||
owner->next = next;
|
owner->next = next;
|
||||||
owner->prev = prev;
|
owner->prev = prev;
|
||||||
prev->next = owner;
|
prev->next = owner;
|
||||||
next->prev = owner;
|
next->prev = owner;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -77,368 +77,368 @@ static void list_add_owner(struct owner *owner, struct owner *next)
|
|||||||
*/
|
*/
|
||||||
static int do_recv(int sock, void *buf, size_t len, int flags)
|
static int do_recv(int sock, void *buf, size_t len, int flags)
|
||||||
{
|
{
|
||||||
int res = recv(sock, buf, len, flags);
|
int res = recv(sock, buf, len, flags);
|
||||||
if (res == 0)
|
if (res == 0)
|
||||||
res = recv(sock, buf, len, flags);
|
res = recv(sock, buf, len, flags);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ulockmgr_send_message(int sock, void *buf, size_t buflen,
|
static int ulockmgr_send_message(int sock, void *buf, size_t buflen,
|
||||||
int *fdp, int numfds)
|
int *fdp, int numfds)
|
||||||
{
|
{
|
||||||
struct msghdr msg;
|
struct msghdr msg;
|
||||||
struct cmsghdr *p_cmsg;
|
struct cmsghdr *p_cmsg;
|
||||||
struct iovec vec;
|
struct iovec vec;
|
||||||
size_t cmsgbuf[CMSG_SPACE(sizeof(int) * MAX_SEND_FDS) / sizeof(size_t)];
|
size_t cmsgbuf[CMSG_SPACE(sizeof(int) * MAX_SEND_FDS) / sizeof(size_t)];
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
assert(numfds <= MAX_SEND_FDS);
|
assert(numfds <= MAX_SEND_FDS);
|
||||||
msg.msg_control = cmsgbuf;
|
msg.msg_control = cmsgbuf;
|
||||||
msg.msg_controllen = sizeof(cmsgbuf);
|
msg.msg_controllen = sizeof(cmsgbuf);
|
||||||
p_cmsg = CMSG_FIRSTHDR(&msg);
|
p_cmsg = CMSG_FIRSTHDR(&msg);
|
||||||
p_cmsg->cmsg_level = SOL_SOCKET;
|
p_cmsg->cmsg_level = SOL_SOCKET;
|
||||||
p_cmsg->cmsg_type = SCM_RIGHTS;
|
p_cmsg->cmsg_type = SCM_RIGHTS;
|
||||||
p_cmsg->cmsg_len = CMSG_LEN(sizeof(int) * numfds);
|
p_cmsg->cmsg_len = CMSG_LEN(sizeof(int) * numfds);
|
||||||
memcpy(CMSG_DATA(p_cmsg), fdp, sizeof(int) * numfds);
|
memcpy(CMSG_DATA(p_cmsg), fdp, sizeof(int) * numfds);
|
||||||
msg.msg_controllen = p_cmsg->cmsg_len;
|
msg.msg_controllen = p_cmsg->cmsg_len;
|
||||||
msg.msg_name = NULL;
|
msg.msg_name = NULL;
|
||||||
msg.msg_namelen = 0;
|
msg.msg_namelen = 0;
|
||||||
msg.msg_iov = &vec;
|
msg.msg_iov = &vec;
|
||||||
msg.msg_iovlen = 1;
|
msg.msg_iovlen = 1;
|
||||||
msg.msg_flags = 0;
|
msg.msg_flags = 0;
|
||||||
vec.iov_base = buf;
|
vec.iov_base = buf;
|
||||||
vec.iov_len = buflen;
|
vec.iov_len = buflen;
|
||||||
res = sendmsg(sock, &msg, MSG_NOSIGNAL);
|
res = sendmsg(sock, &msg, MSG_NOSIGNAL);
|
||||||
if (res == -1) {
|
if (res == -1) {
|
||||||
perror("libulockmgr: sendmsg");
|
perror("libulockmgr: sendmsg");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if ((size_t) res != buflen) {
|
if ((size_t) res != buflen) {
|
||||||
fprintf(stderr, "libulockmgr: sendmsg short\n");
|
fprintf(stderr, "libulockmgr: sendmsg short\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ulockmgr_start_daemon(void)
|
static int ulockmgr_start_daemon(void)
|
||||||
{
|
{
|
||||||
int sv[2];
|
int sv[2];
|
||||||
int res;
|
int res;
|
||||||
char tmp[64];
|
char tmp[64];
|
||||||
|
|
||||||
res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
|
res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
|
||||||
if (res == -1) {
|
if (res == -1) {
|
||||||
perror("libulockmgr: socketpair");
|
perror("libulockmgr: socketpair");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
snprintf(tmp, sizeof(tmp), "exec ulockmgr_server %i", sv[0]);
|
snprintf(tmp, sizeof(tmp), "exec ulockmgr_server %i", sv[0]);
|
||||||
res = system(tmp);
|
res = system(tmp);
|
||||||
close(sv[0]);
|
close(sv[0]);
|
||||||
if (res == -1 || !WIFEXITED(res) || WEXITSTATUS(res) != 0) {
|
if (res == -1 || !WIFEXITED(res) || WEXITSTATUS(res) != 0) {
|
||||||
close(sv[1]);
|
close(sv[1]);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
ulockmgr_cfd = sv[1];
|
ulockmgr_cfd = sv[1];
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct owner *ulockmgr_new_owner(const void *id, size_t id_len)
|
static struct owner *ulockmgr_new_owner(const void *id, size_t id_len)
|
||||||
{
|
{
|
||||||
int sv[2];
|
int sv[2];
|
||||||
int res;
|
int res;
|
||||||
char c = 'm';
|
char c = 'm';
|
||||||
struct owner *o;
|
struct owner *o;
|
||||||
|
|
||||||
if (ulockmgr_cfd == -1 && ulockmgr_start_daemon() == -1)
|
if (ulockmgr_cfd == -1 && ulockmgr_start_daemon() == -1)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
o = calloc(1, sizeof(struct owner) + id_len);
|
o = calloc(1, sizeof(struct owner) + id_len);
|
||||||
if (!o) {
|
if (!o) {
|
||||||
fprintf(stderr, "libulockmgr: failed to allocate memory\n");
|
fprintf(stderr, "libulockmgr: failed to allocate memory\n");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
o->id = o + 1;
|
o->id = o + 1;
|
||||||
o->id_len = id_len;
|
o->id_len = id_len;
|
||||||
res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
|
res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
|
||||||
if (res == -1) {
|
if (res == -1) {
|
||||||
perror("libulockmgr: socketpair");
|
perror("libulockmgr: socketpair");
|
||||||
goto out_free;
|
goto out_free;
|
||||||
}
|
}
|
||||||
res = ulockmgr_send_message(ulockmgr_cfd, &c, sizeof(c), &sv[0], 1);
|
res = ulockmgr_send_message(ulockmgr_cfd, &c, sizeof(c), &sv[0], 1);
|
||||||
close(sv[0]);
|
close(sv[0]);
|
||||||
if (res == -1) {
|
if (res == -1) {
|
||||||
close(ulockmgr_cfd);
|
close(ulockmgr_cfd);
|
||||||
ulockmgr_cfd = -1;
|
ulockmgr_cfd = -1;
|
||||||
goto out_close;
|
goto out_close;
|
||||||
}
|
}
|
||||||
|
|
||||||
o->cfd = sv[1];
|
o->cfd = sv[1];
|
||||||
memcpy(o->id, id, id_len);
|
memcpy(o->id, id, id_len);
|
||||||
list_add_owner(o, &owner_list);
|
list_add_owner(o, &owner_list);
|
||||||
|
|
||||||
return o;
|
return o;
|
||||||
|
|
||||||
out_close:
|
out_close:
|
||||||
close(sv[1]);
|
close(sv[1]);
|
||||||
out_free:
|
out_free:
|
||||||
free(o);
|
free(o);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ulockmgr_send_request(struct message *msg, const void *id,
|
static int ulockmgr_send_request(struct message *msg, const void *id,
|
||||||
size_t id_len)
|
size_t id_len)
|
||||||
{
|
{
|
||||||
int sv[2];
|
int sv[2];
|
||||||
int cfd;
|
int cfd;
|
||||||
struct owner *o;
|
struct owner *o;
|
||||||
struct fd_store *f = NULL;
|
struct fd_store *f = NULL;
|
||||||
struct fd_store *newf = NULL;
|
struct fd_store *newf = NULL;
|
||||||
struct fd_store **fp;
|
struct fd_store **fp;
|
||||||
int fd = msg->fd;
|
int fd = msg->fd;
|
||||||
int cmd = msg->cmd;
|
int cmd = msg->cmd;
|
||||||
int res;
|
int res;
|
||||||
int unlockall = (cmd == F_SETLK && msg->lock.l_type == F_UNLCK &&
|
int unlockall = (cmd == F_SETLK && msg->lock.l_type == F_UNLCK &&
|
||||||
msg->lock.l_start == 0 && msg->lock.l_len == 0);
|
msg->lock.l_start == 0 && msg->lock.l_len == 0);
|
||||||
|
|
||||||
for (o = owner_list.next; o != &owner_list; o = o->next)
|
for (o = owner_list.next; o != &owner_list; o = o->next)
|
||||||
if (o->id_len == id_len && memcmp(o->id, id, id_len) == 0)
|
if (o->id_len == id_len && memcmp(o->id, id, id_len) == 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (o == &owner_list)
|
if (o == &owner_list)
|
||||||
o = NULL;
|
o = NULL;
|
||||||
|
|
||||||
if (!o && cmd != F_GETLK && msg->lock.l_type != F_UNLCK)
|
if (!o && cmd != F_GETLK && msg->lock.l_type != F_UNLCK)
|
||||||
o = ulockmgr_new_owner(id, id_len);
|
o = ulockmgr_new_owner(id, id_len);
|
||||||
|
|
||||||
if (!o) {
|
if (!o) {
|
||||||
if (cmd == F_GETLK) {
|
if (cmd == F_GETLK) {
|
||||||
res = fcntl(msg->fd, F_GETLK, &msg->lock);
|
res = fcntl(msg->fd, F_GETLK, &msg->lock);
|
||||||
return (res == -1) ? -errno : 0;
|
return (res == -1) ? -errno : 0;
|
||||||
} else if (msg->lock.l_type == F_UNLCK)
|
} else if (msg->lock.l_type == F_UNLCK)
|
||||||
return 0;
|
return 0;
|
||||||
else
|
else
|
||||||
return -ENOLCK;
|
return -ENOLCK;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unlockall)
|
if (unlockall)
|
||||||
msg->nofd = 1;
|
msg->nofd = 1;
|
||||||
else {
|
else {
|
||||||
for (fp = &o->fds; *fp; fp = &(*fp)->next) {
|
for (fp = &o->fds; *fp; fp = &(*fp)->next) {
|
||||||
f = *fp;
|
f = *fp;
|
||||||
if (f->fd == fd) {
|
if (f->fd == fd) {
|
||||||
msg->nofd = 1;
|
msg->nofd = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!msg->nofd) {
|
if (!msg->nofd) {
|
||||||
newf = f = calloc(1, sizeof(struct fd_store));
|
newf = f = calloc(1, sizeof(struct fd_store));
|
||||||
if (!f) {
|
if (!f) {
|
||||||
fprintf(stderr, "libulockmgr: failed to allocate memory\n");
|
fprintf(stderr, "libulockmgr: failed to allocate memory\n");
|
||||||
return -ENOLCK;
|
return -ENOLCK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
|
res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
|
||||||
if (res == -1) {
|
if (res == -1) {
|
||||||
perror("libulockmgr: socketpair");
|
perror("libulockmgr: socketpair");
|
||||||
free(newf);
|
free(newf);
|
||||||
return -ENOLCK;
|
return -ENOLCK;
|
||||||
}
|
}
|
||||||
|
|
||||||
cfd = sv[1];
|
cfd = sv[1];
|
||||||
sv[1] = msg->fd;
|
sv[1] = msg->fd;
|
||||||
res = ulockmgr_send_message(o->cfd, msg, sizeof(struct message), sv,
|
res = ulockmgr_send_message(o->cfd, msg, sizeof(struct message), sv,
|
||||||
msg->nofd ? 1 : 2);
|
msg->nofd ? 1 : 2);
|
||||||
close(sv[0]);
|
close(sv[0]);
|
||||||
if (res == -1) {
|
if (res == -1) {
|
||||||
free(newf);
|
free(newf);
|
||||||
close(cfd);
|
close(cfd);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newf) {
|
if (newf) {
|
||||||
newf->fd = msg->fd;
|
newf->fd = msg->fd;
|
||||||
newf->next = o->fds;
|
newf->next = o->fds;
|
||||||
o->fds = newf;
|
o->fds = newf;
|
||||||
}
|
}
|
||||||
if (f)
|
if (f)
|
||||||
f->inuse++;
|
f->inuse++;
|
||||||
|
|
||||||
res = do_recv(cfd, msg, sizeof(struct message), MSG_WAITALL);
|
res = do_recv(cfd, msg, sizeof(struct message), MSG_WAITALL);
|
||||||
if (res == -1) {
|
if (res == -1) {
|
||||||
perror("libulockmgr: recv");
|
perror("libulockmgr: recv");
|
||||||
msg->error = EIO;
|
msg->error = EIO;
|
||||||
} else if (res != sizeof(struct message)) {
|
} else if (res != sizeof(struct message)) {
|
||||||
fprintf(stderr, "libulockmgr: recv short\n");
|
fprintf(stderr, "libulockmgr: recv short\n");
|
||||||
msg->error = EIO;
|
msg->error = EIO;
|
||||||
} else if (cmd == F_SETLKW && msg->error == EAGAIN) {
|
} else if (cmd == F_SETLKW && msg->error == EAGAIN) {
|
||||||
pthread_mutex_unlock(&ulockmgr_lock);
|
pthread_mutex_unlock(&ulockmgr_lock);
|
||||||
while (1) {
|
while (1) {
|
||||||
sigset_t old;
|
sigset_t old;
|
||||||
sigset_t unblock;
|
sigset_t unblock;
|
||||||
int errno_save;
|
int errno_save;
|
||||||
|
|
||||||
sigemptyset(&unblock);
|
sigemptyset(&unblock);
|
||||||
sigaddset(&unblock, SIGUSR1);
|
sigaddset(&unblock, SIGUSR1);
|
||||||
pthread_sigmask(SIG_UNBLOCK, &unblock, &old);
|
pthread_sigmask(SIG_UNBLOCK, &unblock, &old);
|
||||||
res = do_recv(cfd, msg, sizeof(struct message),
|
res = do_recv(cfd, msg, sizeof(struct message),
|
||||||
MSG_WAITALL);
|
MSG_WAITALL);
|
||||||
errno_save = errno;
|
errno_save = errno;
|
||||||
pthread_sigmask(SIG_SETMASK, &old, NULL);
|
pthread_sigmask(SIG_SETMASK, &old, NULL);
|
||||||
if (res == sizeof(struct message))
|
if (res == sizeof(struct message))
|
||||||
break;
|
break;
|
||||||
else if (res >= 0) {
|
else if (res >= 0) {
|
||||||
fprintf(stderr, "libulockmgr: recv short\n");
|
fprintf(stderr, "libulockmgr: recv short\n");
|
||||||
msg->error = EIO;
|
msg->error = EIO;
|
||||||
break;
|
break;
|
||||||
} else if (errno_save != EINTR) {
|
} else if (errno_save != EINTR) {
|
||||||
errno = errno_save;
|
errno = errno_save;
|
||||||
perror("libulockmgr: recv");
|
perror("libulockmgr: recv");
|
||||||
msg->error = EIO;
|
msg->error = EIO;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
msg->intr = 1;
|
msg->intr = 1;
|
||||||
res = send(o->cfd, msg, sizeof(struct message),
|
res = send(o->cfd, msg, sizeof(struct message),
|
||||||
MSG_NOSIGNAL);
|
MSG_NOSIGNAL);
|
||||||
if (res == -1) {
|
if (res == -1) {
|
||||||
perror("libulockmgr: send");
|
perror("libulockmgr: send");
|
||||||
msg->error = EIO;
|
msg->error = EIO;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (res != sizeof(struct message)) {
|
if (res != sizeof(struct message)) {
|
||||||
fprintf(stderr, "libulockmgr: send short\n");
|
fprintf(stderr, "libulockmgr: send short\n");
|
||||||
msg->error = EIO;
|
msg->error = EIO;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pthread_mutex_lock(&ulockmgr_lock);
|
pthread_mutex_lock(&ulockmgr_lock);
|
||||||
|
|
||||||
}
|
}
|
||||||
if (f)
|
if (f)
|
||||||
f->inuse--;
|
f->inuse--;
|
||||||
close(cfd);
|
close(cfd);
|
||||||
if (unlockall) {
|
if (unlockall) {
|
||||||
for (fp = &o->fds; *fp;) {
|
for (fp = &o->fds; *fp;) {
|
||||||
f = *fp;
|
f = *fp;
|
||||||
if (f->fd == fd && !f->inuse) {
|
if (f->fd == fd && !f->inuse) {
|
||||||
*fp = f->next;
|
*fp = f->next;
|
||||||
free(f);
|
free(f);
|
||||||
} else
|
} else
|
||||||
fp = &f->next;
|
fp = &f->next;
|
||||||
}
|
}
|
||||||
if (!o->fds) {
|
if (!o->fds) {
|
||||||
list_del_owner(o);
|
list_del_owner(o);
|
||||||
close(o->cfd);
|
close(o->cfd);
|
||||||
free(o);
|
free(o);
|
||||||
}
|
}
|
||||||
/* Force OK on unlock-all, since it _will_ succeed once the
|
/* Force OK on unlock-all, since it _will_ succeed once the
|
||||||
owner is deleted */
|
owner is deleted */
|
||||||
msg->error = 0;
|
msg->error = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return -msg->error;
|
return -msg->error;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
static uint32_t owner_hash(const unsigned char *id, size_t id_len)
|
static uint32_t owner_hash(const unsigned char *id, size_t id_len)
|
||||||
{
|
{
|
||||||
uint32_t h = 0;
|
uint32_t h = 0;
|
||||||
size_t i;
|
size_t i;
|
||||||
for (i = 0; i < id_len; i++)
|
for (i = 0; i < id_len; i++)
|
||||||
h = ((h << 8) | (h >> 24)) ^ id[i];
|
h = ((h << 8) | (h >> 24)) ^ id[i];
|
||||||
|
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int ulockmgr_canonicalize(int fd, struct flock *lock)
|
static int ulockmgr_canonicalize(int fd, struct flock *lock)
|
||||||
{
|
{
|
||||||
off_t offset;
|
off_t offset;
|
||||||
if (lock->l_whence == SEEK_CUR) {
|
if (lock->l_whence == SEEK_CUR) {
|
||||||
offset = lseek(fd, 0, SEEK_CUR);
|
offset = lseek(fd, 0, SEEK_CUR);
|
||||||
if (offset == (off_t) -1)
|
if (offset == (off_t) -1)
|
||||||
return -errno;
|
return -errno;
|
||||||
} else if (lock->l_whence == SEEK_END) {
|
} else if (lock->l_whence == SEEK_END) {
|
||||||
struct stat stbuf;
|
struct stat stbuf;
|
||||||
int res = fstat(fd, &stbuf);
|
int res = fstat(fd, &stbuf);
|
||||||
if (res == -1)
|
if (res == -1)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
offset = stbuf.st_size;
|
offset = stbuf.st_size;
|
||||||
} else
|
} else
|
||||||
offset = 0;
|
offset = 0;
|
||||||
|
|
||||||
lock->l_whence = SEEK_SET;
|
lock->l_whence = SEEK_SET;
|
||||||
lock->l_start += offset;
|
lock->l_start += offset;
|
||||||
|
|
||||||
if (lock->l_start < 0)
|
if (lock->l_start < 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (lock->l_len < 0) {
|
if (lock->l_len < 0) {
|
||||||
lock->l_start += lock->l_len;
|
lock->l_start += lock->l_len;
|
||||||
if (lock->l_start < 0)
|
if (lock->l_start < 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
lock->l_len = -lock->l_len;
|
lock->l_len = -lock->l_len;
|
||||||
}
|
}
|
||||||
if (lock->l_len && lock->l_start + lock->l_len - 1 < 0)
|
if (lock->l_len && lock->l_start + lock->l_len - 1 < 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ulockmgr_op(int fd, int cmd, struct flock *lock, const void *owner,
|
int ulockmgr_op(int fd, int cmd, struct flock *lock, const void *owner,
|
||||||
size_t owner_len)
|
size_t owner_len)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
struct message msg;
|
struct message msg;
|
||||||
sigset_t old;
|
sigset_t old;
|
||||||
sigset_t block;
|
sigset_t block;
|
||||||
|
|
||||||
if (cmd != F_GETLK && cmd != F_SETLK && cmd != F_SETLKW)
|
if (cmd != F_GETLK && cmd != F_SETLK && cmd != F_SETLKW)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (lock->l_type != F_RDLCK && lock->l_type != F_WRLCK &&
|
if (lock->l_type != F_RDLCK && lock->l_type != F_WRLCK &&
|
||||||
lock->l_type != F_UNLCK)
|
lock->l_type != F_UNLCK)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (lock->l_whence != SEEK_SET && lock->l_whence != SEEK_CUR &&
|
if (lock->l_whence != SEEK_SET && lock->l_whence != SEEK_CUR &&
|
||||||
lock->l_whence != SEEK_END)
|
lock->l_whence != SEEK_END)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
fprintf(stderr, "libulockmgr: %i %i %i %lli %lli own: 0x%08x\n",
|
fprintf(stderr, "libulockmgr: %i %i %i %lli %lli own: 0x%08x\n",
|
||||||
cmd, lock->l_type, lock->l_whence, lock->l_start, lock->l_len,
|
cmd, lock->l_type, lock->l_whence, lock->l_start, lock->l_len,
|
||||||
owner_hash(owner, owner_len));
|
owner_hash(owner, owner_len));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Unlock should never block anyway */
|
/* Unlock should never block anyway */
|
||||||
if (cmd == F_SETLKW && lock->l_type == F_UNLCK)
|
if (cmd == F_SETLKW && lock->l_type == F_UNLCK)
|
||||||
cmd = F_SETLK;
|
cmd = F_SETLK;
|
||||||
|
|
||||||
memset(&msg, 0, sizeof(struct message));
|
memset(&msg, 0, sizeof(struct message));
|
||||||
msg.cmd = cmd;
|
msg.cmd = cmd;
|
||||||
msg.fd = fd;
|
msg.fd = fd;
|
||||||
msg.lock = *lock;
|
msg.lock = *lock;
|
||||||
err = ulockmgr_canonicalize(fd, &msg.lock);
|
err = ulockmgr_canonicalize(fd, &msg.lock);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
sigemptyset(&block);
|
sigemptyset(&block);
|
||||||
sigaddset(&block, SIGUSR1);
|
sigaddset(&block, SIGUSR1);
|
||||||
pthread_sigmask(SIG_BLOCK, &block, &old);
|
pthread_sigmask(SIG_BLOCK, &block, &old);
|
||||||
pthread_mutex_lock(&ulockmgr_lock);
|
pthread_mutex_lock(&ulockmgr_lock);
|
||||||
err = ulockmgr_send_request(&msg, owner, owner_len);
|
err = ulockmgr_send_request(&msg, owner, owner_len);
|
||||||
pthread_mutex_unlock(&ulockmgr_lock);
|
pthread_mutex_unlock(&ulockmgr_lock);
|
||||||
pthread_sigmask(SIG_SETMASK, &old, NULL);
|
pthread_sigmask(SIG_SETMASK, &old, NULL);
|
||||||
if (!err && cmd == F_GETLK) {
|
if (!err && cmd == F_GETLK) {
|
||||||
if (msg.lock.l_type == F_UNLCK)
|
if (msg.lock.l_type == F_UNLCK)
|
||||||
lock->l_type = F_UNLCK;
|
lock->l_type = F_UNLCK;
|
||||||
else
|
else
|
||||||
*lock = msg.lock;
|
*lock = msg.lock;
|
||||||
}
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|||||||
+946
-961
File diff suppressed because it is too large
Load Diff
+173
-177
@@ -16,216 +16,212 @@ static char *progname;
|
|||||||
|
|
||||||
static char *xstrdup(const char *s)
|
static char *xstrdup(const char *s)
|
||||||
{
|
{
|
||||||
char *t = strdup(s);
|
char *t = strdup(s);
|
||||||
if (!t) {
|
if (!t) {
|
||||||
fprintf(stderr, "%s: failed to allocate memory\n", progname);
|
fprintf(stderr, "%s: failed to allocate memory\n", progname);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *xrealloc(void *oldptr, size_t size)
|
static void *xrealloc(void *oldptr, size_t size)
|
||||||
{
|
{
|
||||||
void *ptr = realloc(oldptr, size);
|
void *ptr = realloc(oldptr, size);
|
||||||
if (!ptr) {
|
if (!ptr) {
|
||||||
fprintf(stderr, "%s: failed to allocate memory\n", progname);
|
fprintf(stderr, "%s: failed to allocate memory\n", progname);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void add_arg(char **cmdp, const char *opt)
|
static void add_arg(char **cmdp, const char *opt)
|
||||||
{
|
{
|
||||||
size_t optlen = strlen(opt);
|
size_t optlen = strlen(opt);
|
||||||
size_t cmdlen = *cmdp ? strlen(*cmdp) : 0;
|
size_t cmdlen = *cmdp ? strlen(*cmdp) : 0;
|
||||||
char *cmd = xrealloc(*cmdp, cmdlen + optlen * 4 + 4);
|
char *cmd = xrealloc(*cmdp, cmdlen + optlen * 4 + 4);
|
||||||
char *s;
|
char *s;
|
||||||
s = cmd + cmdlen;
|
s = cmd + cmdlen;
|
||||||
if (*cmdp)
|
if (*cmdp)
|
||||||
*s++ = ' ';
|
*s++ = ' ';
|
||||||
|
|
||||||
*s++ = '\'';
|
*s++ = '\'';
|
||||||
for (; *opt; opt++) {
|
for (; *opt; opt++) {
|
||||||
if (*opt == '\'') {
|
if (*opt == '\'') {
|
||||||
*s++ = '\'';
|
*s++ = '\'';
|
||||||
*s++ = '\\';
|
*s++ = '\\';
|
||||||
*s++ = '\'';
|
*s++ = '\'';
|
||||||
*s++ = '\'';
|
*s++ = '\'';
|
||||||
} else
|
} else
|
||||||
*s++ = *opt;
|
*s++ = *opt;
|
||||||
}
|
}
|
||||||
*s++ = '\'';
|
*s++ = '\'';
|
||||||
*s = '\0';
|
*s = '\0';
|
||||||
*cmdp = cmd;
|
*cmdp = cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *add_option(const char *opt, char *options)
|
static char *add_option(const char *opt, char *options)
|
||||||
{
|
{
|
||||||
int oldlen = options ? strlen(options) : 0;
|
int oldlen = options ? strlen(options) : 0;
|
||||||
|
|
||||||
options = xrealloc(options, oldlen + 1 + strlen(opt) + 1);
|
options = xrealloc(options, oldlen + 1 + strlen(opt) + 1);
|
||||||
if (!oldlen)
|
if (!oldlen)
|
||||||
strcpy(options, opt);
|
strcpy(options, opt);
|
||||||
else {
|
else {
|
||||||
strcat(options, ",");
|
strcat(options, ",");
|
||||||
strcat(options, opt);
|
strcat(options, opt);
|
||||||
}
|
}
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
char *type = NULL;
|
char *type = NULL;
|
||||||
char *source;
|
char *source;
|
||||||
const char *mountpoint;
|
const char *mountpoint;
|
||||||
char *basename;
|
char *basename;
|
||||||
char *options = NULL;
|
char *options = NULL;
|
||||||
char *command = NULL;
|
char *command = NULL;
|
||||||
char *setuid = NULL;
|
char *setuid = NULL;
|
||||||
int i;
|
int i;
|
||||||
int dev = 1;
|
int dev = 1;
|
||||||
int suid = 1;
|
int suid = 1;
|
||||||
|
|
||||||
progname = argv[0];
|
progname = argv[0];
|
||||||
basename = strrchr(argv[0], '/');
|
basename = strrchr(argv[0], '/');
|
||||||
if (basename)
|
if (basename)
|
||||||
basename++;
|
basename++;
|
||||||
else
|
else
|
||||||
basename = argv[0];
|
basename = argv[0];
|
||||||
|
|
||||||
type = "mergerfs";
|
type = "mergerfs";
|
||||||
if (strncmp(basename, "mount.fuse.", 11) == 0)
|
if (strncmp(basename, "mount.fuse.", 11) == 0)
|
||||||
type = basename + 11;
|
type = basename + 11;
|
||||||
if (strncmp(basename, "mount.fuseblk.", 14) == 0)
|
|
||||||
type = basename + 14;
|
|
||||||
|
|
||||||
if (type && !type[0])
|
if (type && !type[0])
|
||||||
type = NULL;
|
type = NULL;
|
||||||
|
|
||||||
if (argc < 3) {
|
if (argc < 3) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"usage: %s %s destination [-t type] [-o opt[,opts...]]\n",
|
"usage: %s %s destination [-t type] [-o opt[,opts...]]\n",
|
||||||
progname, type ? "source" : "type#[source]");
|
progname, type ? "source" : "type#[source]");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
source = argv[1];
|
source = argv[1];
|
||||||
if (!source[0])
|
if (!source[0])
|
||||||
source = NULL;
|
source = NULL;
|
||||||
|
|
||||||
mountpoint = argv[2];
|
mountpoint = argv[2];
|
||||||
|
|
||||||
for (i = 3; i < argc; i++) {
|
for (i = 3; i < argc; i++) {
|
||||||
if (strcmp(argv[i], "-v") == 0) {
|
if (strcmp(argv[i], "-v") == 0) {
|
||||||
continue;
|
continue;
|
||||||
} else if (strcmp(argv[i], "-t") == 0) {
|
} else if (strcmp(argv[i], "-t") == 0) {
|
||||||
i++;
|
i++;
|
||||||
|
|
||||||
if (i == argc) {
|
if (i == argc) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"%s: missing argument to option '-t'\n",
|
"%s: missing argument to option '-t'\n",
|
||||||
progname);
|
progname);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
type = argv[i];
|
type = argv[i];
|
||||||
if (strncmp(type, "fuse.", 5) == 0)
|
if (strncmp(type, "fuse.", 5) == 0)
|
||||||
type += 5;
|
type += 5;
|
||||||
else if (strncmp(type, "fuseblk.", 8) == 0)
|
|
||||||
type += 8;
|
|
||||||
|
|
||||||
if (!type[0]) {
|
if (!type[0]) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"%s: empty type given as argument to option '-t'\n",
|
"%s: empty type given as argument to option '-t'\n",
|
||||||
progname);
|
progname);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
} else if (strcmp(argv[i], "-o") == 0) {
|
} else if (strcmp(argv[i], "-o") == 0) {
|
||||||
char *opts;
|
char *opts;
|
||||||
char *opt;
|
char *opt;
|
||||||
i++;
|
i++;
|
||||||
if (i == argc)
|
if (i == argc)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
opts = xstrdup(argv[i]);
|
opts = xstrdup(argv[i]);
|
||||||
opt = strtok(opts, ",");
|
opt = strtok(opts, ",");
|
||||||
while (opt) {
|
while (opt) {
|
||||||
int j;
|
int j;
|
||||||
int ignore = 0;
|
int ignore = 0;
|
||||||
const char *ignore_opts[] = { "",
|
const char *ignore_opts[] = { "",
|
||||||
"user",
|
"user",
|
||||||
"nouser",
|
"nouser",
|
||||||
"users",
|
"users",
|
||||||
"auto",
|
"auto",
|
||||||
"noauto",
|
"noauto",
|
||||||
"_netdev",
|
"_netdev",
|
||||||
NULL};
|
NULL};
|
||||||
if (strncmp(opt, "setuid=", 7) == 0) {
|
if (strncmp(opt, "setuid=", 7) == 0) {
|
||||||
setuid = xstrdup(opt + 7);
|
setuid = xstrdup(opt + 7);
|
||||||
ignore = 1;
|
ignore = 1;
|
||||||
}
|
}
|
||||||
for (j = 0; ignore_opts[j]; j++)
|
for (j = 0; ignore_opts[j]; j++)
|
||||||
if (strcmp(opt, ignore_opts[j]) == 0)
|
if (strcmp(opt, ignore_opts[j]) == 0)
|
||||||
ignore = 1;
|
ignore = 1;
|
||||||
|
|
||||||
if (!ignore) {
|
if (!ignore) {
|
||||||
if (strcmp(opt, "nodev") == 0)
|
if (strcmp(opt, "nodev") == 0)
|
||||||
dev = 0;
|
dev = 0;
|
||||||
else if (strcmp(opt, "nosuid") == 0)
|
else if (strcmp(opt, "nosuid") == 0)
|
||||||
suid = 0;
|
suid = 0;
|
||||||
|
|
||||||
options = add_option(opt, options);
|
options = add_option(opt, options);
|
||||||
}
|
}
|
||||||
opt = strtok(NULL, ",");
|
opt = strtok(NULL, ",");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dev)
|
if (dev)
|
||||||
options = add_option("dev", options);
|
options = add_option("dev", options);
|
||||||
if (suid)
|
if (suid)
|
||||||
options = add_option("suid", options);
|
options = add_option("suid", options);
|
||||||
|
|
||||||
if (!type) {
|
if (!type) {
|
||||||
if (source) {
|
if (source) {
|
||||||
type = xstrdup(source);
|
type = xstrdup(source);
|
||||||
source = strchr(type, '#');
|
source = strchr(type, '#');
|
||||||
if (source)
|
if (source)
|
||||||
*source++ = '\0';
|
*source++ = '\0';
|
||||||
if (!type[0]) {
|
if (!type[0]) {
|
||||||
fprintf(stderr, "%s: empty filesystem type\n",
|
fprintf(stderr, "%s: empty filesystem type\n",
|
||||||
progname);
|
progname);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "%s: empty source\n", progname);
|
fprintf(stderr, "%s: empty source\n", progname);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
add_arg(&command, type);
|
add_arg(&command, type);
|
||||||
if (source)
|
if (source)
|
||||||
add_arg(&command, source);
|
add_arg(&command, source);
|
||||||
add_arg(&command, mountpoint);
|
add_arg(&command, mountpoint);
|
||||||
if (options) {
|
if (options) {
|
||||||
add_arg(&command, "-o");
|
add_arg(&command, "-o");
|
||||||
add_arg(&command, options);
|
add_arg(&command, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (setuid && setuid[0]) {
|
if (setuid && setuid[0]) {
|
||||||
char *sucommand = command;
|
char *sucommand = command;
|
||||||
command = NULL;
|
command = NULL;
|
||||||
add_arg(&command, "su");
|
add_arg(&command, "su");
|
||||||
add_arg(&command, "-");
|
add_arg(&command, "-");
|
||||||
add_arg(&command, setuid);
|
add_arg(&command, setuid);
|
||||||
add_arg(&command, "-c");
|
add_arg(&command, "-c");
|
||||||
add_arg(&command, sucommand);
|
add_arg(&command, sucommand);
|
||||||
} else if (!getenv("HOME")) {
|
} else if (!getenv("HOME")) {
|
||||||
/* Hack to make filesystems work in the boot environment */
|
/* Hack to make filesystems work in the boot environment */
|
||||||
setenv("HOME", "/root", 0);
|
setenv("HOME", "/root", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
execl("/bin/sh", "/bin/sh", "-c", command, NULL);
|
execl("/bin/sh", "/bin/sh", "-c", command, NULL);
|
||||||
fprintf(stderr, "%s: failed to execute /bin/sh: %s\n", progname,
|
fprintf(stderr, "%s: failed to execute /bin/sh: %s\n", progname,
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
+240
-257
@@ -31,333 +31,316 @@
|
|||||||
#else
|
#else
|
||||||
static int mtab_needs_update(const char *mnt)
|
static int mtab_needs_update(const char *mnt)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
struct stat stbuf;
|
struct stat stbuf;
|
||||||
|
|
||||||
/* If mtab is within new mount, don't touch it */
|
/* If mtab is within new mount, don't touch it */
|
||||||
if (strncmp(mnt, _PATH_MOUNTED, strlen(mnt)) == 0 &&
|
if (strncmp(mnt, _PATH_MOUNTED, strlen(mnt)) == 0 &&
|
||||||
_PATH_MOUNTED[strlen(mnt)] == '/')
|
_PATH_MOUNTED[strlen(mnt)] == '/')
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Skip mtab update if /etc/mtab:
|
* Skip mtab update if /etc/mtab:
|
||||||
*
|
*
|
||||||
* - doesn't exist,
|
* - doesn't exist,
|
||||||
* - is a symlink,
|
* - is a symlink,
|
||||||
* - is on a read-only filesystem.
|
* - is on a read-only filesystem.
|
||||||
*/
|
*/
|
||||||
res = lstat(_PATH_MOUNTED, &stbuf);
|
res = lstat(_PATH_MOUNTED, &stbuf);
|
||||||
if (res == -1) {
|
if (res == -1) {
|
||||||
if (errno == ENOENT)
|
if (errno == ENOENT)
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
uid_t ruid;
|
uid_t ruid;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (S_ISLNK(stbuf.st_mode))
|
if (S_ISLNK(stbuf.st_mode))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
ruid = getuid();
|
ruid = getuid();
|
||||||
if (ruid != 0)
|
if (ruid != 0)
|
||||||
setreuid(0, -1);
|
setreuid(0, -1);
|
||||||
|
|
||||||
res = access(_PATH_MOUNTED, W_OK);
|
res = access(_PATH_MOUNTED, W_OK);
|
||||||
err = (res == -1) ? errno : 0;
|
err = (res == -1) ? errno : 0;
|
||||||
if (ruid != 0)
|
if (ruid != 0)
|
||||||
setreuid(ruid, -1);
|
setreuid(ruid, -1);
|
||||||
|
|
||||||
if (err == EROFS)
|
if (err == EROFS)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
#endif /* __NetBSD__ */
|
#endif /* __NetBSD__ */
|
||||||
|
|
||||||
static int add_mount(const char *progname, const char *fsname,
|
static int add_mount(const char *progname, const char *fsname,
|
||||||
const char *mnt, const char *type, const char *opts)
|
const char *mnt, const char *type, const char *opts)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
int status;
|
int status;
|
||||||
sigset_t blockmask;
|
sigset_t blockmask;
|
||||||
sigset_t oldmask;
|
sigset_t oldmask;
|
||||||
|
|
||||||
sigemptyset(&blockmask);
|
sigemptyset(&blockmask);
|
||||||
sigaddset(&blockmask, SIGCHLD);
|
sigaddset(&blockmask, SIGCHLD);
|
||||||
res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask);
|
res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask);
|
||||||
if (res == -1) {
|
if (res == -1) {
|
||||||
fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno));
|
fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
res = fork();
|
res = fork();
|
||||||
if (res == -1) {
|
if (res == -1) {
|
||||||
fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
|
fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
|
||||||
goto out_restore;
|
goto out_restore;
|
||||||
}
|
}
|
||||||
if (res == 0) {
|
if (res == 0) {
|
||||||
char *env = NULL;
|
char *env = NULL;
|
||||||
|
|
||||||
sigprocmask(SIG_SETMASK, &oldmask, NULL);
|
sigprocmask(SIG_SETMASK, &oldmask, NULL);
|
||||||
setuid(geteuid());
|
setuid(geteuid());
|
||||||
execle("/bin/mount", "/bin/mount", "--no-canonicalize", "-i",
|
execle("/bin/mount", "/bin/mount", "--no-canonicalize", "-i",
|
||||||
"-f", "-t", type, "-o", opts, fsname, mnt, NULL, &env);
|
"-f", "-t", type, "-o", opts, fsname, mnt, NULL, &env);
|
||||||
fprintf(stderr, "%s: failed to execute /bin/mount: %s\n",
|
fprintf(stderr, "%s: failed to execute /bin/mount: %s\n",
|
||||||
progname, strerror(errno));
|
progname, strerror(errno));
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
res = waitpid(res, &status, 0);
|
res = waitpid(res, &status, 0);
|
||||||
if (res == -1)
|
if (res == -1)
|
||||||
fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno));
|
fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno));
|
||||||
|
|
||||||
if (status != 0)
|
if (status != 0)
|
||||||
res = -1;
|
res = -1;
|
||||||
|
|
||||||
out_restore:
|
out_restore:
|
||||||
sigprocmask(SIG_SETMASK, &oldmask, NULL);
|
sigprocmask(SIG_SETMASK, &oldmask, NULL);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fuse_mnt_add_mount(const char *progname, const char *fsname,
|
int fuse_mnt_add_mount(const char *progname, const char *fsname,
|
||||||
const char *mnt, const char *type, const char *opts)
|
const char *mnt, const char *type, const char *opts)
|
||||||
{
|
{
|
||||||
if (!mtab_needs_update(mnt))
|
if (!mtab_needs_update(mnt))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return add_mount(progname, fsname, mnt, type, opts);
|
return add_mount(progname, fsname, mnt, type, opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int exec_umount(const char *progname, const char *rel_mnt, int lazy)
|
static int exec_umount(const char *progname, const char *rel_mnt, int lazy)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
int status;
|
int status;
|
||||||
sigset_t blockmask;
|
sigset_t blockmask;
|
||||||
sigset_t oldmask;
|
sigset_t oldmask;
|
||||||
|
|
||||||
sigemptyset(&blockmask);
|
sigemptyset(&blockmask);
|
||||||
sigaddset(&blockmask, SIGCHLD);
|
sigaddset(&blockmask, SIGCHLD);
|
||||||
res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask);
|
res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask);
|
||||||
if (res == -1) {
|
if (res == -1) {
|
||||||
fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno));
|
fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
res = fork();
|
res = fork();
|
||||||
if (res == -1) {
|
if (res == -1) {
|
||||||
fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
|
fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
|
||||||
goto out_restore;
|
goto out_restore;
|
||||||
}
|
}
|
||||||
if (res == 0) {
|
if (res == 0) {
|
||||||
char *env = NULL;
|
char *env = NULL;
|
||||||
|
|
||||||
sigprocmask(SIG_SETMASK, &oldmask, NULL);
|
sigprocmask(SIG_SETMASK, &oldmask, NULL);
|
||||||
setuid(geteuid());
|
setuid(geteuid());
|
||||||
if (lazy) {
|
if (lazy) {
|
||||||
execle("/bin/umount", "/bin/umount", "-i", rel_mnt,
|
execle("/bin/umount", "/bin/umount", "-i", rel_mnt,
|
||||||
"-l", NULL, &env);
|
"-l", NULL, &env);
|
||||||
} else {
|
} else {
|
||||||
execle("/bin/umount", "/bin/umount", "-i", rel_mnt,
|
execle("/bin/umount", "/bin/umount", "-i", rel_mnt,
|
||||||
NULL, &env);
|
NULL, &env);
|
||||||
}
|
}
|
||||||
fprintf(stderr, "%s: failed to execute /bin/umount: %s\n",
|
fprintf(stderr, "%s: failed to execute /bin/umount: %s\n",
|
||||||
progname, strerror(errno));
|
progname, strerror(errno));
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
res = waitpid(res, &status, 0);
|
res = waitpid(res, &status, 0);
|
||||||
if (res == -1)
|
if (res == -1)
|
||||||
fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno));
|
fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno));
|
||||||
|
|
||||||
if (status != 0) {
|
if (status != 0) {
|
||||||
res = -1;
|
res = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
out_restore:
|
out_restore:
|
||||||
sigprocmask(SIG_SETMASK, &oldmask, NULL);
|
sigprocmask(SIG_SETMASK, &oldmask, NULL);
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int fuse_mnt_umount(const char *progname, const char *abs_mnt,
|
int fuse_mnt_umount(const char *progname, const char *abs_mnt,
|
||||||
const char *rel_mnt, int lazy)
|
const char *rel_mnt, int lazy)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
if (!mtab_needs_update(abs_mnt)) {
|
if (!mtab_needs_update(abs_mnt)) {
|
||||||
res = umount2(rel_mnt, lazy ? 2 : 0);
|
res = umount2(rel_mnt, lazy ? 2 : 0);
|
||||||
if (res == -1)
|
if (res == -1)
|
||||||
fprintf(stderr, "%s: failed to unmount %s: %s\n",
|
fprintf(stderr, "%s: failed to unmount %s: %s\n",
|
||||||
progname, abs_mnt, strerror(errno));
|
progname, abs_mnt, strerror(errno));
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
return exec_umount(progname, rel_mnt, lazy);
|
return exec_umount(progname, rel_mnt, lazy);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int remove_mount(const char *progname, const char *mnt)
|
static int remove_mount(const char *progname, const char *mnt)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
int status;
|
int status;
|
||||||
sigset_t blockmask;
|
sigset_t blockmask;
|
||||||
sigset_t oldmask;
|
sigset_t oldmask;
|
||||||
|
|
||||||
sigemptyset(&blockmask);
|
sigemptyset(&blockmask);
|
||||||
sigaddset(&blockmask, SIGCHLD);
|
sigaddset(&blockmask, SIGCHLD);
|
||||||
res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask);
|
res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask);
|
||||||
if (res == -1) {
|
if (res == -1) {
|
||||||
fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno));
|
fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
res = fork();
|
res = fork();
|
||||||
if (res == -1) {
|
if (res == -1) {
|
||||||
fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
|
fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
|
||||||
goto out_restore;
|
goto out_restore;
|
||||||
}
|
}
|
||||||
if (res == 0) {
|
if (res == 0) {
|
||||||
char *env = NULL;
|
char *env = NULL;
|
||||||
|
|
||||||
sigprocmask(SIG_SETMASK, &oldmask, NULL);
|
sigprocmask(SIG_SETMASK, &oldmask, NULL);
|
||||||
setuid(geteuid());
|
setuid(geteuid());
|
||||||
execle("/bin/umount", "/bin/umount", "--no-canonicalize", "-i",
|
execle("/bin/umount", "/bin/umount", "--no-canonicalize", "-i",
|
||||||
"--fake", mnt, NULL, &env);
|
"--fake", mnt, NULL, &env);
|
||||||
fprintf(stderr, "%s: failed to execute /bin/umount: %s\n",
|
fprintf(stderr, "%s: failed to execute /bin/umount: %s\n",
|
||||||
progname, strerror(errno));
|
progname, strerror(errno));
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
res = waitpid(res, &status, 0);
|
res = waitpid(res, &status, 0);
|
||||||
if (res == -1)
|
if (res == -1)
|
||||||
fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno));
|
fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno));
|
||||||
|
|
||||||
if (status != 0)
|
if (status != 0)
|
||||||
res = -1;
|
res = -1;
|
||||||
|
|
||||||
out_restore:
|
out_restore:
|
||||||
sigprocmask(SIG_SETMASK, &oldmask, NULL);
|
sigprocmask(SIG_SETMASK, &oldmask, NULL);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fuse_mnt_remove_mount(const char *progname, const char *mnt)
|
int fuse_mnt_remove_mount(const char *progname, const char *mnt)
|
||||||
{
|
{
|
||||||
if (!mtab_needs_update(mnt))
|
if (!mtab_needs_update(mnt))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return remove_mount(progname, mnt);
|
return remove_mount(progname, mnt);
|
||||||
}
|
}
|
||||||
|
|
||||||
char *fuse_mnt_resolve_path(const char *progname, const char *orig)
|
char *fuse_mnt_resolve_path(const char *progname, const char *orig)
|
||||||
{
|
{
|
||||||
char buf[PATH_MAX];
|
char buf[PATH_MAX];
|
||||||
char *copy;
|
char *copy;
|
||||||
char *dst;
|
char *dst;
|
||||||
char *end;
|
char *end;
|
||||||
char *lastcomp;
|
char *lastcomp;
|
||||||
const char *toresolv;
|
const char *toresolv;
|
||||||
|
|
||||||
if (!orig[0]) {
|
if (!orig[0]) {
|
||||||
fprintf(stderr, "%s: invalid mountpoint '%s'\n", progname,
|
fprintf(stderr, "%s: invalid mountpoint '%s'\n", progname,
|
||||||
orig);
|
orig);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
copy = strdup(orig);
|
copy = strdup(orig);
|
||||||
if (copy == NULL) {
|
if (copy == NULL) {
|
||||||
fprintf(stderr, "%s: failed to allocate memory\n", progname);
|
fprintf(stderr, "%s: failed to allocate memory\n", progname);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
toresolv = copy;
|
toresolv = copy;
|
||||||
lastcomp = NULL;
|
lastcomp = NULL;
|
||||||
for (end = copy + strlen(copy) - 1; end > copy && *end == '/'; end --);
|
for (end = copy + strlen(copy) - 1; end > copy && *end == '/'; end --);
|
||||||
if (end[0] != '/') {
|
if (end[0] != '/') {
|
||||||
char *tmp;
|
char *tmp;
|
||||||
end[1] = '\0';
|
end[1] = '\0';
|
||||||
tmp = strrchr(copy, '/');
|
tmp = strrchr(copy, '/');
|
||||||
if (tmp == NULL) {
|
if (tmp == NULL) {
|
||||||
lastcomp = copy;
|
lastcomp = copy;
|
||||||
toresolv = ".";
|
toresolv = ".";
|
||||||
} else {
|
} else {
|
||||||
lastcomp = tmp + 1;
|
lastcomp = tmp + 1;
|
||||||
if (tmp == copy)
|
if (tmp == copy)
|
||||||
toresolv = "/";
|
toresolv = "/";
|
||||||
}
|
}
|
||||||
if (strcmp(lastcomp, ".") == 0 || strcmp(lastcomp, "..") == 0) {
|
if (strcmp(lastcomp, ".") == 0 || strcmp(lastcomp, "..") == 0) {
|
||||||
lastcomp = NULL;
|
lastcomp = NULL;
|
||||||
toresolv = copy;
|
toresolv = copy;
|
||||||
}
|
}
|
||||||
else if (tmp)
|
else if (tmp)
|
||||||
tmp[0] = '\0';
|
tmp[0] = '\0';
|
||||||
}
|
}
|
||||||
if (realpath(toresolv, buf) == NULL) {
|
if (realpath(toresolv, buf) == NULL) {
|
||||||
fprintf(stderr, "%s: bad mount point %s: %s\n", progname, orig,
|
fprintf(stderr, "%s: bad mount point %s: %s\n", progname, orig,
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
free(copy);
|
free(copy);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (lastcomp == NULL)
|
if (lastcomp == NULL)
|
||||||
dst = strdup(buf);
|
dst = strdup(buf);
|
||||||
else {
|
else {
|
||||||
dst = (char *) malloc(strlen(buf) + 1 + strlen(lastcomp) + 1);
|
dst = (char *) malloc(strlen(buf) + 1 + strlen(lastcomp) + 1);
|
||||||
if (dst) {
|
if (dst) {
|
||||||
unsigned buflen = strlen(buf);
|
unsigned buflen = strlen(buf);
|
||||||
if (buflen && buf[buflen-1] == '/')
|
if (buflen && buf[buflen-1] == '/')
|
||||||
sprintf(dst, "%s%s", buf, lastcomp);
|
sprintf(dst, "%s%s", buf, lastcomp);
|
||||||
else
|
else
|
||||||
sprintf(dst, "%s/%s", buf, lastcomp);
|
sprintf(dst, "%s/%s", buf, lastcomp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
free(copy);
|
free(copy);
|
||||||
if (dst == NULL)
|
if (dst == NULL)
|
||||||
fprintf(stderr, "%s: failed to allocate memory\n", progname);
|
fprintf(stderr, "%s: failed to allocate memory\n", progname);
|
||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fuse_mnt_check_empty(const char *progname, const char *mnt,
|
int fuse_mnt_check_empty(const char *progname, const char *mnt,
|
||||||
mode_t rootmode, off_t rootsize)
|
mode_t rootmode, off_t rootsize)
|
||||||
{
|
{
|
||||||
int isempty = 1;
|
int isempty = 1;
|
||||||
|
|
||||||
if (S_ISDIR(rootmode)) {
|
if (S_ISDIR(rootmode)) {
|
||||||
struct dirent *ent;
|
struct dirent *ent;
|
||||||
DIR *dp = opendir(mnt);
|
DIR *dp = opendir(mnt);
|
||||||
if (dp == NULL) {
|
if (dp == NULL) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"%s: failed to open mountpoint for reading: %s\n",
|
"%s: failed to open mountpoint for reading: %s\n",
|
||||||
progname, strerror(errno));
|
progname, strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
while ((ent = readdir(dp)) != NULL) {
|
while ((ent = readdir(dp)) != NULL) {
|
||||||
if (strcmp(ent->d_name, ".") != 0 &&
|
if (strcmp(ent->d_name, ".") != 0 &&
|
||||||
strcmp(ent->d_name, "..") != 0) {
|
strcmp(ent->d_name, "..") != 0) {
|
||||||
isempty = 0;
|
isempty = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
closedir(dp);
|
closedir(dp);
|
||||||
} else if (rootsize)
|
} else if (rootsize)
|
||||||
isempty = 0;
|
isempty = 0;
|
||||||
|
|
||||||
if (!isempty) {
|
if (!isempty) {
|
||||||
fprintf(stderr, "%s: mountpoint is not empty\n", progname);
|
fprintf(stderr, "%s: mountpoint is not empty\n", progname);
|
||||||
fprintf(stderr, "%s: if you are sure this is safe, use the 'nonempty' mount option\n", progname);
|
fprintf(stderr, "%s: if you are sure this is safe, use the 'nonempty' mount option\n", progname);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
int fuse_mnt_check_fuseblk(void)
|
|
||||||
{
|
|
||||||
char buf[256];
|
|
||||||
FILE *f = fopen("/proc/filesystems", "r");
|
|
||||||
if (!f)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
while (fgets(buf, sizeof(buf), f))
|
|
||||||
if (strstr(buf, "fuseblk\n")) {
|
|
||||||
fclose(f);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(f);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -55,7 +55,7 @@ Config::Config()
|
|||||||
writeback_cache(false),
|
writeback_cache(false),
|
||||||
readdirplus(false),
|
readdirplus(false),
|
||||||
cache_files(CacheFiles::LIBFUSE),
|
cache_files(CacheFiles::LIBFUSE),
|
||||||
fuse_msg_size(FUSE_MAX_MAX_PAGES),
|
fuse_msg_size(FUSE_MSG_MAX_PAGES),
|
||||||
POLICYINIT(access),
|
POLICYINIT(access),
|
||||||
POLICYINIT(chmod),
|
POLICYINIT(chmod),
|
||||||
POLICYINIT(chown),
|
POLICYINIT(chown),
|
||||||
|
|||||||
+1
-1
@@ -73,7 +73,7 @@ namespace l
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
c_.fuse_msg_size = FUSE_DEFAULT_MAX_PAGES_PER_REQ;
|
c_.fuse_msg_size = FUSE_MSG_DEFAULT_PAGES;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -382,7 +382,7 @@ parse_and_process_kv_arg(Config &config,
|
|||||||
else if(key == "fuse_msg_size")
|
else if(key == "fuse_msg_size")
|
||||||
rv = parse_and_process(value,config.fuse_msg_size,
|
rv = parse_and_process(value,config.fuse_msg_size,
|
||||||
1,
|
1,
|
||||||
FUSE_MAX_MAX_PAGES);
|
FUSE_MSG_MAX_PAGES);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(rv == -1)
|
if(rv == -1)
|
||||||
|
|||||||
Reference in New Issue
Block a user