From owner-svn-src-projects@FreeBSD.ORG Thu Sep 20 15:50:28 2012 Return-Path: Delivered-To: svn-src-projects@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id 870AB106566C; Thu, 20 Sep 2012 15:50:28 +0000 (UTC) (envelope-from attilio@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 6F1178FC18; Thu, 20 Sep 2012 15:50:28 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.4/8.14.4) with ESMTP id q8KFoS37046614; Thu, 20 Sep 2012 15:50:28 GMT (envelope-from attilio@svn.freebsd.org) Received: (from attilio@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id q8KFoSWx046609; Thu, 20 Sep 2012 15:50:28 GMT (envelope-from attilio@svn.freebsd.org) Message-Id: <201209201550.q8KFoSWx046609@svn.freebsd.org> From: Attilio Rao Date: Thu, 20 Sep 2012 15:50:28 +0000 (UTC) To: src-committers@freebsd.org, svn-src-projects@freebsd.org X-SVN-Group: projects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r240752 - in projects/fuse/sbin: . mount_fusefs X-BeenThere: svn-src-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the src " projects" tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 20 Sep 2012 15:50:28 -0000 Author: attilio Date: Thu Sep 20 15:50:27 2012 New Revision: 240752 URL: http://svn.freebsd.org/changeset/base/240752 Log: Add the mount support for fusefs volumes. This is almost entirely based on the port fusefs-kmod sources. Submitted by: people working on the fusefs-kmod Added: projects/fuse/sbin/mount_fusefs/ projects/fuse/sbin/mount_fusefs/Makefile (contents, props changed) projects/fuse/sbin/mount_fusefs/mount_fusefs.8 (contents, props changed) projects/fuse/sbin/mount_fusefs/mount_fusefs.c (contents, props changed) Modified: projects/fuse/sbin/Makefile Modified: projects/fuse/sbin/Makefile ============================================================================== --- projects/fuse/sbin/Makefile Thu Sep 20 15:19:01 2012 (r240751) +++ projects/fuse/sbin/Makefile Thu Sep 20 15:50:27 2012 (r240752) @@ -49,6 +49,7 @@ SUBDIR=adjkerntz \ mksnap_ffs \ mount \ mount_cd9660 \ + mount_fusefs \ mount_msdosfs \ mount_nfs \ mount_ntfs \ Added: projects/fuse/sbin/mount_fusefs/Makefile ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ projects/fuse/sbin/mount_fusefs/Makefile Thu Sep 20 15:50:27 2012 (r240752) @@ -0,0 +1,33 @@ +# $FreeBSD$ + +.if defined(DEBUG) +DEBUG_FLAGS+= -D_DEBUG -g +.endif + +.if defined(DEBUG2G) +DEBUG_FLAGS+= -D_DEBUG2G -g +.endif + +.if defined(DEBUG3G) +DEBUG_FLAGS+= -D_DEBUG3G -g +.endif + +.if defined(DEBUG_MSG) +DEBUG_FLAGS+= -D_DEBUG_MSG +.endif + +.if defined(F4BVERS) +DEBUG_FLAGS+= -DFUSE4BSD_VERSION="\"${F4BVERS}\"" +.endif + +PROG= mount_fusefs +SRCS= mount_fusefs.c getmntopts.c +MAN8= mount_fusefs.8 +NO_MANCOMPRESS?= yes + +MOUNT= ${.CURDIR}/../mount +CFLAGS+= -I${MOUNT} + +.PATH: ${MOUNT} + +.include Added: projects/fuse/sbin/mount_fusefs/mount_fusefs.8 ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ projects/fuse/sbin/mount_fusefs/mount_fusefs.8 Thu Sep 20 15:50:27 2012 (r240752) @@ -0,0 +1,373 @@ +.\" Copyright (c) 1980, 1989, 1991, 1993 +.\" The Regents of the University of California. +.\" Copyright (c) 2005, 2006 Csaba Henk +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd January 13, 2006 +.Dt MOUNT_FUSEFS 8 +.Os +.Sh NAME +.Nm mount_fusefs +.Nd mount a Fuse file system daemon +.Sh SYNOPSIS +.Nm +.Op Fl A +.Op Fl S +.Op Fl v +.Op Fl D Ar fuse_daemon +.Op Fl O Ar daemon_opts +.Op Fl s Ar special +.Op Fl m Ar node +.Op Fl h +.Op Fl V +.Op Fl o Ar option ... +.Ar special node +.Op Ar fuse_daemon ... +.Sh DESCRIPTION +The most basic way of usage is as follows: before calling +.Nm , +one starts a fuse daemon on the given +.Ar special +(in practice, the daemon gets one automatically, which can then be indentified +via +.Xr fstat 1 ) , +and that special file can then be mounted by +.Nm . +.Pp +However, the procedure of spawning a daemon can be automated so that it's +also performed by +.Nm . +If the command invoking a given +.Ar fuse_daemon +is appended to the list of arguments, +.Nm +will call then +.Ar fuse_daemon +via that command, in a way that +.Ar fuse_daemon +will be instructed to attach itself to +.Ar special . +From that on mounting goes as in the simple case. (See also +.Sx DAEMON MOUNTS . ) +.Pp +The +.Ar special +argument can be utilized by +.Nm +in the following ways: +.Bl -bullet -offset indent +.It +Basicly, it will be treated as the path of the special file to mount. +.It +However, if +.Pa auto +is passed as +.Ar special , +then +.Nm +will look for a suitable free fuse device by itself. +.It +Moreover, if +.Ar special +is an integer, then it will be interpreted as the number +of the file descriptor of an already open fuse device +(used when the Fuse library invokes +.Nm , +cf. +.Sx DAEMON MOUNTS ) . +.El +.Pp +The options are as follows: +.Bl -tag -width indent +.It Fl A , Ic --reject-allow_other +Prohibit the +.Cm allow_other +mount flag. Intended for to be used in scripts and the +.Xr sudoers 5 +file. +.It Fl S , Ic --safe +Run in safe mode, that is, reject invoking a filesystem daemon. +.It Fl v +Be verbose. +.It Fl D, Ic --daemon Ar daemon +Call the specified +.Ar daemon . +.It Fl O, Ic --daemon_opts Ar opts +Add +.Ar opts +to the daemon's command line. +.It Fl s, Ic --special Ar special +Use +.Ar special +as special. +.It Fl m, Ic --mountpath Ar node +Mount on +.Ar node . +.It Fl h, Ic --help +Show help. +.It Fl V, Ic --version +Show version information. +.It Fl o +Mount options are specified via +.Fl o . +The following options are available (and also their negated versions, +by prefixing them with +.Dq no ) : +.Bl -tag -width indent +.It Cm default_permissions +Enable traditional (file mode based) permission checking in kernel. +.It Cm allow_other +Do not apply +.Sx STRICT ACCESS POLICY . +Only root can use this option. +.It Cm max_read Ns = Ns Ar n +Limit size of read requests with +.Ar n . +.It Cm private +Refuse shared mounting of the daemon. This is the default behaviour, +to allow sharing, use expicitly +.Fl o Cm noprivate . +.It Cm neglect_shares +Don't refuse unmounting if there are secondary mounts. +.It Cm push_symlinks_in +Prefix absolute symlinks with mountpoint. +.El +.Pp +.El +.Pp +Besides the above mount options, there is a set of pseudo-mount options which +are supported by the Fuse library. One can list these by passing +.Fl h +to a Fuse daemon. Most of these options have effect only on the behaviour of +the daemon (that is, their scope is limited to userspace). However, +there are some which do require in-kernel support. +Currently the following ones are supported by the kernel: +.Bl -tag -width indent +.It Cm direct_io +Bypass the buffer cache system. +.It Cm kernel_cache +By default, cached buffers of a given file are flushed at each +.Xr open 2 . +This option disables this behaviour. +.El +.Sh DAEMON MOUNTS +Usually users don't need to use +.Nm +directly, as the Fuse library enables Fuse daemons to invoke +.Nm +by themselves. That is, +.Pp +.Dl fuse_daemon mountpoint +.Pp +has the same effect as +.Pp +.Dl mount_fusefs auto mountpoint fuse_daemon +.Pp +This is the recommended way of usage, unless you want to go beyond basic usage +(eg, run daemon on a low privilege level, but mount it as root). +.Sh STRICT ACCESS POLICY +The strict access policy for Fuse filesystems lets one to use the filesystem +only if the filesystem daemon has the same credentials (uid, real uid, gid, +real gid) as the user. +.Pp +This is applied for Fuse mounts by default, and only root can mount without +the strict access policy (cf. the +.Cm allow_other +mount option). +.Pp +The reason is to shield users from the daemon +.Dq spying +on their I/O activities. +.Pp +Users might opt for willingly relax strict access policy (as far they +are concerned) by doing their own secondary mount (cf. +.Sx SHARED MOUNTS ) . +.Sh SHARED MOUNTS +A Fuse daemon can be shared, ie. mounted multiple times. +When doing the first (primary) mount, the spawner and the mounter of the daemon +must have the same uid, or the mounter should be the superuser. +.Pp +After the primary mount is in place, secondary mounts can be done by anyone +(unless this feature is disabled by +.Cm private ) . +The behaviour of a secondary mount is analogous to that of symbolic +links: they redirect all filesystem operations to the primary mount. +.Pp +Doing a secondary mount is like signing an agreement: by this action, the mounter +agrees that the Fuse daemon can trace her I/O activities. From that on, she is not +banned from using the filesystem (either via her own mount or via the primary mount), +regardless whether +.Cm allow_other +is used or not. +.Pp +The device name of a secondary mount is the device name of the corresponding primary +mount, followed by a '#' character and the index of the secondary mount, like +.Pa /dev/fuse0#3 . +.Sh SECURITY +System administratos might want to use a custom mount policy (ie., one going beyond the +.Va vfs.usermount +sysctl). The primary tool for such purposes is +.Xr sudo 8 . +However, given that +.Nm +is capable of invoking an arbitrary program, one must be careful about this. +.Nm +is designed in a way such that it makes that easy. For this purpose, +there are options which disable certain risky features (cf. +.Fl S +and +.Fl A ) , +and command line parsing is done in a flexible way: mixing options and +non-options allowed, but processing them stops at the third non-option argument +(after the first two has been utilized as device and mountpoint). The rest of +the command line specifies the daemon and its arguments. (Alternatively, the +daemon, the special and the mount path can be specified using the respective +options.) Note that +.Nm +ignores the environment variable +.Ev POSIXLY_CORRECT +and always behaves as described. +.Pp +In general, to be as scripting / +.Xr sudoers 5 +friendly as possible, no information has a fixed +position in the command line, but once a given piece of information is +provided, subsequent arguments/options cannot override it (maybe with the +exception of some non-critical ones). +.Sh ENVIRONMENT +.Bl -tag -width ".Ev MOUNT_FUSEFS_SAFE" +.It Ev MOUNT_FUSEFS_SAFE +Setting this has the same effect as the +.Fl S +option. +.It Ev MOUNT_FUSEFS_VERBOSE +Setting this has the same effect as the +.Fl v +option. +.It Ev MOUNT_FUSEFS_IGNORE_UNKNOWN +If this is set, +.Nm +will ignore uknown mount options. +.It Ev MOUNT_FUSEFS_CALL_BY_LIB +Adjust behaviour to the needs of the FUSE library. Currently it has effect +on help output. +.El +.Pp +Although the following variables don't have effect on +.Nm +itself, they affect the behaviour of fuse daemons: +.Bl -tag -width ".Ev FUSE_DEV_NAME" +.It Ev FUSE_DEV_NAME +Device to get attached to. If not set, the multiplexer path +.Ar /dev/fuse +is used. +.It Ev FUSE_DEV_FD +File desciptor of an opened Fuse device to use. Overrides +.Ev FUSE_DEV_NAME . +.It Ev FUSE_NO_MOUNT +If this is set, the library won't attempt to mount the filesystem, even +if a mountpoint argument is supplied. +.El +.Sh FILES +.Bl -tag -width /dev/fuseN +.It Pa /dev/fuseN +Fuse devices by which the kernel and Fuse daemons can communicate. +.It Pa /dev/fuse +The multiplexer path. An +.Xr open 2 +performed on it automatically gets passed to a free Fuse device by the kernel (which might be +just created for this puprose). +.El +.Sh EXAMPLES +Mounting the example filesystem of the Fuse distribution (from its directory): either +.Pp +.Dl ./fusexmp /mnt/fuse +.Pp +or +.Pp +.Dl mount_fusefs auto /mnt/fuse ./fusexmp +.Pp +Doing the same in two steps, using +.Pa /dev/fuse0 : +.Pp +.Dl FUSE_DEV_NAME=/dev/fuse0 ./fusexmp && +.Dl mount_fusefs /dev/fuse0 /mnt/fuse +.Pp +A script wrapper for fusexmp which ensures that +.Nm +doesn't call any external utility and also provides a hacky +(non race-free) automatic device selection: +.Pp +.Dl #!/bin/sh -e +.Pp +.Dl n=`ls /dev/fuse* | awk 'END{ print FNR }'` +.Dl FUSE_DEV_NAME=/dev/fuse$n fusexmp +.Dl mount_fusefs -S /dev/fuse$n /mnt/fuse \(lq$@\(rq +.Pp +A better (race-free) script wrapper: +.Pp +.Dl #!/bin/sh -e +.Pp +.Dl exec 3<>/dev/fuse +.Dl FUSE_DEV_FD=3 fusexmp +.Dl mount_fusefs -S 3 /mnt/fuse \(lq$@\(rq +.Sh SEE ALSO +.Xr fstat 1 , +.Xr mount 8 , +.Xr umount 8 , +.Xr sudo 8 +.Sh CAVEATS +Secondary mounts are to be unmounted via their device name. If they attempted to be unmounted via +their filesystem root path, the unmount request will be forwarded to the primary mount path. +In general, unmounting by device name is less error-prone than by mount path +(although the latter will also work under normal circumstances). +.Pp +If the daemon is specified via the +.Fl D +and +.Fl O +options, it will be invoked via +.Xr system 3 , +and the daemon's command line will be also appended a +.Dq & +sygill, so that we don't have to wait for its termination. That is, you'd better +use a simple command line when invoking the daemon via these options. +.Sh HISTORY +.Nm +appears as the part of the FreeBSD implementation of the Fuse userspace filesystem +framework (see http://fuse.sourceforge.net). This user interface is FreeBSD specific. +.Sh BUGS +.Ar special +is treated as a multiplexer if and only if it's literally the same as +.Pa auto +or +.Pa /dev/fuse . +Other paths which are equivalent with +.Pa /dev/fuse +(eg., +.Pa /../dev/fuse ) +are not. Added: projects/fuse/sbin/mount_fusefs/mount_fusefs.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ projects/fuse/sbin/mount_fusefs/mount_fusefs.c Thu Sep 20 15:50:27 2012 (r240752) @@ -0,0 +1,502 @@ +/*- + * Copyright (c) 2005 Jean-Sébastien Pédron + * Copyright (c) 2005 Csaba Henk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mntopts.h" + +#ifndef FUSE4BSD_VERSION +#define FUSE4BSD_VERSION "0.3.9-pre1" +#endif + +void __usage_short(void); +void usage(void); +void helpmsg(void); +void showversion(void); +int init_backgrounded(void); + +struct mntopt mopts[] = { + #define ALTF_PRIVATE 0x01 + { "private", 0, ALTF_PRIVATE, 1 }, + { "neglect_shares", 0, 0x02, 1 }, + { "push_symlinks_in", 0, 0x04, 1 }, + { "allow_other", 0, 0x08, 1 }, + { "default_permissions", 0, 0x10, 1 }, + #define ALTF_MAXREAD 0x20 + { "max_read=", 0, ALTF_MAXREAD, 1 }, + #define ALTF_SUBTYPE 0x40 + { "subtype=", 0, ALTF_SUBTYPE, 1 }, + #define ALTF_SYNC_UNMOUNT 0x80 + { "sync_unmount", 0, ALTF_SYNC_UNMOUNT, 1 }, + /* Linux specific options, we silently ignore them */ + { "fsname=", 0, 0x00, 1 }, + { "fd=", 0, 0x00, 1 }, + { "rootmode=", 0, 0x00, 1 }, + { "user_id=", 0, 0x00, 1 }, + { "group_id=", 0, 0x00, 1 }, + { "large_read", 0, 0x00, 1 }, + /* "nonempty", just the first two chars are stripped off during parsing */ + { "nempty", 0, 0x00, 1 }, + MOPT_STDOPTS, + MOPT_END +}; + +struct mntval { + int mv_flag; + void *mv_value; + int mv_len; +}; + +struct mntval mvals[] = { + { ALTF_MAXREAD, NULL, 0 }, + { ALTF_SUBTYPE, NULL, 0 }, + { 0, NULL, 0 } +}; + +char *progname; + +#define DEFAULT_MOUNT_FLAGS ALTF_PRIVATE | ALTF_SYNC_UNMOUNT + +int +main(int argc, char *argv[]) +{ + struct iovec *iov; + char ch = '\0'; + int mntflags, iovlen, verbose = 0; + char *dev = NULL, *dir = NULL, mntpath[MAXPATHLEN]; + char *devo = NULL, *diro = NULL; + char ndev[128], fdstr[15]; + int i, done = 0, reject_allow_other = 0, safe_level = 0; + int altflags = DEFAULT_MOUNT_FLAGS; + int __altflags = DEFAULT_MOUNT_FLAGS; + struct mntopt *mo; + struct mntval *mv; + static struct option longopts[] = { + {"reject-allow_other", no_argument, NULL, 'A'}, + {"safe", no_argument, NULL, 'S'}, + {"daemon", required_argument, NULL, 'D'}, + {"daemon_opts", required_argument, NULL, 'O'}, + {"special", required_argument, NULL, 's'}, + {"mountpath", required_argument, NULL, 'm'}, + {"version", no_argument, NULL, 'V'}, + {"help", no_argument, NULL, 'h'}, + {0,0,0,0} + }; + int pid = 0; + int fd = -1, fdx; + char *ep; + char *daemon_str = NULL, *daemon_opts = NULL; + + progname = argv[0]; + + /* + * We want a parsing routine which is not sensitive to + * the position of args/opts; it should extract the + * first two args and stop at the beginning of the rest. + * (This makes it easier to call mount_fusefs from external + * utils than it is with a strict "util flags args" syntax.) + */ + + iov = NULL; + iovlen = 0; + mntflags = 0; + /* All in all, I feel it more robust this way... */ + unsetenv("POSIXLY_CORRECT"); + if (getenv("MOUNT_FUSEFS_IGNORE_UNKNOWN")) + getmnt_silent = 1; + if (getenv("MOUNT_FUSEFS_VERBOSE")) + verbose = 1; + + do { + for (i = 0; i < 3; i++) { + if (optind < argc && argv[optind][0] != '-') { + if (dir) { + done = 1; + break; + } + if (dev) + dir = argv[optind]; + else + dev = argv[optind]; + optind++; + } + } + switch(ch) { + case 'A': + reject_allow_other = 1; + break; + case 'S': + safe_level = 1; + break; + case 'D': + if (daemon_str) + errx(1, "daemon specified inconsistently"); + daemon_str = optarg; + break; + case 'O': + if (daemon_opts) + errx(1, "daemon opts specified inconsistently"); + daemon_opts = optarg; + break; + case 'o': + getmntopts(optarg, mopts, &mntflags, &altflags); + for (mv = mvals; mv->mv_flag; ++mv) { + if (! (altflags & mv->mv_flag)) + continue; + for (mo = mopts; mo->m_flag; ++mo) { + char *p, *q; + + if (mo->m_flag != mv->mv_flag) + continue; + p = strstr(optarg, mo->m_option); + if (p) { + p += strlen(mo->m_option); + q = p; + while (*q != '\0' && *q != ',') + q++; + mv->mv_len = q - p + 1; + mv->mv_value = malloc(mv->mv_len); + memcpy(mv->mv_value, p, mv->mv_len - 1); + ((char *)mv->mv_value)[mv->mv_len - 1] = '\0'; + break; + } + } + } + break; + case 's': + if (devo) + errx(1, "special specified inconsistently"); + devo = optarg; + break; + case 'm': + if (diro) + errx(1, "mount path specified inconsistently"); + diro = optarg; + break; + case 'v': + verbose = 1; + break; + case 'h': + helpmsg(); + break; + case 'V': + showversion(); + break; + case '\0': + break; + case '?': + default: + usage(); + } + if (done) + break; + } while ((ch = getopt_long(argc, argv, "AvVho:SD:O:s:m:", longopts, NULL)) != -1); + + argc -= optind; + argv += optind; + + if (devo) { + if (dev) + errx(1, "special specified inconsistently"); + dev = devo; + } else if (diro) + errx(1, "if mountpoint is given via an option, special should also be given via an option"); + + if (diro) { + if (dir) + errx(1, "mount path specified inconsistently"); + dir = diro; + } + + if ((! dev) && argc > 0) { + dev = *argv++; + argc--; + } + + if ((! dir) && argc > 0) { + dir = *argv++; + argc--; + } + + if (! (dev && dir)) + errx(1, "missing special and/or mountpoint"); + + for (mo = mopts; mo->m_flag; ++mo) { + if (altflags & mo->m_flag) { + int iov_done = 0; + + if (reject_allow_other && + strcmp(mo->m_option, "allow_other") == 0) + /* + * reject_allow_other is stronger than a + * negative of allow_other: if this is set, + * allow_other is blocked, period. + */ + errx(1, "\"allow_other\" usage is banned by respective option"); + + for (mv = mvals; mv->mv_flag; ++mv) { + if (mo->m_flag != mv->mv_flag) + continue; + if (mv->mv_value) { + build_iovec(&iov, &iovlen, mo->m_option, mv->mv_value, mv->mv_len); + iov_done = 1; + break; + } + } + if (! iov_done) + build_iovec(&iov, &iovlen, mo->m_option, + __DECONST(void *, ""), -1); + } + if (__altflags & mo->m_flag) { + char *uscore_opt; + + if (asprintf(&uscore_opt, "__%s", mo->m_option) == -1) + err(1, "failed to allocate memory"); + build_iovec(&iov, &iovlen, uscore_opt, + __DECONST(void *, ""), -1); + free(uscore_opt); + } + } + + if (getenv("MOUNT_FUSEFS_SAFE")) + safe_level = 1; + + if (safe_level > 0 && (argc > 0 || daemon_str || daemon_opts)) + errx(1, "safe mode, spawning daemon not allowed"); + + if ((argc > 0 && (daemon_str || daemon_opts)) || + (daemon_opts && ! daemon_str)) + errx(1, "daemon specified inconsistently"); + + /* + * Resolve the mountpoint with realpath(3) and remove unnecessary + * slashes from the devicename if there are any. + */ + if (checkpath(dir, mntpath) != 0) + err(1, "%s", mntpath); + (void)rmslashes(dev, dev); + + if (strcmp(dev, "auto") == 0) + dev = __DECONST(char *, "/dev/fuse"); + + if (strcmp(dev, "/dev/fuse") == 0) { + if (! (argc > 0 || daemon_str)) { + fprintf(stderr, "Please also specify the fuse daemon to run when mounting via the multiplexer!\n"); + usage(); + } + if ((fd = open(dev, O_RDWR)) < 0) + err(1, "failed to open fuse device"); + } else { + fdx = strtol(dev, &ep, 10); + if (*ep == '\0') + fd = fdx; + } + + /* Identifying device */ + if (fd >= 0) { + struct stat sbuf; + char *ndevbas, *lep; + + if (fstat(fd, &sbuf) == -1) + err(1, "cannot stat device file descriptor"); + + strcpy(ndev, _PATH_DEV); + ndevbas = ndev + strlen(_PATH_DEV); + devname_r(sbuf.st_rdev, S_IFCHR, ndevbas, + sizeof(ndev) - strlen(_PATH_DEV)); + + if (strncmp(ndevbas, "fuse", 4)) + errx(1, "mounting inappropriate device"); + + strtol(ndevbas + 4, &lep, 10); + if (*lep != '\0') + errx(1, "mounting inappropriate device"); + + dev = ndev; + } + + if (argc > 0 || daemon_str) { + char *fds; + + if (fd < 0 && (fd = open(dev, O_RDWR)) < 0) + err(1, "failed to open fuse device"); + + if (asprintf(&fds, "%d", fd) == -1) + err(1, "failed to allocate memory"); + setenv("FUSE_DEV_FD", fds, 1); + free(fds); + setenv("FUSE_NO_MOUNT", "1", 1); + + if (daemon_str) { + char *bgdaemon; + int len; + + if (! daemon_opts) + daemon_opts = __DECONST(char *, ""); + + len = strlen(daemon_str) + 1 + strlen(daemon_opts) + + 2 + 1; + bgdaemon = calloc(1, len); + + if (! bgdaemon) + err(1, "failed to allocate memory"); + + strlcpy(bgdaemon, daemon_str, len); + strlcat(bgdaemon, " ", len); + strlcat(bgdaemon, daemon_opts, len); + strlcat(bgdaemon, " &", len); + + if (system(bgdaemon)) + err(1, "failed to call fuse daemon"); + } else { + if ((pid = fork()) < 0) + err(1, "failed to fork for fuse daemon"); + + if (pid == 0) { + execvp(argv[0], argv); + err(1, "failed to exec fuse daemon"); + } + } + } + + if (fd >= 0 && ! init_backgrounded() && close(fd) < 0) { + if (pid) + kill(pid, SIGKILL); + err(1, "failed to close fuse device"); + } + + /* Prepare the options vector for nmount(). build_iovec() is declared + * in mntopts.h. */ + sprintf(fdstr, "%d", fd); + build_iovec(&iov, &iovlen, "fstype", __DECONST(void *, "fusefs"), -1); + build_iovec(&iov, &iovlen, "fspath", mntpath, -1); + build_iovec(&iov, &iovlen, "from", dev, -1); + build_iovec(&iov, &iovlen, "fd", fdstr, -1); + + if (verbose) + fprintf(stderr, "mounting fuse daemon on device %s\n", dev); + + if (nmount(iov, iovlen, mntflags) < 0) + err(EX_OSERR, "%s on %s", dev, mntpath); + + exit(0); +} + +void +__usage_short(void) { + fprintf(stderr, + "usage:\n%s [-A|-S|-v|-V|-h|-D daemon|-O args|-s special|-m node|-o option...] special node [daemon args...]\n\n", + basename(progname)); +} + +void +usage(void) +{ + struct mntopt *mo; + + __usage_short(); + + fprintf(stderr, "known options:\n"); + for (mo = mopts; mo->m_flag; ++mo) + fprintf(stderr, "\t%s\n", mo->m_option); + + fprintf(stderr, "\n(use -h for a detailed description of these options)\n"); + exit(EX_USAGE); +} + +void +helpmsg(void) +{ + if (! getenv("MOUNT_FUSEFS_CALL_BY_LIB")) { + __usage_short(); + fprintf(stderr, "description of options:\n"); + } + + /* + * The main use case of this function is giving info embedded in general + * FUSE lib help output. Therefore the style and the content of the output + * tries to fit there as much as possible. + */ + fprintf(stderr, + " -o allow_other allow access to other users\n" + /* " -o nonempty allow mounts over non-empty file/dir\n" */ + " -o default_permissions enable permission checking by kernel\n" + /* + " -o fsname=NAME set filesystem name\n" + " -o large_read issue large read requests (2.4 only)\n" + */ + " -o subtype=NAME set filesystem type\n" + " -o max_read=N set maximum size of read requests\n" + " -o noprivate allow secondary mounting of the filesystem\n" + " -o neglect_shares don't report EBUSY when unmount attempted\n" + " in presence of secondary mounts\n" + " -o push_symlinks_in prefix absolute symlinks with mountpoint\n" + " -o sync_unmount do unmount synchronously\n" + ); + exit(EX_USAGE); +} + +void +showversion(void) +{ + puts("mount_fusefs [fuse4bsd] version: " FUSE4BSD_VERSION); + exit(EX_USAGE); +} + +int +init_backgrounded(void) +{ + int ibg; + size_t len; + + len = sizeof(ibg); + + if (sysctlbyname("vfs.fuse.init_backgrounded", &ibg, &len, NULL, 0)) + return (0); + + return (ibg); +}