mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-01-21 20:15:17 +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 "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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -4,7 +4,6 @@
|
||||
|
||||
# driver.h
|
||||
virDriverLoadModule;
|
||||
virDriverLoadModuleFull;
|
||||
|
||||
# Let emacs know we want case-insensitive sorting
|
||||
# Local Variables:
|
||||
|
@ -2228,6 +2228,9 @@ virMediatedDeviceTypeFree;
|
||||
virMediatedDeviceTypeReadAttrs;
|
||||
|
||||
|
||||
# util/virmodule.h
|
||||
virModuleLoad;
|
||||
|
||||
|
||||
# util/virnetdev.h
|
||||
virNetDevAddMulti;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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 \
|
||||
|
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…
x
Reference in New Issue
Block a user