+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
+#@+leo-ver=4
+#@+node:@file README
+#@@comment
+
+
General Information
===================
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
===========
[1] http://www.python.org
[2] http://sourceforge.net/projects/avf/
[3] http://unpythonic.dhs.org/~jepler/fuse/
+#@-node:@file README
+#@-leo
+//@+leo-ver=4
+//@+node:@file _fusemodule.c
+//@@language c
/*
Copyright (C) 2001 Jeff Epler <jepler@unpythonic.dhs.org>
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
-
- 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;
- }
+int i;
+PyObject *v = PyObject_CallFunction(getattr_cb, "s", path);
+PROLOGUE
- 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;
+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;
+}
- ret = 0;
- EPILOGUE
+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);
EPILOGUE
}
+//@-node:readlink_func
+//@+node:getdir_add_entry
static int getdir_add_entry(PyObject *w, fuse_dirh_t dh, fuse_dirfil_t df)
{
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)
{
EPILOGUE
}
+//@-node:getdir_func
+//@+node:mknod_func
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)
{
PROLOGUE
EPILOGUE
}
+//@-node:mkdir_func
+//@+node:unlink_func
static int unlink_func(const char *path)
{
PROLOGUE
EPILOGUE
}
+//@-node:unlink_func
+//@+node:rmdir_func
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)
{
PROLOGUE
EPILOGUE
}
+//@-node:symlink_func
+//@+node:rename_func
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)
{
PROLOGUE
EPILOGUE
}
+//@-node:link_func
+//@+node:chmod_func
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)
{
PROLOGUE
EPILOGUE
}
+//@-node:chown_func
+//@+node:truncate_func
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);
PROLOGUE
EPILOGUE
}
+//@-node:utime_func
+//@+node:read_func
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)
{
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)
{
PyThreadState_Delete(state);
PyEval_ReleaseLock();
}
+//@-node:process_cmd
+//@+node:pyfuse_loop_mt
static void pyfuse_loop_mt(struct fuse *f)
{
/* Not yet reached: */
PyEval_RestoreThread(save);
}
+//@-node:pyfuse_loop_mt
+//@+node:Fuse_main
static PyObject *
"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; }
DO_ONE_ATTR(open);
DO_ONE_ATTR(read);
DO_ONE_ATTR(write);
+ DO_ONE_ATTR(release);
fuse = fuse_new(0, flags, &op);
if(multithreaded)
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},
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
+#@+leo-ver=4
+#@+node:@file fuse.py
#
# Copyright (C) 2001 Jeff Epler <jepler@unpythonic.dhs.org>
#
# 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
#!/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>
#
# 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
}
}
+/* 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;
const char *dev = FUSE_DEV;
const char *type = "fuse";
struct stat stbuf;
+ int mtablock;
res = check_perm(mnt, &stbuf);
if(res == -1)
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;
restore_privs();
if(unmount) {
+ int mtablock = lock_mtab();
res = remove_mount(mnt);
+ unlock_mtab(mtablock);
if(res == -1)
exit(1);
--- /dev/null
+#!/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