The driver.{c,h} files are primarily targetted at loading hypervisor
drivers and some helper functions in that area. It also, however,
contains a generically useful function for loading extension modules
that is called by the storage driver. Split that functionality off
into a new virmodule.{c,h} file to isolate it.
Signed-off-by: Daniel P. Berrangé <berrange(a)redhat.com>
---
src/driver.c | 133 +-------------------------------
src/driver.h | 3 -
src/libvirt_driver_modules.syms | 1 -
src/libvirt_private.syms | 3 +
src/storage/storage_backend.c | 3 +-
src/util/Makefile.inc.am | 2 +
src/util/virmodule.c | 163 ++++++++++++++++++++++++++++++++++++++++
src/util/virmodule.h | 29 +++++++
8 files changed, 201 insertions(+), 136 deletions(-)
create mode 100644 src/util/virmodule.c
create mode 100644 src/util/virmodule.h
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 <dlfcn.h>
-
-
-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
+ * <
http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <config.h>
+
+#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 <dlfcn.h>
+
+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
+ * <
http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef __VIR_MODULE_H__
+# define __VIR_MODULE_H__
+
+int virModuleLoad(const char *path,
+ const char *regfunc,
+ bool required);
+
+#endif /* __VIR_MODULE_H__ */
--
2.14.3