diff options
-rw-r--r-- | ChangeLog | 27 | ||||
-rw-r--r-- | python/README | 21 | ||||
-rw-r--r-- | python/_fusemodule.c | 178 | ||||
-rw-r--r-- | python/fuse.py | 110 | ||||
-rwxr-xr-x | python/xmp.py | 202 | ||||
-rw-r--r-- | util/fusermount.c | 34 | ||||
-rw-r--r-- | util/mount.fuse | 85 |
7 files changed, 521 insertions, 136 deletions
@@ -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 diff --git a/python/README b/python/README index 451c56c..3b0d70f 100644 --- a/python/README +++ b/python/README @@ -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 diff --git a/python/_fusemodule.c b/python/_fusemodule.c index 6956be2..557d312 100644 --- a/python/_fusemodule.c +++ b/python/_fusemodule.c @@ -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 - - 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); @@ -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 diff --git a/python/fuse.py b/python/fuse.py index ec1e633..ae621f3 100644 --- a/python/fuse.py +++ b/python/fuse.py @@ -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 diff --git a/python/xmp.py b/python/xmp.py index 271e269..e85faeb 100755 --- a/python/xmp.py +++ b/python/xmp.py @@ -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 diff --git a/util/fusermount.c b/util/fusermount.c index f223c5f..c451c41 100644 --- a/util/fusermount.c +++ b/util/fusermount.c @@ -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); diff --git a/util/mount.fuse b/util/mount.fuse new file mode 100644 index 0000000..4ec1409 --- /dev/null +++ b/util/mount.fuse @@ -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 |