This commit is contained in:
Miklos Szeredi 2003-12-11 14:27:57 +00:00
parent 406bf11df0
commit 874d95da5b
7 changed files with 522 additions and 137 deletions

View File

@ -1,3 +1,30 @@
2003-12-11 Miklos Szeredi <mszeredi@inf.bme.hu>
* Add file locking for mount/unmount (based on patch by Valient
Gough)
2003-12-11 David McNab <david@rebirthing.co.nz>
* Python filesystem - was broken with python2.3, now fixed:
- changed PyTuple_* calls to PySequence_*, because os.lstat
is no longer returning a pure tuple
- changed PyInt_Check() calls to also call PyLong_Check,
to cover for cases (eg os.lstat) where longs are returned
- Added support for file 'release' handling, which IMO is
essential since this signals to a FS that writes to a file
are complete (and therefore the file can now be disposed of
meaningfully at the python filesystem's discretion)
- Added '__init__' handler to base Fuse class, which allows
your Python class to know the mountpoint and mount args,
as attributes myfs.mountpoint, myfs.optlist, myfs.optdict
* General:
- added 'mount.fuse' script (in util/ dir), which is meant to be
symlinked from /sbin, and which allows FUSE filesystems to
be mounted with the 'mount' command, and listed in fstab;
also, mount arguments get passed to your filesystem
2003-11-04 Miklos Szeredi <mszeredi@inf.bme.hu>
* Fix kernel version detection (again). Bugreport by Peter Levart

View File

@ -1,3 +1,8 @@
#@+leo-ver=4
#@+node:@file README
#@@comment
General Information
===================
@ -22,6 +27,20 @@ for some reason,
fusermount <mount point> python <script name>
does not seem to work. (why?)
Update
======
Updated Dec 2003 by David McNab <david@rebirthing.co.nz>:
- added support for 'release' events (ie when file gets closed)
- added __init__ to base class, which picks off parameters and
stores them as instance attributes:
- self.mountpoint - the mountpoint as given in the mount command
- self.optlist - unnamed options (eg 'rw', 'exec' etc)
- self.optdict - named options (eg, '-o arg1=val1,arg2=val2...' from mount cmd)
- fixed incompatibility issues with recent pythons (original was broken
under python2.3)
Limitations
===========
@ -58,3 +77,5 @@ License, Version 2. Future versions, if any, will be available at [3].
[1] http://www.python.org
[2] http://sourceforge.net/projects/avf/
[3] http://unpythonic.dhs.org/~jepler/fuse/
#@-node:@file README
#@-leo

View File

@ -1,3 +1,6 @@
//@+leo-ver=4
//@+node:@file _fusemodule.c
//@@language c
/*
Copyright (C) 2001 Jeff Epler <jepler@unpythonic.dhs.org>
@ -5,59 +8,84 @@
See the file COPYING.
*/
//@+others
//@+node:includes
#include <Python.h>
#include <fuse.h>
#include <time.h>
//@-node:includes
//@+node:globals
static PyObject *getattr_cb=NULL, *readlink_cb=NULL, *getdir_cb=NULL,
*mknod_cb=NULL, *mkdir_cb=NULL, *unlink_cb=NULL, *rmdir_cb=NULL,
*symlink_cb=NULL, *rename_cb=NULL, *link_cb=NULL, *chmod_cb=NULL,
*chown_cb=NULL, *truncate_cb=NULL, *utime_cb=NULL,
*open_cb=NULL, *read_cb=NULL, *write_cb=NULL;
*open_cb=NULL, *read_cb=NULL, *write_cb=NULL, *release_cb=NULL;
//@-node:globals
//@+node:PROLOGUE
#define PROLOGUE \
int ret = -EINVAL; \
if (!v) { PyErr_Print(); goto OUT; } \
if(v == Py_None) { ret = 0; goto OUT_DECREF; } \
if(PyInt_Check(v)) { ret = PyInt_AsLong(v); goto OUT_DECREF; }
int ret = -EINVAL; \
if (!v) { PyErr_Print(); goto OUT; } \
if(v == Py_None) { ret = 0; goto OUT_DECREF; } \
if(PyInt_Check(v)) { ret = PyInt_AsLong(v); goto OUT_DECREF; }
//@-node:PROLOGUE
//@+node:EPILOGUE
#define EPILOGUE \
OUT_DECREF: \
Py_DECREF(v); \
OUT: \
return ret;
OUT_DECREF: \
Py_DECREF(v); \
OUT: \
return ret;
//@-node:EPILOGUE
//@+node:getattr_func
/*
* Local Variables:
* indent-tabs-mode: t
* c-basic-offset: 8
* End:
* Changed by David McNab (david@rebirthing.co.nz) to work with recent pythons.
* Namely, replacing PyTuple_* with PySequence_*, and checking numerical values
* with both PyInt_Check and PyLong_Check.
*/
static int getattr_func(const char *path, struct stat *st)
{
int i;
PyObject *v = PyObject_CallFunction(getattr_cb, "s", path);
PROLOGUE
int i;
PyObject *v = PyObject_CallFunction(getattr_cb, "s", path);
PROLOGUE
if(!PyTuple_Check(v)) { goto OUT_DECREF; }
if(PyTuple_Size(v) < 10) { goto OUT_DECREF; }
for(i=0; i<10; i++) {
if (!PyInt_Check(PyTuple_GetItem(v, 0))) goto OUT_DECREF;
}
st->st_mode = PyInt_AsLong(PyTuple_GetItem(v, 0));
st->st_ino = PyInt_AsLong(PyTuple_GetItem(v, 1));
st->st_dev = PyInt_AsLong(PyTuple_GetItem(v, 2));
st->st_nlink= PyInt_AsLong(PyTuple_GetItem(v, 3));
st->st_uid = PyInt_AsLong(PyTuple_GetItem(v, 4));
st->st_gid = PyInt_AsLong(PyTuple_GetItem(v, 5));
st->st_size = PyInt_AsLong(PyTuple_GetItem(v, 6));
st->st_atime= PyInt_AsLong(PyTuple_GetItem(v, 7));
st->st_mtime= PyInt_AsLong(PyTuple_GetItem(v, 8));
st->st_ctime= PyInt_AsLong(PyTuple_GetItem(v, 9));
/* Fill in fields not provided by Python lstat() */
st->st_blksize= 4096;
st->st_blocks= (st->st_size + 511)/512;
st->st_ino = 0;
ret = 0;
EPILOGUE
if(!PySequence_Check(v)) { goto OUT_DECREF; }
if(PySequence_Size(v) < 10) { goto OUT_DECREF; }
for(i=0; i<10; i++)
{
PyObject *tmp = PySequence_GetItem(v, i);
if (!(PyInt_Check(tmp) || PyLong_Check(tmp))) goto OUT_DECREF;
}
st->st_mode = PyInt_AsLong(PySequence_GetItem(v, 0));
st->st_ino = PyInt_AsLong(PySequence_GetItem(v, 1));
st->st_dev = PyInt_AsLong(PySequence_GetItem(v, 2));
st->st_nlink= PyInt_AsLong(PySequence_GetItem(v, 3));
st->st_uid = PyInt_AsLong(PySequence_GetItem(v, 4));
st->st_gid = PyInt_AsLong(PySequence_GetItem(v, 5));
st->st_size = PyInt_AsLong(PySequence_GetItem(v, 6));
st->st_atime= PyInt_AsLong(PySequence_GetItem(v, 7));
st->st_mtime= PyInt_AsLong(PySequence_GetItem(v, 8));
st->st_ctime= PyInt_AsLong(PySequence_GetItem(v, 9));
/* Fill in fields not provided by Python lstat() */
st->st_blksize= 4096;
st->st_blocks= (st->st_size + 511)/512;
st->st_ino = 0;
ret = 0;
EPILOGUE
}
//@-node:getattr_func
//@+node:readlink_func
static int readlink_func(const char *path, char *link, size_t size)
{
PyObject *v = PyObject_CallFunction(readlink_cb, "s", path);
@ -72,6 +100,8 @@ static int readlink_func(const char *path, char *link, size_t size)
EPILOGUE
}
//@-node:readlink_func
//@+node:getdir_add_entry
static int getdir_add_entry(PyObject *w, fuse_dirh_t dh, fuse_dirfil_t df)
{
@ -108,6 +138,8 @@ out_decref:
out:
return ret;
}
//@-node:getdir_add_entry
//@+node:getdir_func
static int getdir_func(const char *path, fuse_dirh_t dh, fuse_dirfil_t df)
{
@ -130,6 +162,8 @@ static int getdir_func(const char *path, fuse_dirh_t dh, fuse_dirfil_t df)
EPILOGUE
}
//@-node:getdir_func
//@+node:mknod_func
static int mknod_func(const char *path, mode_t m, dev_t d)
{
@ -137,6 +171,8 @@ static int mknod_func(const char *path, mode_t m, dev_t d)
PROLOGUE
EPILOGUE
}
//@-node:mknod_func
//@+node:mkdir_func
static int mkdir_func(const char *path, mode_t m)
{
@ -144,6 +180,8 @@ static int mkdir_func(const char *path, mode_t m)
PROLOGUE
EPILOGUE
}
//@-node:mkdir_func
//@+node:unlink_func
static int unlink_func(const char *path)
{
@ -151,6 +189,8 @@ static int unlink_func(const char *path)
PROLOGUE
EPILOGUE
}
//@-node:unlink_func
//@+node:rmdir_func
static int rmdir_func(const char *path)
{
@ -158,6 +198,8 @@ static int rmdir_func(const char *path)
PROLOGUE
EPILOGUE
}
//@-node:rmdir_func
//@+node:symlink_func
static int symlink_func(const char *path, const char *path1)
{
@ -165,6 +207,8 @@ static int symlink_func(const char *path, const char *path1)
PROLOGUE
EPILOGUE
}
//@-node:symlink_func
//@+node:rename_func
static int rename_func(const char *path, const char *path1)
{
@ -172,6 +216,8 @@ static int rename_func(const char *path, const char *path1)
PROLOGUE
EPILOGUE
}
//@-node:rename_func
//@+node:link_func
static int link_func(const char *path, const char *path1)
{
@ -179,6 +225,8 @@ static int link_func(const char *path, const char *path1)
PROLOGUE
EPILOGUE
}
//@-node:link_func
//@+node:chmod_func
static int chmod_func(const char *path, mode_t m)
{
@ -186,6 +234,8 @@ static int chmod_func(const char *path, mode_t m)
PROLOGUE
EPILOGUE
}
//@-node:chmod_func
//@+node:chown_func
static int chown_func(const char *path, uid_t u, gid_t g)
{
@ -193,6 +243,8 @@ static int chown_func(const char *path, uid_t u, gid_t g)
PROLOGUE
EPILOGUE
}
//@-node:chown_func
//@+node:truncate_func
static int truncate_func(const char *path, off_t o)
{
@ -200,6 +252,8 @@ static int truncate_func(const char *path, off_t o)
PROLOGUE
EPILOGUE
}
//@-node:truncate_func
//@+node:utime_func
static int utime_func(const char *path, struct utimbuf *u) {
int actime = u ? u->actime : time(NULL);
@ -209,6 +263,8 @@ static int utime_func(const char *path, struct utimbuf *u) {
PROLOGUE
EPILOGUE
}
//@-node:utime_func
//@+node:read_func
static int read_func(const char *path, char *buf, size_t s, off_t off)
{
@ -221,6 +277,8 @@ static int read_func(const char *path, char *buf, size_t s, off_t off)
}
EPILOGUE
}
//@-node:read_func
//@+node:write_func
static int write_func(const char *path, const char *buf, size_t t, off_t off)
{
@ -228,13 +286,28 @@ static int write_func(const char *path, const char *buf, size_t t, off_t off)
PROLOGUE
EPILOGUE
}
//@-node:write_func
//@+node:open_func
static int open_func(const char *path, int mode)
{
PyObject *v = PyObject_CallFunction(open_cb, "si", path, mode);
PROLOGUE
printf("open_func: path=%s\n", path);
EPILOGUE
}
//@-node:open_func
//@+node:release_func
static int release_func(const char *path)
{
PyObject *v = PyObject_CallFunction(release_cb, "s", path);
PROLOGUE
printf("release_func: path=%s\n", path);
EPILOGUE
}
//@-node:release_func
//@+node:process_cmd
static void process_cmd(struct fuse *f, struct fuse_cmd *cmd, void *data)
{
@ -250,6 +323,8 @@ static void process_cmd(struct fuse *f, struct fuse_cmd *cmd, void *data)
PyThreadState_Delete(state);
PyEval_ReleaseLock();
}
//@-node:process_cmd
//@+node:pyfuse_loop_mt
static void pyfuse_loop_mt(struct fuse *f)
{
@ -263,6 +338,8 @@ static void pyfuse_loop_mt(struct fuse *f)
/* Not yet reached: */
PyEval_RestoreThread(save);
}
//@-node:pyfuse_loop_mt
//@+node:Fuse_main
static PyObject *
@ -278,15 +355,15 @@ Fuse_main(PyObject *self, PyObject *args, PyObject *kw)
"getattr", "readlink", "getdir", "mknod",
"mkdir", "unlink", "rmdir", "symlink", "rename",
"link", "chmod", "chown", "truncate", "utime",
"open", "read", "write", "flags", "multithreaded", NULL};
"open", "read", "write", "release", "flags", "multithreaded", NULL};
memset(&op, 0, sizeof(op));
if (!PyArg_ParseTupleAndKeywords(args, kw, "|OOOOOOOOOOOOOOOOOii",
if (!PyArg_ParseTupleAndKeywords(args, kw, "|OOOOOOOOOOOOOOOOOOii",
kwlist, &getattr_cb, &readlink_cb, &getdir_cb, &mknod_cb,
&mkdir_cb, &unlink_cb, &rmdir_cb, &symlink_cb, &rename_cb,
&link_cb, &chmod_cb, &chown_cb, &truncate_cb, &utime_cb,
&open_cb, &read_cb, &write_cb, &flags, &multithreaded))
&open_cb, &read_cb, &write_cb, &release_cb, &flags, &multithreaded))
return NULL;
#define DO_ONE_ATTR(name) if(name ## _cb) { Py_INCREF(name ## _cb); op.name = name ## _func; } else { op.name = NULL; }
@ -308,6 +385,7 @@ Fuse_main(PyObject *self, PyObject *args, PyObject *kw)
DO_ONE_ATTR(open);
DO_ONE_ATTR(read);
DO_ONE_ATTR(write);
DO_ONE_ATTR(release);
fuse = fuse_new(0, flags, &op);
if(multithreaded)
@ -315,11 +393,18 @@ Fuse_main(PyObject *self, PyObject *args, PyObject *kw)
else
fuse_loop(fuse);
//printf("Fuse_main: called\n");
Py_INCREF(Py_None);
return Py_None;
}
/* List of functions defined in the module */
//@-node:Fuse_main
//@+node:DL_EXPORT
//@+at
//@nonl
// List of functions defined in the module
//@-at
//@@c
static PyMethodDef Fuse_methods[] = {
{"main", (PyCFunction)Fuse_main, METH_VARARGS|METH_KEYWORDS},
@ -344,11 +429,8 @@ init_fuse(void)
PyDict_SetItemString(d, "error", ErrorObject);
PyDict_SetItemString(d, "DEBUG", PyInt_FromLong(FUSE_DEBUG));
}
//@-node:DL_EXPORT
//@-others
/*
* Local Variables:
* indent-tabs-mode: t
* c-basic-offset: 8
* End:
*/
//@-node:@file _fusemodule.c
//@-leo

View File

@ -1,3 +1,5 @@
#@+leo-ver=4
#@+node:@file fuse.py
#
# Copyright (C) 2001 Jeff Epler <jepler@unpythonic.dhs.org>
#
@ -5,34 +7,92 @@
# See the file COPYING.
#
#@@language python
#@+others
#@+node:imports
# suppress version mismatch warnings
try:
import warnings
warnings.filterwarnings('ignore',
'Python C API version mismatch',
RuntimeWarning,
)
except:
pass
from _fuse import main, DEBUG
import os
import os, sys
from errno import *
#@-node:imports
#@+node:class ErrnoWrapper
class ErrnoWrapper:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kw):
try:
return apply(self.func, args, kw)
except (IOError, OSError), detail:
# Sometimes this is an int, sometimes an instance...
if hasattr(detail, "errno"): detail = detail.errno
return -detail
#@ @+others
#@+node:__init__
def __init__(self, func):
self.func = func
#@-node:__init__
#@+node:__call__
def __call__(self, *args, **kw):
try:
return apply(self.func, args, kw)
except (IOError, OSError), detail:
# Sometimes this is an int, sometimes an instance...
if hasattr(detail, "errno"): detail = detail.errno
return -detail
#@-node:__call__
#@-others
#@-node:class ErrnoWrapper
#@+node:class Fuse
class Fuse:
_attrs = ['getattr', 'readlink', 'getdir', 'mknod', 'mkdir',
'unlink', 'rmdir', 'symlink', 'rename', 'link', 'chmod',
'chown', 'truncate', 'utime', 'open', 'read', 'write']
flags = 0
multithreaded = 0
def main(self):
d = {'flags': self.flags}
d['multithreaded'] = self.multithreaded
for a in self._attrs:
if hasattr(self,a):
d[a] = ErrnoWrapper(getattr(self, a))
apply(main, (), d)
#@ @+others
#@+node:attribs
_attrs = ['getattr', 'readlink', 'getdir', 'mknod', 'mkdir',
'unlink', 'rmdir', 'symlink', 'rename', 'link', 'chmod',
'chown', 'truncate', 'utime', 'open', 'read', 'write', 'release']
flags = 0
multithreaded = 0
#@-node:attribs
#@+node:__init__
def __init__(self, *args, **kw):
# default attributes
self.optlist = []
self.optdict = {}
self.mountpoint = None
# grab arguments, if any
argv = sys.argv
argc = len(argv)
if argc > 1:
# we've been given the mountpoint
self.mountpoint = argv[1]
if argc > 2:
# we've received mount args
optstr = argv[2]
opts = optstr.split(",")
for o in opts:
try:
k, v = o.split("=", 1)
self.optdict[k] = v
except:
self.optlist.append(o)
#@-node:__init__
#@+node:main
def main(self):
d = {'flags': self.flags}
d['multithreaded'] = self.multithreaded
for a in self._attrs:
if hasattr(self,a):
d[a] = ErrnoWrapper(getattr(self, a))
apply(main, (), d)
#@-node:main
#@-others
#@-node:class Fuse
#@-others
#@-node:@file fuse.py
#@-leo

View File

@ -1,4 +1,7 @@
#!/usr/bin/env python
#@+leo-ver=4
#@+node:@file xmp.py
#@@first #!/usr/bin/env python
#
# Copyright (C) 2001 Jeff Epler <jepler@unpythonic.dhs.org>
#
@ -6,78 +9,153 @@
# See the file COPYING.
#
#@+others
#@+node:imports
from fuse import Fuse
import os
from errno import *
from stat import *
import thread
#@-node:imports
#@+node:class Xmp
class Xmp(Fuse):
flags = 1
def getattr(self, path):
return os.lstat(path)
def readlink(self, path):
return os.readlink(path)
def getdir(self, path):
return map(lambda x: (x,0), os.listdir(path))
def unlink(self, path):
return os.unlink(path)
def rmdir(self, path):
return os.rmdir(path)
def symlink(self, path, path1):
return os.symlink(path, path1)
def rename(self, path, path1):
return os.rename(path, path1)
def link(self, path, path1):
return os.link(path, path1)
def chmod(self, path, mode):
return os.chmod(path, mode)
def chown(self, path, user, group):
return os.chown(path, user, group)
def truncate(self, path, size):
f = open(path, "w+")
return f.truncate(size)
def mknod(self, path, mode, dev):
""" Python has no os.mknod, so we can only do some things """
if S_ISREG(mode):
open(path, "w")
else:
return -EINVAL
def mkdir(self, path, mode):
return os.mkdir(path, mode)
def utime(self, path, times):
return os.utime(path, times)
def open(self, path, flags):
os.close(os.open(path, flags))
return 0
def read(self, path, len, offset):
f = open(path, "r")
f.seek(offset)
return f.read(len)
def write(self, path, buf, off):
f = open(path, "r+")
f.seek(off)
f.write(buf)
return len(buf)
#@ @+others
#@+node:__init__
def __init__(self, *args, **kw):
Fuse.__init__(self, *args, **kw)
if 1:
print "mountpoint: %s" % repr(self.mountpoint)
print "unnamed mount options: %s" % self.optlist
print "named mount options: %s" % self.optdict
# do stuff to set up your filesystem here, if you want
#thread.start_new_thread(self.mythread, ())
pass
#@-node:__init__
#@+node:mythread
def mythread(self):
"""
The beauty of the FUSE python implementation is that with the python interp
running in foreground, you can have threads
"""
print "mythread: started"
#while 1:
# time.sleep(120)
# print "mythread: ticking"
#@-node:mythread
#@+node:attribs
flags = 1
#@-node:attribs
#@+node:getattr
def getattr(self, path):
return os.lstat(path)
#@-node:getattr
#@+node:readlink
def readlink(self, path):
return os.readlink(path)
#@-node:readlink
#@+node:getdir
def getdir(self, path):
return map(lambda x: (x,0), os.listdir(path))
#@-node:getdir
#@+node:unlink
def unlink(self, path):
return os.unlink(path)
#@-node:unlink
#@+node:rmdir
def rmdir(self, path):
return os.rmdir(path)
#@-node:rmdir
#@+node:symlink
def symlink(self, path, path1):
return os.symlink(path, path1)
#@-node:symlink
#@+node:rename
def rename(self, path, path1):
return os.rename(path, path1)
#@-node:rename
#@+node:link
def link(self, path, path1):
return os.link(path, path1)
#@-node:link
#@+node:chmod
def chmod(self, path, mode):
return os.chmod(path, mode)
#@-node:chmod
#@+node:chown
def chown(self, path, user, group):
return os.chown(path, user, group)
#@-node:chown
#@+node:truncate
def truncate(self, path, size):
f = open(path, "w+")
return f.truncate(size)
#@-node:truncate
#@+node:mknod
def mknod(self, path, mode, dev):
""" Python has no os.mknod, so we can only do some things """
if S_ISREG(mode):
open(path, "w")
else:
return -EINVAL
#@-node:mknod
#@+node:mkdir
def mkdir(self, path, mode):
return os.mkdir(path, mode)
#@-node:mkdir
#@+node:utime
def utime(self, path, times):
return os.utime(path, times)
#@-node:utime
#@+node:open
def open(self, path, flags):
#print "open: %s" % path
os.close(os.open(path, flags))
return 0
#@-node:open
#@+node:read
def read(self, path, len, offset):
#print "read: %s" % path
f = open(path, "r")
f.seek(offset)
return f.read(len)
#@-node:read
#@+node:write
def write(self, path, buf, off):
#print "write: %s" % path
f = open(path, "r+")
f.seek(off)
f.write(buf)
return len(buf)
#@-node:write
#@+node:release
def release(self, path):
#print "release: %s" % path
return 0
#@-node:release
#@-others
#@-node:class Xmp
#@+node:mainline
if __name__ == '__main__':
server = Xmp()
server.flags = 0
server.multithreaded = 1;
server.main()
#@-node:mainline
#@-others
#@-node:@file xmp.py
#@-leo

View File

@ -59,6 +59,33 @@ static const char *get_user_name()
}
}
/* use a lock file so that multiple fusermount processes don't try and
modify the mtab file at once! */
static int lock_mtab()
{
const char *mtab_lock = _PATH_MOUNTED ".fuselock";
int mtablock;
int res;
mtablock = open(mtab_lock, O_RDWR | O_CREAT, 0600);
if(mtablock >= 0) {
res = lockf(mtablock, F_LOCK, 0);
if(res < 0)
perror("error getting lock: %s");
} else
fprintf(stderr, "unable to open fuse lock file, continuing anyway\n");
return mtablock;
}
static void unlock_mtab(int mtablock)
{
if(mtablock >= 0) {
lockf(mtablock, F_ULOCK, 0);
close(mtablock);
}
}
static int add_mount(const char *dev, const char *mnt, const char *type)
{
int res;
@ -343,6 +370,7 @@ static int mount_fuse(const char *mnt, int flags)
const char *dev = FUSE_DEV;
const char *type = "fuse";
struct stat stbuf;
int mtablock;
res = check_perm(mnt, &stbuf);
if(res == -1)
@ -371,8 +399,10 @@ static int mount_fuse(const char *mnt, int flags)
res = do_mount(dev, mnt, type, stbuf.st_mode & S_IFMT, fd, flags);
if(res == -1)
return -1;
mtablock = lock_mtab();
res = add_mount(dev, mnt, type);
unlock_mtab(mtablock);
if(res == -1) {
umount(mnt);
return -1;
@ -530,7 +560,9 @@ int main(int argc, char *argv[])
restore_privs();
if(unmount) {
int mtablock = lock_mtab();
res = remove_mount(mnt);
unlock_mtab(mtablock);
if(res == -1)
exit(1);

85
util/mount.fuse Normal file
View File

@ -0,0 +1,85 @@
#!/usr/bin/env python
#@+leo-ver=4
#@+node:@file mount.fuse
#@@first #!/usr/bin/env python
"""
This utility allows FUSE filesystems to be mounted with the regular *nix
'mount' command, or even be listed in /etc/fstab
To enable this, you need to:
1. set execute-permission on this script
2. symlink this script into /sbin/mount.fuse
Usage:
You can use this in 3 ways:
1. mount -t fuse /path/to/script/or/program /path/of/mount/point [options]
2. mount -t fuse none /path/of/mount/point -o fs=/path/to/script/or/prog[,opt=val...]
3. in /etc/fstab, add:
/path/to/script/or/prog /path/of/mount/point fuse noauto[,...]
"""
import sys, os, time
progname = sys.argv[0]
def usage(ret):
print "Usage: %s /path/to/fuse/fs /path/of/mountpoint [-o options]" % progname
print "or: %s none /path/of/mountpoint [-o fs=/path/to/fuse/fs[,...]]" % progname
sys.exit(ret)
def main():
# initial sanity check
argc = len(sys.argv)
if argc < 3 or sys.argv[3] != "-o":
usage(1)
dev = sys.argv[1]
mountpoint = sys.argv[2]
# grab options, if any
optdict = {}
optlist = []
if argc > 4:
odata = sys.argv[4]
opts = odata.split(",")
#print opts
for o in opts:
try:
k, v = o.split("=", 1)
optdict[k] = v
except:
optlist.append(o)
else:
odata = ""
#print sys.argv
if dev == 'none':
if not optdict.has_key("fs"):
print "%s: Must specify python file with 'fs' option\n" % progname
usage(1)
pyfile = optdict['fs']
else:
pyfile = dev
if not os.path.isfile(pyfile):
print "%s: file %s doesn't exist, or is not a file" % (progname, pyfile)
sys.exit(1)
pypath = os.path.abspath(pyfile)
#print optdict, optlist
# all seems ok - run our fuse fs as a child
if os.fork() == 0:
os.system("fusermount -c -x %s %s %s %s" % (mountpoint, pypath, mountpoint, odata))
else:
#print "parent exiting..."
pass
if __name__ == '__main__':
main()
#@-node:@file mount.fuse
#@-leo