diff --git a/src/driver.c b/src/driver.c index 67ac02006d4a006fd50ea9d7107f1945e36f782f..38f2f6c312db6c14aaa145826c6385bf47a9f6cc 100644 --- a/src/driver.c +++ b/src/driver.c @@ -43,13 +43,103 @@ VIR_LOG_INIT("driver"); # include # define DEFAULT_DRIVER_DIR LIBDIR "/libvirt/connection-driver" + +static void * +virDriverLoadModuleFile(const char *file) +{ + void *handle = NULL; + + VIR_DEBUG("Load module file '%s'", file); + + if (access(file, R_OK) < 0) { + VIR_INFO("Module %s not accessible", file); + return NULL; + } + + virUpdateSelfLastChanged(file); + + if (!(handle = dlopen(file, RTLD_NOW | RTLD_GLOBAL))) + VIR_ERROR(_("failed to load module %s %s"), file, dlerror()); + + return handle; +} + + +static void * +virDriverLoadModuleFunc(void *handle, + const char *funcname) +{ + void *regsym; + + VIR_DEBUG("Lookup function '%s'", funcname); + + if (!(regsym = dlsym(handle, funcname))) + VIR_ERROR(_("Missing module registration symbol %s"), funcname); + + return regsym; +} + + +/** + * virDriverLoadModuleFull: + * @path: filename of module to load + * @regfunc: name of the function that registers the module + * @handle: Returns handle of the loaded library if not NULL + * + * Loads a loadable module named @path and calls the + * registration function @regfunc. If @handle is not NULL the handle is returned + * in the variable. Otherwise the handle is leaked so that the module stays + * loaded forever. + * + * The module is automatically looked up in the appropriate place (git or + * installed directory). + * + * Returns 0 on success, 1 if the module was not found and -1 on any error. + */ +int +virDriverLoadModuleFull(const char *path, + const char *regfunc, + void **handle) +{ + void *rethandle = NULL; + int (*regsym)(void); + int ret = -1; + + if (!(rethandle = virDriverLoadModuleFile(path))) { + ret = 1; + goto cleanup; + } + + if (!(regsym = virDriverLoadModuleFunc(rethandle, regfunc))) + goto cleanup; + + if ((*regsym)() < 0) { + VIR_ERROR(_("Failed module registration %s"), regfunc); + goto cleanup; + } + + if (handle) + VIR_STEAL_PTR(*handle, rethandle); + else + rethandle = NULL; + + ret = 0; + + cleanup: + if (rethandle) + dlclose(rethandle); + return ret; +} + + void * virDriverLoadModule(const char *name) { - char *modfile = NULL, *regfunc = NULL, *fixedname = NULL; + char *modfile = NULL; + char *fixedname = NULL; + char *regfunc = NULL; char *tmp; void *handle = NULL; - int (*regsym)(void); VIR_DEBUG("Module load %s", name); @@ -61,19 +151,6 @@ virDriverLoadModule(const char *name) "LIBVIRT_DRIVER_DIR"))) return NULL; - if (access(modfile, R_OK) < 0) { - VIR_INFO("Module %s not accessible", modfile); - goto cleanup; - } - - virUpdateSelfLastChanged(modfile); - - handle = dlopen(modfile, RTLD_NOW | RTLD_GLOBAL); - if (!handle) { - VIR_ERROR(_("failed to load module %s %s"), modfile, dlerror()); - goto cleanup; - } - if (VIR_STRDUP_QUIET(fixedname, name) < 0) { VIR_ERROR(_("out of memory")); goto cleanup; @@ -88,29 +165,13 @@ virDriverLoadModule(const char *name) if (virAsprintfQuiet(®func, "%sRegister", fixedname) < 0) goto cleanup; - regsym = dlsym(handle, regfunc); - if (!regsym) { - VIR_ERROR(_("Missing module registration symbol %s"), regfunc); - goto cleanup; - } - - if ((*regsym)() < 0) { - VIR_ERROR(_("Failed module registration %s"), regfunc); - goto cleanup; - } - - VIR_FREE(modfile); - VIR_FREE(regfunc); - VIR_FREE(fixedname); - return handle; + virDriverLoadModuleFull(modfile, regfunc, &handle); cleanup: VIR_FREE(modfile); - VIR_FREE(regfunc); VIR_FREE(fixedname); - if (handle) - dlclose(handle); - return NULL; + VIR_FREE(regfunc); + return handle; } diff --git a/src/driver.h b/src/driver.h index e4e382b6347eafa18c02deb7fb3a4813bc515c65..885e8843e52f30afeb8691fe44fae0fd602965ec 100644 --- a/src/driver.h +++ b/src/driver.h @@ -100,5 +100,8 @@ int virSetSharedSecretDriver(virSecretDriverPtr driver) ATTRIBUTE_RETURN_CHECK; int virSetSharedStorageDriver(virStorageDriverPtr driver) ATTRIBUTE_RETURN_CHECK; void *virDriverLoadModule(const char *name); +int virDriverLoadModuleFull(const char *name, + const char *regfunc, + void **handle); #endif /* __VIR_DRIVER_H__ */ diff --git a/src/libvirt_driver_modules.syms b/src/libvirt_driver_modules.syms index f9d0ee9b971407ca4c429c38e25c68558aeffa09..bd9bf1c3151d4b7ca396dd58036cd3ecca5d3608 100644 --- a/src/libvirt_driver_modules.syms +++ b/src/libvirt_driver_modules.syms @@ -4,6 +4,7 @@ # driver.h virDriverLoadModule; +virDriverLoadModuleFull; # Let emacs know we want case-insensitive sorting # Local Variables: