diff --git a/include/fuse.h b/include/fuse.h index 04ab31b..8d7de4b 100644 --- a/include/fuse.h +++ b/include/fuse.h @@ -959,13 +959,10 @@ void fuse_register_module(struct fuse_module *mod); * For the parameters, see description of the fields in 'struct * fuse_module' */ -#define FUSE_REGISTER_MODULE(name_, factory_) \ - static __attribute__((constructor)) void name_ ## _register(void) \ - { \ - static struct fuse_module mod = \ - { #name_, factory_, NULL, NULL, 0 }; \ - fuse_register_module(&mod); \ - } +#define FUSE_REGISTER_MODULE(name_, factory_) \ + struct fuse_module fuse_fusemod_ ## name_ ## _module = { \ + #name_, factory_, NULL, NULL, 0 \ + }; /* ----------------------------------------------------------- * diff --git a/lib/fuse.c b/lib/fuse.c index 885c9ce..fd38322 100644 --- a/lib/fuse.c +++ b/lib/fuse.c @@ -219,41 +219,76 @@ struct fuse_context_i { fuse_req_t req; }; +/* Defined by FUSE_REGISTER_MODULE() in lib/modules/subdir.c and iconv.c. */ +extern struct fuse_module fuse_fusemod_subdir_module; +extern struct fuse_module fuse_fusemod_iconv_module; + static pthread_key_t fuse_context_key; static pthread_mutex_t fuse_context_lock = PTHREAD_MUTEX_INITIALIZER; static int fuse_context_ref; static struct fusemod_so *fuse_current_so; -static struct fuse_module *fuse_modules; +static struct fuse_module *fuse_modules = NULL; -static int fuse_load_so_name(const char *soname) +static int fuse_load_so_name(const char *soname, const char *module_name) { struct fusemod_so *so; + int ret = 0; so = calloc(1, sizeof(struct fusemod_so)); if (!so) { fprintf(stderr, "fuse: memory allocation failed\n"); - return -1; + ret = -1; + goto end; } fuse_current_so = so; - so->handle = dlopen(soname, RTLD_NOW); + + so->handle = dlopen (soname, RTLD_NOW); + if (so->handle == NULL) { + fprintf (stderr, "fuse: dlopen() failed: %s\n", dlerror ()); + ret = -1; + goto freeso_end; + } + + const size_t module_len = strlen (module_name); + char *symbol = malloc (64 + module_len); + if (symbol == NULL) { + perror ("fuse"); + ret = -1; + goto dlopen_end; + } + + sprintf (symbol, "fuse_fusemod_%s_module", module_name); + + struct fuse_module *module; + module = dlsym (so->handle, symbol); + if (module != NULL) { + fuse_register_module (module); + } + fuse_current_so = NULL; - if (!so->handle) { - fprintf(stderr, "fuse: %s\n", dlerror()); - goto err; - } + if (!so->ctr) { fprintf(stderr, "fuse: %s did not register any modules\n", soname); - goto err; + ret = -1; + goto freesym_end; } - return 0; -err: - if (so->handle) - dlclose(so->handle); - free(so); - return -1; +freesym_end: + free (symbol); +dlopen_end: + if (ret != 0) { + /* dlclose() only on error, otherwise we won't have + * access to the .so anymore. */ + if (dlclose (so->handle)) { + fprintf (stderr, "fuse: dlclose() failed: %s\n", dlerror ()); + } + } +freeso_end: + free (so); +end: + return ret; } static int fuse_load_so_module(const char *module) @@ -265,14 +300,14 @@ static int fuse_load_so_module(const char *module) return -1; } sprintf(soname, "libfusemod_%s.so", module); - res = fuse_load_so_name(soname); + res = fuse_load_so_name(soname, module); free(soname); return res; } static struct fuse_module *fuse_find_module(const char *module) { - struct fuse_module *m; + struct fuse_module *m; for (m = fuse_modules; m; m = m->next) { if (strcmp(module, m->name) == 0) { m->ctr++; @@ -4672,6 +4707,15 @@ struct fuse *fuse_new_common(struct fuse_chan *ch, struct fuse_args *args, struct fuse_fs *fs; struct fuse_lowlevel_ops llop = fuse_path_ops; + /* Boolean: have the builtin modules already been registered? */ + static int builtin_modules_registered_p = 0; + if (builtin_modules_registered_p == 0) { + /* If not, register them. */ + fuse_register_module (&fuse_fusemod_subdir_module); + fuse_register_module (&fuse_fusemod_iconv_module); + builtin_modules_registered_p = 1; + } + if (fuse_create_context_key() == -1) goto out;