Revamp fs initialization code.

This commit is contained in:
dzsekijo 2006-05-24 05:04:36 +00:00
parent 7b3b54b8d5
commit f148047acd
4 changed files with 152 additions and 77 deletions

View file

@ -1,3 +1,15 @@
2006-05-24 Csaba Henk <csaba.henk@creo.hu>
* Revamp fs initialization code.
- Get rid of both of the kopts/lopts and the fuse_opt stuff,
just keep opts in a dict and assemble a simple argc/argv pair
from that. This means that for all supported API versions we can
get away with the fuse_setup() / *fuse_loop*() / fuse_teardown()
call sequence. This is much more clean and correct than the
earlier approaches, and differenciating between APIs boils down
to differenciating between the exact form of the above routines.
- Properly catch and propagate errors.
- Add crude support for fetching options from command line to xmp.py.
2006-05-23 Csaba Henk <csaba.henk@creo.hu>
* Fix statfs index mismatch in xmp.py.
* Rebase build system on pkg-config.

View file

@ -43,6 +43,8 @@ static PyObject *getattr_cb=NULL, *readlink_cb=NULL, *getdir_cb=NULL,
static int debuglevel=0;
static PyObject *Py_FuseError;
//@-node:globals
//@+node:PROLOGUE
#define PROLOGUE \
@ -449,21 +451,24 @@ static void process_cmd(struct fuse *f, struct fuse_cmd *cmd, void *data)
//@-node:process_cmd
//@+node:pyfuse_loop_mt
static void pyfuse_loop_mt(struct fuse *f)
static int pyfuse_loop_mt(struct fuse *f)
{
PyInterpreterState *interp;
PyThreadState *save;
int err;
PyEval_InitThreads();
interp = PyThreadState_Get()->interp;
save = PyEval_SaveThread();
#if FUSE_VERSION >= 22
fuse_loop_mt_proc(f, process_cmd, interp);
err = fuse_loop_mt_proc(f, process_cmd, interp);
#else
__fuse_loop_mt(f, process_cmd, interp);
err = __fuse_loop_mt(f, process_cmd, interp);
#endif
/* Not yet reached: */
PyEval_RestoreThread(save);
return(err);
}
//@-node:pyfuse_loop_mt
//@+node:Fuse_main
@ -473,40 +478,36 @@ static struct fuse *fuse=NULL;
static PyObject *
Fuse_main(PyObject *self, PyObject *args, PyObject *kw)
{
#if FUSE_VERSION >= 26
struct fuse_chan *chanfd;
#else
int chanfd;
#if FUSE_VERSION < 26
int fd;
#endif
int multithreaded=0;
char *lopts=NULL;
char *kopts=NULL;
int multithreaded=0, mthp;
char *mountpoint;
#if FUSE_VERSION >= 25
struct fuse_args margs = FUSE_ARGS_INIT(0, NULL);
struct fuse_args fargs = FUSE_ARGS_INIT(0, NULL);
#endif
PyObject *fargseq;
int err;
int i;
char *fmp;
struct fuse_operations op;
int fargc;
char **fargv;
static char *kwlist[] = {
"getattr", "readlink", "getdir", "mknod",
"mkdir", "unlink", "rmdir", "symlink", "rename",
"link", "chmod", "chown", "truncate", "utime",
"open", "read", "write", "release", "statfs", "fsync",
"mountpoint", "kopts", "lopts", "multithreaded",
"debug", NULL};
"fuse_args", "mountpoint", "multithreaded", "debug", NULL};
memset(&op, 0, sizeof(op));
if (!PyArg_ParseTupleAndKeywords(args, kw, "|OOOOOOOOOOOOOOOOOOOOsssii",
if (!PyArg_ParseTupleAndKeywords(args, kw, "|OOOOOOOOOOOOOOOOOOOOOsii",
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, &release_cb, &statfs_cb, &fsync_cb,
&mountpoint, &kopts, &lopts, &multithreaded, &debuglevel))
&fargseq, &mountpoint, &multithreaded, &debuglevel))
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(getattr);
@ -530,56 +531,75 @@ Fuse_main(PyObject *self, PyObject *args, PyObject *kw)
DO_ONE_ATTR(statfs);
DO_ONE_ATTR(fsync);
#if FUSE_VERSION >= 25
/*
* XXX: What comes here is just a ridiculous use of the option parsing API
* to hack on compatibility with other parts of the new API. First and
* foremost, real C argc/argv would be good to get at...
*/
#define opts2args(opts, args) \
(opts && \
(fuse_opt_add_arg(args, "") == -1 || \
fuse_opt_add_arg(args, "-o") == -1 || \
fuse_opt_add_arg(args, opts) == -1))
if (opts2args(kopts, &margs) || opts2args(lopts, &fargs)) {
fuse_opt_free_args(&margs);
fuse_opt_free_args(&fargs);
fprintf(stderr, "out of memory\n");
if (fargseq && !PySequence_Check(fargseq)) {
PyErr_SetString(PyExc_TypeError, "fuse_args is not a sequence");
return(NULL);
}
chanfd = fuse_mount(mountpoint,&margs);
fuse_opt_free_args(&margs);
#if FUSE_VERSION >= 26
if (! chanfd)
#else
if (chanfd < 0)
#endif
fprintf(stderr, "could not mount fuse filesystem\n");
fargc = (fargseq ? PySequence_Length(fargseq) : 0) + 2;
fargv = malloc(fargc * sizeof(char *));
if (! fargv)
return(PyErr_NoMemory());
fargv[0] = PyString_AsString(PySequence_GetItem(PySys_GetObject("argv"), 0));
fargv[1] = mountpoint;
if (fargseq) {
for (i=0; i < PySequence_Length(fargseq); i++) {
PyObject *pa;
pa = PySequence_GetItem(fargseq, i);
if (! PyString_Check(pa)) {
PyErr_SetString(PyExc_TypeError,
"fuse argument is not a string");
return(NULL);
}
fargv[i + 2] = PyString_AsString(pa);
}
}
/*
* We don't use the mthp value, set below. We just pass it on so that
* the lib won't end up in dereferring a NULL pointer.
* (Later versions check for NULL, nevertheless we play safe.)
*/
#if FUSE_VERSION >= 26
fuse = fuse_new(chanfd, &fargs, &op, sizeof(op), NULL);
fuse = fuse_setup(fargc, fargv, &op, sizeof(op), &fmp, &mthp, NULL);
#elif FUSE_VERSION >= 22
fuse = fuse_setup(fargc, fargv, &op, sizeof(op), &fmp, &mthp, &fd);
#else
fuse = fuse_new(chanfd, &fargs, &op, sizeof(op));
fuse = __fuse_setup(fargc, fargv, &op, &fmp, &mthp, &fd);
#endif
#else /* FUSE_VERSION >= 25 */
chanfd = fuse_mount(mountpoint, kopts);
#if FUSE_VERSION >= 22
fuse = fuse_new(chanfd, lopts, &op, sizeof(op));
#else
fuse = fuse_new(chanfd, lopts, &op);
#endif
#endif /* FUSE_VERSION >= 25 */
free(fargv);
assert(strcmp(mountpoint, fmp) == 0);
if (fuse == NULL) {
PyErr_SetString(Py_FuseError, "filesystem initialization failed");
return (NULL);
}
if(multithreaded)
pyfuse_loop_mt(fuse);
err = pyfuse_loop_mt(fuse);
else
fuse_loop(fuse);
#if FUSE_VERSION >= 25
fuse_opt_free_args(&fargs);
err = fuse_loop(fuse);
#if FUSE_VERSION >= 26
fuse_teardown(fuse, fmp);
#elif FUSE_VERSION >= 25
fuse_teardown(fuse, fd, fmp);
#elif FUSE_VERSION >= 22
fuse_teardown(fuse, fd, strdup(mountpoint));
#else
__fuse_teardown(fuse, fd, strdup(mountpoint));
#endif
//printf("Fuse_main: called\n");
if (err == -1) {
PyErr_SetString(Py_FuseError, "service loop failed");
return (NULL);
}
Py_INCREF(Py_None);
return Py_None;
@ -658,15 +678,16 @@ DL_EXPORT(void)
init_fuse(void)
{
PyObject *m, *d;
static PyObject *ErrorObject;
/* Create the module and add the functions */
m = Py_InitModule("_fuse", Fuse_methods);
/* Add some symbolic constants to the module */
d = PyModule_GetDict(m);
ErrorObject = PyErr_NewException("fuse.error", NULL, NULL);
PyDict_SetItemString(d, "error", ErrorObject);
Py_FuseError = PyErr_NewException("fuse.FuseError", NULL, NULL);
PyDict_SetItemString(d, "FuseError", Py_FuseError);
/* compat */
PyDict_SetItemString(d, "error", Py_FuseError);
// PyDict_SetItemString(d, "DEBUG", PyInt_FromLong(FUSE_DEBUG));
}
//@-node:DL_EXPORT

61
fuse.py
View file

@ -21,7 +21,7 @@ try:
except:
pass
from _fuse import main, FuseGetContext, FuseInvalidate
from _fuse import main, FuseGetContext, FuseInvalidate, FuseError
from string import join
import sys
from errno import *
@ -75,7 +75,17 @@ class Fuse:
self.mountpoint = self.optlist[0]
else:
self.mountpoint = None
# This kind of forced commandline parsing still sucks,
# but:
# - changing it would hurt compatibility
# - if changed, that should be done cleverly:
# either by calling down to fuse_opt or coded
# purely in python, it should cherry-pick
# some args/opts based on a template and place
# that into a dict, and return the rest, so that
# can be passed to fuselib
# grab command-line arguments, if any.
# Those will override whatever parameters
# were passed to __init__ directly.
@ -107,23 +117,48 @@ class Fuse:
d = {'mountpoint': self.mountpoint}
d['multithreaded'] = self.multithreaded
if hasattr( self, 'debug'):
d['lopts'] = 'debug';
k=[]
if hasattr(self,'allow_other'):
k.append('allow_other')
if not hasattr(self, 'fuse_opt_list'):
self.fuse_opt_list = []
if hasattr(self,'kernel_cache'):
k.append('kernel_cache')
# deprecated direct attributes for some fuse options
for a in 'debug', 'allow_other', 'kernel_cache':
if hasattr(self, a):
self.fuse_opt_list.append(a);
if not hasattr(self, 'fuse_opts'):
self.fuse_opts = {}
for o in self.fuse_opt_list:
self.fuse_opts[o] = True
nomount = False
d['fuse_args'] = []
# Regarding those lib options which are direct options
# (used as `-x' or `--foo', rather than `-o foo'):
# we still prefer to have them as attributes
for a in 'help', 'version':
if hasattr(self, 'show' + a):
d['fuse_args'].append('--' + a)
nomount = True
if hasattr(self, 'foreground'):
d['fuse_args'].append('-f')
opta = []
for k in self.fuse_opts.keys():
if self.fuse_opts[k] == True:
opta.append(str(k))
else:
opta.append(str(k) + '=' + str(self.fuse_opts[k]))
d['fuse_args'].append("-o" + ",".join(opta))
if len(k):
d['kopts'] = join(k,',')
for a in self._attrs:
if hasattr(self,a):
d[a] = ErrnoWrapper(getattr(self, a))
apply(main, (), d)
try:
apply(main, (), d)
except FuseError:
if not nomount: raise
#@-node:main
#@-others
#@-node:class Fuse

7
xmp.py
View file

@ -191,6 +191,13 @@ if __name__ == '__main__':
server = Xmp()
server.multithreaded = 1;
# pass on cmdline arguments to FUSE, ending up with the very crude
# syntax "xmp.py mp opt1 ...", ie. we can type things like
# "xmp.py /mnt/fuse debug max_read=4096"
# (This looks bad, but it's _not_ xmp.py who should properly parse the
# arguments, so we don't do anything more sophisticated here ATM.)
server.fuse_opt_list = server.optlist
server.fuse_opts = server.optdict
server.main()
#@-node:mainline
#@-others