diff --git a/src/driver.c b/src/driver.c index 447f61d554..8b5ade763f 100644 --- a/src/driver.c +++ b/src/driver.c @@ -28,6 +28,7 @@ #include "viralloc.h" #include "virfile.h" #include "virlog.h" +#include "virmodule.h" #include "virthread.h" #include "configmake.h" @@ -38,136 +39,6 @@ VIR_LOG_INIT("driver"); /* XXX re-implement this for other OS, or use libtools helper lib ? */ #define DEFAULT_DRIVER_DIR LIBDIR "/libvirt/connection-driver" -#ifdef HAVE_DLFCN_H -# include - - -static void * -virDriverLoadModuleFile(const char *file) -{ - void *handle = NULL; - int flags = RTLD_NOW | RTLD_GLOBAL; - -# ifdef RTLD_NODELETE - flags |= RTLD_NODELETE; -# endif - - VIR_DEBUG("Load module file '%s'", file); - - virUpdateSelfLastChanged(file); - - if (!(handle = dlopen(file, flags))) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Failed to load module '%s': %s"), file, dlerror()); - return NULL; - } - - return handle; -} - - -static void * -virDriverLoadModuleFunc(void *handle, - const char *file, - const char *funcname) -{ - void *regsym; - - VIR_DEBUG("Lookup function '%s'", funcname); - - if (!(regsym = dlsym(handle, funcname))) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Failed to find symbol '%s' in module '%s': %s"), - funcname, file, dlerror()); - return NULL; - } - - return regsym; -} - - -/** - * virDriverLoadModuleFull: - * @path: filename of module to load - * @regfunc: name of the function that registers the module - * - * Loads a loadable module named @path and calls the - * registration function @regfunc. The module will never - * be unloaded because unloading is not safe in a multi-threaded - * application. - * - * 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, - bool required) -{ - void *rethandle = NULL; - int (*regsym)(void); - int ret = -1; - - if (!virFileExists(path)) { - if (required) { - virReportSystemError(errno, - _("Failed to find module '%s'"), path); - return -1; - } else { - VIR_INFO("Module '%s' does not exist", path); - return 1; - } - } - - if (!(rethandle = virDriverLoadModuleFile(path))) - goto cleanup; - - if (!(regsym = virDriverLoadModuleFunc(rethandle, path, regfunc))) - goto cleanup; - - if ((*regsym)() < 0) { - /* regsym() should report an error itself, but lets - * just make sure */ - virErrorPtr err = virGetLastError(); - if (err == NULL) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Failed to execute symbol '%s' in module '%s'"), - regfunc, path); - } - goto cleanup; - } - - rethandle = NULL; - ret = 0; - - cleanup: - if (rethandle) - dlclose(rethandle); - return ret; -} - -#else /* ! HAVE_DLFCN_H */ -int -virDriverLoadModuleFull(const char *path ATTRIBUTE_UNUSED, - const char *regfunc ATTRIBUTE_UNUSED, - bool required) -{ - VIR_DEBUG("dlopen not available on this platform"); - if (required) { - virReportSystemError(ENOSYS, - _("Failed to find module '%s': %s"), path); - return -1; - } else { - /* Since we have no dlopen(), but definition we have no - * loadable modules on disk, so we can resaonably - * return '1' instead of an error. - */ - return 1; - } -} -#endif /* ! HAVE_DLFCN_H */ int @@ -188,7 +59,7 @@ virDriverLoadModule(const char *name, "LIBVIRT_DRIVER_DIR"))) return -1; - ret = virDriverLoadModuleFull(modfile, regfunc, required); + ret = virModuleLoad(modfile, regfunc, required); VIR_FREE(modfile); diff --git a/src/driver.h b/src/driver.h index b4e50ab987..0b1f7a2269 100644 --- a/src/driver.h +++ b/src/driver.h @@ -110,9 +110,6 @@ int virSetSharedStorageDriver(virStorageDriverPtr driver) ATTRIBUTE_RETURN_CHECK int virDriverLoadModule(const char *name, const char *regfunc, bool required); -int virDriverLoadModuleFull(const char *path, - const char *regfunc, - bool required); virConnectPtr virGetConnectInterface(void); virConnectPtr virGetConnectNetwork(void); diff --git a/src/libvirt_driver_modules.syms b/src/libvirt_driver_modules.syms index bd9bf1c315..f9d0ee9b97 100644 --- a/src/libvirt_driver_modules.syms +++ b/src/libvirt_driver_modules.syms @@ -4,7 +4,6 @@ # driver.h virDriverLoadModule; -virDriverLoadModuleFull; # Let emacs know we want case-insensitive sorting # Local Variables: diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index d2728749fb..1051a105b8 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -2228,6 +2228,9 @@ virMediatedDeviceTypeFree; virMediatedDeviceTypeReadAttrs; +# util/virmodule.h +virModuleLoad; + # util/virnetdev.h virNetDevAddMulti; diff --git a/src/storage/storage_backend.c b/src/storage/storage_backend.c index cb1bcc0944..7d226f3d3a 100644 --- a/src/storage/storage_backend.c +++ b/src/storage/storage_backend.c @@ -33,6 +33,7 @@ #include "virstoragefile.h" #include "storage_backend.h" #include "virlog.h" +#include "virmodule.h" #include "virfile.h" #include "configmake.h" @@ -97,7 +98,7 @@ virStorageDriverLoadBackendModule(const char *name, "LIBVIRT_STORAGE_BACKEND_DIR"))) return -1; - ret = virDriverLoadModuleFull(modfile, regfunc, forceload); + ret = virModuleLoad(modfile, regfunc, forceload); VIR_FREE(modfile); diff --git a/src/util/Makefile.inc.am b/src/util/Makefile.inc.am index 9624fb687c..ec8745da7e 100644 --- a/src/util/Makefile.inc.am +++ b/src/util/Makefile.inc.am @@ -100,6 +100,8 @@ UTIL_SOURCES = \ util/virmacaddr.h \ util/virmacmap.c \ util/virmacmap.h \ + util/virmodule.c \ + util/virmodule.h \ util/virnetdev.c \ util/virnetdev.h \ util/virnetdevbandwidth.c \ diff --git a/src/util/virmodule.c b/src/util/virmodule.c new file mode 100644 index 0000000000..ff8c22752e --- /dev/null +++ b/src/util/virmodule.c @@ -0,0 +1,163 @@ +/* + * virmodule.c: APIs for dlopen'ing extension modules + * + * Copyright (C) 2012-2018 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; If not, see + * . + * + */ + +#include + +#include "internal.h" +#include "virmodule.h" +#include "virerror.h" +#include "virfile.h" +#include "virlog.h" + +#define VIR_FROM_THIS VIR_FROM_NONE + +VIR_LOG_INIT("util.module"); + +#ifdef HAVE_DLFCN_H +# include + +static void * +virModuleLoadFile(const char *file) +{ + void *handle = NULL; + int flags = RTLD_NOW | RTLD_GLOBAL; + +# ifdef RTLD_NODELETE + flags |= RTLD_NODELETE; +# endif + + VIR_DEBUG("Load module file '%s'", file); + + virUpdateSelfLastChanged(file); + + if (!(handle = dlopen(file, flags))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to load module '%s': %s"), file, dlerror()); + return NULL; + } + + return handle; +} + + +static void * +virModuleLoadFunc(void *handle, + const char *file, + const char *funcname) +{ + void *regsym; + + VIR_DEBUG("Lookup function '%s'", funcname); + + if (!(regsym = dlsym(handle, funcname))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to find symbol '%s' in module '%s': %s"), + funcname, file, dlerror()); + return NULL; + } + + return regsym; +} + + +/** + * virModuleLoad: + * @path: filename of module to load + * @regfunc: name of the function that registers the module + * @required: true if module must exist on disk, false to silently skip + * + * Loads a loadable module named @path and calls the + * registration function @regfunc. The module will never + * be unloaded because unloading is not safe in a multi-threaded + * application. + * + * 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 +virModuleLoad(const char *path, + const char *regfunc, + bool required) +{ + void *rethandle = NULL; + int (*regsym)(void); + int ret = -1; + + if (!virFileExists(path)) { + if (required) { + virReportSystemError(errno, + _("Failed to find module '%s'"), path); + return -1; + } else { + VIR_INFO("Module '%s' does not exist", path); + return 1; + } + } + + if (!(rethandle = virModuleLoadFile(path))) + goto cleanup; + + if (!(regsym = virModuleLoadFunc(rethandle, path, regfunc))) + goto cleanup; + + if ((*regsym)() < 0) { + /* regsym() should report an error itself, but lets + * just make sure */ + virErrorPtr err = virGetLastError(); + if (err == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to execute symbol '%s' in module '%s'"), + regfunc, path); + } + goto cleanup; + } + + rethandle = NULL; + ret = 0; + + cleanup: + if (rethandle) + dlclose(rethandle); + return ret; +} + +#else /* ! HAVE_DLFCN_H */ +int +virModuleLoad(const char *path ATTRIBUTE_UNUSED, + const char *regfunc ATTRIBUTE_UNUSED, + bool required) +{ + VIR_DEBUG("dlopen not available on this platform"); + if (required) { + virReportSystemError(ENOSYS, + _("Failed to find module '%s': %s"), path); + return -1; + } else { + /* Since we have no dlopen(), but definition we have no + * loadable modules on disk, so we can resaonably + * return '1' instead of an error. + */ + return 1; + } +} +#endif /* ! HAVE_DLFCN_H */ diff --git a/src/util/virmodule.h b/src/util/virmodule.h new file mode 100644 index 0000000000..cccd836b41 --- /dev/null +++ b/src/util/virmodule.h @@ -0,0 +1,29 @@ +/* + * virmodule.h: APIs for dlopen'ing extension modules + * + * Copyright (C) 2012-2018 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; If not, see + * . + * + */ + +#ifndef __VIR_MODULE_H__ +# define __VIR_MODULE_H__ + +int virModuleLoad(const char *path, + const char *regfunc, + bool required); + +#endif /* __VIR_MODULE_H__ */