PERFORCE change 83408 for review
soc-chenk
soc-chenk at FreeBSD.org
Sun Sep 11 10:08:16 PDT 2005
http://perforce.freebsd.org/chv.cgi?CH=83408
Change 83408 by soc-chenk at soc-chenk_leavemealone on 2005/09/11 17:07:48
Code state tagged as "version 0.01.1
Affected files ...
.. //depot/projects/soc2005/fuse4bsd2/COPYRIGHT#1 add
.. //depot/projects/soc2005/fuse4bsd2/Changelog#1 add
.. //depot/projects/soc2005/fuse4bsd2/README#2 edit
.. //depot/projects/soc2005/fuse4bsd2/fuse_module/Makefile#2 edit
.. //depot/projects/soc2005/fuse4bsd2/fuse_module/fuse.c#2 edit
.. //depot/projects/soc2005/fuse4bsd2/fuse_module/fuse_subr.c#1 add
.. //depot/projects/soc2005/fuse4bsd2/mount_fusefs/mount_fusefs.c#2 edit
Differences ...
==== //depot/projects/soc2005/fuse4bsd2/README#2 (text+ko) ====
@@ -1,21 +1,162 @@
-This is a FreeBSD kernel module to support the Fuse userspace virtual
-filesystem framework (http://fuse.sourceforge.net).
+Fuse module for FreeBSD.
+
+Fuse is an userspace filesystem framework, originally for Linux,
+see http://fuse.sourceforge.net.
+
+This distributions contains a port of Fuse to FreeBSD.
+
+Mainly this consists of writing a compatible kernel module for FreeBSD.
+The userspace part is pretty portable. You'll find here a patch to get
+that compiled, and brief instruvctions to get that running.
+
+The module was written for and tested with CURRENT, aka FreeBSD-7.0.
+I'd guess it will work fine with RELENG 6 too, but currently its not usable
+with 5.x (or lower) versions.
+
+Waht can be considered as a public homepage for the project is
+
+ http://wikitest.freebsd.org/moin.cgi/FuseFilesystem
+
+see updtates, further info there. Get in contact with me at
+soc-chenk at freebsd.org.
+
+Installation
+
+I'll describe here the installation of the core Fuse components and a Fuse
+based filesystem, sshfs, which lets you mount a machine remotely by means
+of an ssh conncetion.
+
+I'll describe a non-privileged installation.
+
+Downloads
+
+You need to get a bunch of things.
+
+ * Fuse itself. Get Fuse 2.4.0-pre1 from their homepage,
+ http://fuse.sourceforge.net
+
+ * This module. The latest version is available via Darcs, you can fetch it by
+ the
+
+ darcs get http://creo.hu/~csaba/darcs-repos/fuse4bsd
+
+ command. These instructions are appropriate for the version in place (with
+ which this README ships).
+
+ * Fuse sshfs. The latest release (1.2) will do, fetch the sshfs-fuse package from
+ [WWW]http://sourceforge.net/projects/fuse.
+
+Compilation
+
+Let's start with the module.
+
+ * From your Fuse distribuiton copy over kernel/fuse_kernel.h as
+ fuse_module/fuse_kernel.h.orig.
+
+ * Type make. If you want normal quantity of debug output, use
+ DEBUG2G=1, if you want tons of debug output, use DEBUG=1.
+
+Now go for the fuse userspace.
+
+ * We will assume that you have my module at ../fuse4bsd
+
+ * Apply the patch with
+
+ patch -Np1 < ../fuse4bsd/fuselib/fuselib-2.4.0-pre1.diff
+
+ * Do
+
+ cp ../fuse4bsd/fuselib/fusermount.c util/ &&
+ cp ../fuse4bsd/fuse_module/fuse_kernel.h include/ &&
+ cp ../fuse4bsd/fuse_module/linux_compat.h include/
+
+ (the first command replaces fusermount.c with a trimmed down version
+ without the mount support code, and the other two dynamically customize the
+ header file defining the kernel-userland interface; as these are needed in
+ the module as well, they are handled separately from the userspace patch).
+
+ * We will do a non-privileged install, I'll use ~/meta/fuse-2.4.0-pre1 as the
+ prefix. Configure fuse with
+
+ /configure --prefix ~/meta/fuse-2.4.0-pre1 --disable-kernel-module MOUNT_FUSE_PATH=/tmp
+
+ * Now type
+
+ make &&
+ ln -s /usr/bin/true chown &&
+ ln -s /usr/bin/true mknod &&
+ ln -s /usr/bin/true chmod &&
+ env PATH=`pwd`:$PATH make install
+
+
+You have successfully installed fuse libs. Go on to sshfs.
+
+ * Edit sshfs.c: add a #include <sys/socket.h> line to its includes.
+
+ * Type
+ env PKG_CONFIG_PATH=~/meta/fuse-2.4.0-pre1/lib/pkgconfig/ ./configure &&
+ make
+
+Congratulations, you have all components prepared!
+
+In the following, you'll need to act as superuser, or enable the vfs.usermount
+sysctl.
+
+First, of course, load fuse_module/fuse.ko (for this you definitely need to be a
+superuser).
+
+Then pick your favourite ssh accessible account (though maybe you'd better
+stick to servers running OpenSSH -- I've seen commits in sshfs' CVS for better
+interoperability with other servers, which show there might occur problems with
+them), say, it's foo at bar.baz.
+
+Firing up a Fuse daemon
+
+... sshfs, more concretely.
+
+Go to sshfs' directory. Type something along the following line:
+
+env PATH=$PATH:~csaba/meta/fuse-2.4.0-pre1/bin/ \
+ LD_LIBRARY_PATH=~csaba/meta/fuse-2.4.0-pre1/lib/ \
+ ./sshfs foo at bar.baz / -d
+
+Note that common Fuse arguments include the mountpoint -- in our case, that's
+just ignored, but required nevertheless --, and "-d" which doesn't let the
+daemon fork to background and enables debug messages.
+
+Mounting a Fuse filesystem
+
+Mounting is nnpfs style, in contrast to Linux Fuse style.
+
+In Linux, when you start a Fuse daemon, it first connects to the (unique) Fuse
+device, and then calls the mount system call with the appropriate parameters,
+so as a user, you can't separate the stages of Fuse mounting.
+
+In FreeBSD, you first start the daemon as above, then it gets a shiny fresh new
+dedicated fuse device (like /dev/fuse0), and you have to do the mounting
+manually, like
+
+mount_fusefs /dev/fuse0 /mnt/fuse
+
+(Find mount_fusefs in the mount_fusefs/ subdir of the fuse4bsd source tree.
+If you run it without arguments, it prints the available options.)
+
+You can ask: how to find out the device number? If you start your first daemon,
+by all chance it will be /dev/fuse0. But in general, you can do a fstat /dev/
+fuse* to see which device is in use.
-It's not yet ready, but you can test those parts which has already been
-completed.
+If you mounted it successfully, you can use the filesystem.
-See http://wikitest.freebsd.org/moin.cgi/FuseFilesystem for more info.
+It supports common POSIX fucntionality (mmap is read-only).
-Some of the stuff needed for compiling the userspace component for
-FreeBSD (those ones namely which don't require active development, just
-synchronization with Fuse sources from time to time) are available from
+When you finished, umount it with the "-f" siwtch.
-http://creo.hu/~csaba/projects/fuse4bsd
+It's a bug that you have to use that, but harmless... in the 95%
+percent of cases. If you had intensive I/O which has been interrupted,
+then there will remain dirty buffers, and in this case forced umount
+may result in a panic.
-The latest version of this module is available from the FreeBSD Perforce
-server (htpp://perforce.freebsd.org) at the path
-//depot/projects/soc2005/fuse4bsd/, and by Darcs, via the
+Any feedbakc is highly welcome.
-darcs get http://creo.hu/~csaba/darcs-repos/fuse4bsd
+Csaba Henk
-command.
==== //depot/projects/soc2005/fuse4bsd2/fuse_module/Makefile#2 (text+ko) ====
@@ -1,4 +1,4 @@
-SRCS=fuse.c
+SRCS=fuse.c fuse_subr.c
.if defined(FMASTER)
SRCS+= fmaster.c
==== //depot/projects/soc2005/fuse4bsd2/fuse_module/fuse.c#2 (text+ko) ====
@@ -21,7 +21,6 @@
#include <sys/stat.h>
#include <sys/unistd.h> /* pathconf */
#include <sys/filedesc.h> /* open */
-//#include <sys/ucred.h> /* open */
#include <sys/file.h> /* open */
#include <sys/fcntl.h> /* open */
#include <sys/dirent.h> /* readdir */
@@ -32,13 +31,7 @@
#include <vm/vm_extern.h>
#include <vm/vnode_pager.h>
-//#include <vm/vnode_pager.h>
#include <vm/vm_object.h>
-//#include <vm/vm_page.h>
-//#include <vm/vm_pager.h>
-//#include <vm/vm_map.h>
-//#include <vm/vnode_pager.h>
-//extern int vnode_pbuf_freecnt;
#include "fuse.h"
@@ -1186,7 +1179,7 @@
if (! fdip->tick)
fdip->tick = ticket_fetch(fdip->data);
- FUSE_DIMALLOC2(&fdip->tick->msgn.msg, fdip->finh, fdip->indata, fdip->iosize);
+ FUSE_DIMALLOC(&fdip->tick->msgn.msg, fdip->finh, fdip->indata, fdip->iosize);
fuse_setup_ihead(fdip->finh, fdip->tick, nid, op, td, cred);
}
@@ -1353,6 +1346,11 @@
int err = 0;
DEBUG("sending FORGET with %llu lookups\n", nlookup);
+#if 0 & _DEBUG2G
+ DEBUG2G("=============>\n");
+ kdb_backtrace();
+ DEBUG2G("<=============\n");
+#endif
fdip->iosize = sizeof(*ffi);
if (fdip->tick) {
@@ -1457,6 +1455,7 @@
.vfs_root = fuse_root,
.vfs_statfs = fuse_statfs,
//.vfs_vget = fuse_vget,
+ //.vfs_sync = vfs_stdsync,
};
#if __FreeBSD_version >= 600000
@@ -1623,9 +1622,24 @@
return (ENXIO);
}
- MALLOC(fmnt, struct fuse_mnt_data *, sizeof(*fmnt), M_FUSEFS, M_WAITOK);
+ MALLOC(fmnt, struct fuse_mnt_data *, sizeof(*fmnt), M_FUSEFS, M_WAITOK| M_ZERO);
fmnt->fdev = fdev;
+ vfs_flagopt(opts, "allow_other", &fmnt->mntopts, FUSEFS_DAEMON_CAN_SPY);
+ if (fmnt->mntopts & FUSEFS_DAEMON_CAN_SPY && suser(td)) {
+ uprintf("only root can use \"allow_other\"\n");
+ free(fmnt, M_FUSEFS);
+ return (EPERM);
+ }
+ vfs_flagopt(opts, "direct_io", &fmnt->mntopts, FUSEFS_DIRECTIO);
+ vfs_flagopt(opts, "kernel_cache", &fmnt->mntopts, FUSEFS_KEEPCACHE);
+#if ! REALTIME_TRACK_UNPRIVPROCDBG
+ fmnt->mntopts &= ~FUSEFS_UNPRIVPROCDBG;
+ fmnt->mntopts |= get_unprivileged_proc_debug(td) ? FUSEFS_UNPRIVPROCDBG : 0;
+#endif
+
+ DEBUG2G("mntopts 0x%x\n", fmnt->mntopts);
+
sx_slock(slock);
/* Sanity + permission checks */
@@ -1644,7 +1658,7 @@
}
if ((! err) && suser(td)) {
- if (td->td_ucred->cr_ruid != data->daemoncred->cr_ruid) {
+ if (td->td_ucred->cr_uid != data->daemoncred->cr_uid) {
err = EPERM;
uprintf("attempt to mount other user's daemon\n");
}
@@ -1729,7 +1743,10 @@
flags |= FORCECLOSE;
#if _DEBUG
- vn_printf(((struct fuse_mnt_data *)mp->mnt_data)->rvp, DEBLABEL "root node before execution\n");
+ //vn_printf(((struct fuse_mnt_data *)mp->mnt_data)->rvp, DEBLABEL "root node before execution\n");
+ DEBUG2G("=============>\n");
+ kdb_backtrace();
+ DEBUG2G("<=============\n");
#endif
/* Flush files -> vflush */
/* There is 1 extra root vnode reference (mp->mnt_data). */
@@ -1890,6 +1907,7 @@
}
+
/******************
*
* >>> Vnode ops
@@ -1990,6 +2008,12 @@
struct thread *td = ap->a_td;
DEBUG("pfft...\n");
+#if _DEBUG
+ DEBUG2G("=============>\n");
+ kdb_backtrace();
+ vn_printf(vp, " ");
+ DEBUG2G("<=============\n");
+#endif
fuse_filehandle_gc(vp, td, NULL);
vnode_destroy_vobject(vp);
return (fuse_recyc_backend(vp, td));
@@ -2004,6 +2028,12 @@
int err;
DEBUG("getting at vnode of ino %d\n", VTOI(vp));
+#if _DEBUG
+ DEBUG2G("=============>\n");
+ kdb_backtrace();
+ vn_printf(vp, " ");
+ DEBUG2G("<=============\n");
+#endif
fuse_filehandle_gc(vp, td, NULL);
@@ -2107,37 +2137,43 @@
struct ucred *cred = ap->a_cred;
struct thread *td = ap->a_td;
+ struct fuse_mnt_data *fmnt = vp->v_mount->mnt_data;
struct fuse_dispatcher fdi;
int err = 0;
if ((err = fdisp_simple_putget(&fdi, FUSE_GETATTR, vp, td, cred)))
return (err);
-
-
/* XXX we discard timeout related info,
* just go for the attributes */
fat2vat(vp->v_mount, &((struct fuse_attr_out *)fdi.answ)->attr, vap);
ticket_drop(fdi.tick);
-#if ! DAEMON_CAN_SPY
- /* The default policy is to forbid a user from using the filesystem,
- * if she is *more* privileged than the daemon. This is to protect
- * the power user from the daemon spying on her I/O operations.
- * Yes, it is a crude and blunt protection...
- * XXX there should be a sysctl interface to this. Ideally not just a
- * "daemon can spy bit", but some clever data which determines in a
- * compact but flexible way whose daemon can spy on whom.
- */
+ if (! (fmnt->mntopts & FUSEFS_DAEMON_CAN_SPY)) {
+ /* The policy is to forbid a user from using the filesystem,
+ * if she is *more* privileged than the daemon. This is to protect
+ * the power user from the daemon spying on her I/O operations.
+ * Yes, it is a crude and blunt protection...
+ * XXX there should be a sysctl interface to this. Ideally not just a
+ * "daemon can spy bit", but some clever data which determines in a
+ * compact but flexible way whose daemon can spy on whom.
+ */
- if (cr_cansee(fusedev_get_data(fdi.fdev)->daemoncred, cred)) {
- sx_sunlock(fdi.slock);
- uprintf("Your access is blocked in order to prevent the fuse daemon spying on you\n");
- return (EPERM);
+ //DEBUG2G("mntopts 0x%x\n", ((struct fuse_mnt_data *)vp->v_mount->mnt_data)->mntopts);
+ if (cr_candebug(
+#if REALTIME_TRACK_UNPRIVPROCDBG
+ get_unprivileged_proc_debug(td),
+#else
+ ((struct fuse_mnt_data *)vp->v_mount->mnt_data)->mntopts & FUSEFS_UNPRIVPROCDBG,
+#endif
+ fusedev_get_data(fdi.fdev)->daemoncred, cred))
+ {
+ sx_sunlock(fdi.slock);
+ uprintf("Your access is blocked in order to prevent the fuse daemon spying on you\n (consider mounting with \"allow_other\")\n");
+ return (EPERM);
+ }
}
-#endif
-
sx_sunlock(fdi.slock);
if (vp->v_type != vap->va_type) {
@@ -2633,6 +2669,7 @@
static int
fuse_standard_metrics(struct vnode *vp, struct thread *td, struct ucred *cred, int mode, struct fuse_filehandle *fufh, void *param)
{
+ DEBUG2G("fufh->mode, %x mode %x\n", fufh->mode, mode);
if (fufh->cred->cr_uid == cred->cr_uid &&
fufh->cred->cr_rgid == cred->cr_rgid &&
fufh->pid == td->td_proc->p_pid &&
@@ -2711,7 +2748,7 @@
struct vnode *vp = ap->a_vp;
int fdidx = ap->a_fdidx;
struct ucred *cred = ap->a_cred;
- int mode = OFLAGS(ap->a_mode);
+ int mode = ap->a_mode;
struct fuse_filehandle *fufh;
struct fuse_vnode_data *fvdat = vp->v_data;
@@ -2724,6 +2761,7 @@
int err = 0;
struct file *fp = NULL;
int keep_cache;
+ struct fuse_mnt_data *fmnt = vp->v_mount->mnt_data;
if (! vp->v_object)
/* The "if" here is just to avoid needless getattr'ing */
@@ -2753,12 +2791,13 @@
if (! fp)
panic("nonneg file desc passed to us but no file there");
+ DEBUG2G("fp->f_flag 0x%x, open mode %d\n", fp->f_flag, mode);
fdi.iosize = sizeof(*foi);
if ((err = fdisp_prepare_all(&fdi, (vp->v_type == VDIR) ? FUSE_OPENDIR : FUSE_OPEN, vp, td, cred)))
return (err);
foi = fdi.indata;
- foi->flags = mode;
+ foi->flags = OFLAGS(mode);
if ((err = fdisp_wait_answ(&fdi)))
return (err);
@@ -2768,14 +2807,41 @@
fufh->fh_id = foo->fh;
+#if 0
+ /*
+ * We ignore the following flags sent from userspace, as they are in
+ * fact mount options... just for some bizarre reason in Linux they
+ * are kept at the daemon an she sends them down all the time.
+ *
+ * Well, that bizarre reason might be that this way daemons can
+ * interpret/evaluate/override mount options. Yet you shouldn't
+ * worry too mich about that happenning, as its accessible only
+ * via the low-level API (filesystem writers are not encouraged to
+ * fiddle with it).
+ *
+ * This implementation gives the mount opts to the mount util, which in turn
+ * passes them to the kernel, not to the daemon, so our mount info
+ * is authoritative, not the flags as seen by the daemon. So we ignore
+ * them.
+ */
+
if (foo->open_flags & FOPEN_DIRECT_IO)
fp->f_flag |= O_DIRECT;
keep_cache = foo->open_flags & FOPEN_KEEP_CACHE;
+#endif
ticket_drop(fdi.tick);
sx_sunlock(fdi.slock);
+ fp->f_flag = mode;
+ if (fmnt->mntopts & FUSEFS_DIRECTIO)
+ fp->f_flag |= O_DIRECT;
+
+
+ DEBUG2G("fp->f_flag 0x%x\n", fp->f_flag);
+ keep_cache = fmnt->mntopts & FUSEFS_KEEPCACHE;
+
#if DIRECTIO_FOR_DIRS
if (vp->v_type == VDIR) {
DEBUG("coloring file #%d\n", fdidx);
@@ -2900,7 +2966,7 @@
fri = fdi.indata;
fri->fh = fufh->fh_id;
- fri->flags = flags;
+ fri->flags = OFLAGS(flags);
fuse_insert_callback(fdi.tick, NULL);
fuse_insert_message(fdi.tick);
@@ -2963,7 +3029,7 @@
fp->f_data = NULL;
if (fufh->useco == 0)
- err = fuse_send_release(fp->f_vnode, td, NULL, fufh, OFLAGS(fp->f_flag) & ~O_EXCL);
+ err = fuse_send_release(fp->f_vnode, td, NULL, fufh, fp->f_flag & ~O_EXCL);
//DEBUG2G("closing vnode #%d, opencount now is %d\n", VTOI(fp->f_vnode), --(fvdat->opencount));
return (err);
@@ -3132,6 +3198,7 @@
{
int err = 0;
struct fuse_filehandle *fufh = fp->f_data;
+ struct fuse_mnt_data *fmnt = fp->f_vnode->v_mount->mnt_data;
BREAK_IF_BAD(fp);
@@ -3141,7 +3208,16 @@
if ((flags & FOF_OFFSET) == 0)
uio->uio_offset = fp->f_offset;
- if (fp->f_flag & O_DIRECT) {
+ DEBUG2G("fp->f_flag 0x%x\n", fp->f_flag);
+
+ /* The great idea is to use the directio mnt opt such that it just
+ * controls the default mode of the file, later on it can be tuned
+ * by fcntl. Alas, that doesn't work -- the system always stripes
+ * out the O_DIRECT bit from my customized flag. So we fall back
+ * to the hardcoded behaviour (similar to Linux's, btw).
+ */
+ //if (fp->f_flag & O_DIRECT) {
+ if (fmnt->mntopts & FUSEFS_DIRECTIO) {
DEBUG2G("direct read of vnode %d via file handle %llu\n", VTOI(fp->f_vnode), fufh->fh_id);
err = fuse_read_directbackend(fp->f_vnode, fufh->fh_id, uio, cred, td, FUSE_READ, fuse_std_buffeater, NULL);
} else {
@@ -4366,6 +4442,7 @@
{
struct fuse_filehandle *fufh = fp->f_data;
struct vattr va;
+ struct fuse_mnt_data *fmnt = fp->f_vnode->v_mount->mnt_data;
int err = 0;
BREAK_IF_BAD(fp);
@@ -4387,7 +4464,8 @@
} else if ((flags & FOF_OFFSET) == 0)
uio->uio_offset = fp->f_offset;
- if (fp->f_flag & O_DIRECT) {
+ //if (fp->f_flag & O_DIRECT) {
+ if (fmnt->mntopts & FUSEFS_DIRECTIO) {
DEBUG2G("direct write of vnode %d via file handle %llu\n", VTOI(fp->f_vnode), fufh->fh_id);
err = fuse_write_directbackend(fp->f_vnode, fufh->fh_id, uio, cred, td);
} else {
@@ -4454,7 +4532,7 @@
#if _DEBUG
vn_printf(vp, DEBLABEL "fuse_strategy: looking for fufh for vnode #%d, to read from block #%d\n", VTOI(vp), (int)bp->b_blkno);
#endif
- if (! (fufh = get_filehandle(vp, NULL, cred, bp->b_iocmd == BIO_READ ? O_RDONLY : O_WRONLY)))
+ if (! (fufh = get_filehandle(vp, NULL, cred, bp->b_iocmd == BIO_READ ? FREAD : FWRITE)))
err = EIO;
if (! err)
@@ -4608,7 +4686,7 @@
{
struct fuse_vnode_data *fvdat = ap->a_vp->v_data;
- printf("nodeid: %d, fh_counter: %d\n", VTOI(ap->a_vp), fvdat->fh_counter);
+ printf("nodeid: %d, fh_counter: %d, nlookup: %llu\n", VTOI(ap->a_vp), fvdat->fh_counter, fvdat->nlookup);
return (0);
}
==== //depot/projects/soc2005/fuse4bsd2/mount_fusefs/mount_fusefs.c#2 (text+ko) ====
@@ -39,29 +39,30 @@
#include "mntopts.h"
-struct mntopt mopts[] = {
- MOPT_STDOPTS,
- { NULL }
-};
-
void usage(void);
int
main(int argc, char *argv[])
{
-#if __FreeBSD_version >= 600000
struct iovec *iov;
-#else
- struct iovec iov[6];
-#endif
int ch, mntflags, iovlen;
char *dev, *dir, mntpath[MAXPATHLEN];
+ iov = NULL;
+ iovlen = 0;
mntflags = 0;
while ((ch = getopt(argc, argv, "o:")) != -1) {
switch(ch) {
case 'o':
- getmntopts(optarg, mopts, &mntflags, 0);
+ if (strcmp(optarg,"fspath") &&
+ strcmp(optarg,"from") &&
+ strcmp(optarg,"allow_other") &&
+ strcmp(optarg,"kernel_cache") &&
+ strcmp(optarg,"direct_io")) {
+ usage();
+ return (1);
+ }
+ build_iovec(&iov, &iovlen, optarg, "", -1);
break;
case '?':
default:
@@ -86,30 +87,11 @@
/* Prepare the options vector for nmount(). build_iovec() is declared
* in mntopts.h. */
-#if __FreeBSD_version >= 600000
- iov = NULL;
- iovlen = 0;
build_iovec(&iov, &iovlen, "fstype", "fusefs", -1);
build_iovec(&iov, &iovlen, "fspath", mntpath, -1);
build_iovec(&iov, &iovlen, "from", dev, -1);
- if (nmount(iov, iovlen, mntflags) < 0)
-#else
- iov[0].iov_base = "fstype";
- iov[0].iov_len = sizeof("fstype");
- iov[1].iov_base = "fusefs";
- iov[1].iov_len = strlen(iov[1].iov_base) + 1;
- iov[2].iov_base = "fspath";
- iov[2].iov_len = sizeof("fspath");
- iov[3].iov_base = mntpath;
- iov[3].iov_len = strlen(mntpath) + 1;
- iov[4].iov_base = "from";
- iov[4].iov_len = sizeof("from");
- iov[5].iov_base = dev;
- iov[5].iov_len = strlen(dev) + 1;
-
- if (nmount(iov, 6, mntflags) < 0)
-#endif
+ if (nmount(iov, iovlen, 0) < 0)
err(EX_OSERR, "%s", dev);
exit(0);
@@ -119,6 +101,9 @@
usage(void)
{
fprintf(stderr,
- "usage: mount_fusefs [-o options] special node\n");
+ "usage: mount_fusefs [-o option...] special node\n"
+ "known options: allow_other kernel_cache direct_io\n"
+ "(multiple options require separate \"-o\"-s)\n");
+
exit(EX_USAGE);
}
More information about the p4-projects
mailing list