mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-10-30 18:03:32 +00:00
util: create new virmodule.{c,h} files for dlopen support code
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@redhat.com>
This commit is contained in:
parent
1f2f055bc3
commit
8b0f721f2e
133
src/driver.c
133
src/driver.c
@ -28,6 +28,7 @@
|
|||||||
#include "viralloc.h"
|
#include "viralloc.h"
|
||||||
#include "virfile.h"
|
#include "virfile.h"
|
||||||
#include "virlog.h"
|
#include "virlog.h"
|
||||||
|
#include "virmodule.h"
|
||||||
#include "virthread.h"
|
#include "virthread.h"
|
||||||
#include "configmake.h"
|
#include "configmake.h"
|
||||||
|
|
||||||
@ -38,136 +39,6 @@ VIR_LOG_INIT("driver");
|
|||||||
/* XXX re-implement this for other OS, or use libtools helper lib ? */
|
/* XXX re-implement this for other OS, or use libtools helper lib ? */
|
||||||
#define DEFAULT_DRIVER_DIR LIBDIR "/libvirt/connection-driver"
|
#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
|
int
|
||||||
@ -188,7 +59,7 @@ virDriverLoadModule(const char *name,
|
|||||||
"LIBVIRT_DRIVER_DIR")))
|
"LIBVIRT_DRIVER_DIR")))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
ret = virDriverLoadModuleFull(modfile, regfunc, required);
|
ret = virModuleLoad(modfile, regfunc, required);
|
||||||
|
|
||||||
VIR_FREE(modfile);
|
VIR_FREE(modfile);
|
||||||
|
|
||||||
|
@ -110,9 +110,6 @@ int virSetSharedStorageDriver(virStorageDriverPtr driver) ATTRIBUTE_RETURN_CHECK
|
|||||||
int virDriverLoadModule(const char *name,
|
int virDriverLoadModule(const char *name,
|
||||||
const char *regfunc,
|
const char *regfunc,
|
||||||
bool required);
|
bool required);
|
||||||
int virDriverLoadModuleFull(const char *path,
|
|
||||||
const char *regfunc,
|
|
||||||
bool required);
|
|
||||||
|
|
||||||
virConnectPtr virGetConnectInterface(void);
|
virConnectPtr virGetConnectInterface(void);
|
||||||
virConnectPtr virGetConnectNetwork(void);
|
virConnectPtr virGetConnectNetwork(void);
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
|
|
||||||
# driver.h
|
# driver.h
|
||||||
virDriverLoadModule;
|
virDriverLoadModule;
|
||||||
virDriverLoadModuleFull;
|
|
||||||
|
|
||||||
# Let emacs know we want case-insensitive sorting
|
# Let emacs know we want case-insensitive sorting
|
||||||
# Local Variables:
|
# Local Variables:
|
||||||
|
@ -2228,6 +2228,9 @@ virMediatedDeviceTypeFree;
|
|||||||
virMediatedDeviceTypeReadAttrs;
|
virMediatedDeviceTypeReadAttrs;
|
||||||
|
|
||||||
|
|
||||||
|
# util/virmodule.h
|
||||||
|
virModuleLoad;
|
||||||
|
|
||||||
|
|
||||||
# util/virnetdev.h
|
# util/virnetdev.h
|
||||||
virNetDevAddMulti;
|
virNetDevAddMulti;
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
#include "virstoragefile.h"
|
#include "virstoragefile.h"
|
||||||
#include "storage_backend.h"
|
#include "storage_backend.h"
|
||||||
#include "virlog.h"
|
#include "virlog.h"
|
||||||
|
#include "virmodule.h"
|
||||||
#include "virfile.h"
|
#include "virfile.h"
|
||||||
#include "configmake.h"
|
#include "configmake.h"
|
||||||
|
|
||||||
@ -97,7 +98,7 @@ virStorageDriverLoadBackendModule(const char *name,
|
|||||||
"LIBVIRT_STORAGE_BACKEND_DIR")))
|
"LIBVIRT_STORAGE_BACKEND_DIR")))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
ret = virDriverLoadModuleFull(modfile, regfunc, forceload);
|
ret = virModuleLoad(modfile, regfunc, forceload);
|
||||||
|
|
||||||
VIR_FREE(modfile);
|
VIR_FREE(modfile);
|
||||||
|
|
||||||
|
@ -100,6 +100,8 @@ UTIL_SOURCES = \
|
|||||||
util/virmacaddr.h \
|
util/virmacaddr.h \
|
||||||
util/virmacmap.c \
|
util/virmacmap.c \
|
||||||
util/virmacmap.h \
|
util/virmacmap.h \
|
||||||
|
util/virmodule.c \
|
||||||
|
util/virmodule.h \
|
||||||
util/virnetdev.c \
|
util/virnetdev.c \
|
||||||
util/virnetdev.h \
|
util/virnetdev.h \
|
||||||
util/virnetdevbandwidth.c \
|
util/virnetdevbandwidth.c \
|
||||||
|
163
src/util/virmodule.c
Normal file
163
src/util/virmodule.c
Normal file
@ -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 */
|
29
src/util/virmodule.h
Normal file
29
src/util/virmodule.h
Normal file
@ -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__ */
|
Loading…
Reference in New Issue
Block a user