Make all plugins dynamically loaded.

Signed-off-by: Lon Hohberger <lhh@redhat.com>
This commit is contained in:
Lon Hohberger 2009-09-01 18:54:17 -04:00
parent ac60769002
commit 5beaad3390
6 changed files with 267 additions and 51 deletions

View File

@ -3,6 +3,7 @@ fence_virtd {
listener = "multicast";
backend = "libvirt";
name_mode = "name";
module_path = "/usr/lib64/fence_virt";
}
listeners {

View File

@ -103,6 +103,7 @@ const listener_plugin_t *plugin_find_listener(const char *name);
void plugin_dump(void);
#ifdef _MODULE
int plugin_load(const char *libpath);
int plugin_load(const char *filename);
int plugin_search(const char *pathname);
#endif

View File

@ -15,12 +15,14 @@ include ../Makefile.top
TARGETS=fence_virtd
MODULES=libvirt.so checkpoint.so
MODULES=libvirt.so checkpoint.so multicast.so
fence_virtd_SOURCES = mcast.c main.c plugin.c
fence_virtd_SOURCES = main.c plugin.c
libvirt_so_SOURCES = libvirt.c
multicast_so_SOURCES = mcast.c
checkpoint_so_SOURCES = virt.c vm_states.c
INCLUDES=-I../include\
@ -41,6 +43,9 @@ all: ${TARGETS} ${MODULES}
fence_virtd: ${fence_virtd_SOURCES:.c=.o}
gcc -o $@ $^ $(LIBS) $(MAIN_LIBS)
multicast.so: ${multicast_so_SOURCES:.c=.o}
gcc -o $@ $^ $(LIBS) -shared
libvirt.so: ${libvirt_so_SOURCES:.c=.o}
gcc -o $@ $^ $(LIBS) -shared

View File

@ -15,7 +15,7 @@
int
main(int argc, char **argv)
{
char val[80];
char val[4096];
char listener_name[80];
char backend_name[80];
const char *config_file = DEFAULT_CONFIG_FILE;
@ -74,14 +74,24 @@ main(int argc, char **argv)
printf("Backend plugin: %s\n", backend_name);
#ifdef _MODULE
if (plugin_load("./libvirt.so") < 0) {
printf("Doom\n");
if (sc_get(config, "fence_virtd/@module_path", val,
sizeof(val))) {
printf("Failed to determine module path.\n");
return -1;
}
if (plugin_load("/usr/lib64/fence_virt/libvirt.so") < 0) {
printf("Doom\n");
printf("Searching %s for plugins...\n", val);
opt = plugin_search(val);
if (opt > 0) {
printf("%d plugins found\n", opt);
} else {
printf("No plugins found\n");
return 1;
}
#endif
plugin_dump();
#endif
lp = plugin_find_listener(listener_name);
if (!lp) {

View File

@ -552,7 +552,7 @@ static listener_plugin_t mcast_plugin = {
};
#ifdef _MODULE_FOO
#ifdef _MODULE
double
LISTENER_VER_SYM(void)
{

View File

@ -25,7 +25,6 @@
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>
#include <list.h>
@ -33,7 +32,7 @@
#include <server_plugin.h>
#include <malloc.h>
#include <string.h>
#include <dirent.h>
typedef struct _plugin_list {
list_head();
@ -44,11 +43,17 @@ typedef struct _plugin_list {
static plugin_list_t *server_plugins = NULL;
int
plugin_reg_backend(const backend_plugin_t *plugin)
{
plugin_list_t *newplug;
if (plugin_find_backend(plugin->name)) {
errno = EEXIST;
return -1;
}
newplug = malloc(sizeof(*newplug));
if (!newplug)
return -1;
@ -66,6 +71,11 @@ plugin_reg_listener(const listener_plugin_t *plugin)
{
plugin_list_t *newplug;
if (plugin_find_listener(plugin->name)) {
errno = EEXIST;
return -1;
}
newplug = malloc(sizeof(*newplug));
if (!newplug)
return -1;
@ -95,6 +105,7 @@ plugin_dump(void)
}
}
const backend_plugin_t *
plugin_find_backend(const char *name)
{
@ -129,6 +140,109 @@ plugin_find_listener(const char *name)
}
static int
backend_plugin_load(void *handle, const char *libpath)
{
const backend_plugin_t *plug = NULL;
double (*modversion)(void);
backend_plugin_t *(*modinfo)(void);
modversion = dlsym(handle, BACKEND_VER_STR);
if (!modversion) {
#ifdef DEBUG
printf("Failed to map %s\n", BACKEND_VER_STR);
#endif
errno = EINVAL;
return -1;
}
if (modversion() != PLUGIN_VERSION_BACKEND) {
#ifdef DEBUG
printf("API version mismatch in %s: \n"
" %f expected; %f received.\n", libpath,
PLUGIN_VERSION_BACKEND, modversion());
#endif
errno = EINVAL;
return -1;
}
modinfo = dlsym(handle, BACKEND_INFO_STR);
if (!modinfo) {
#ifdef DEBUG
printf("Failed to map %s\n", BACKEND_INFO_STR);
#endif
errno = EINVAL;
return -1;
}
plug = modinfo();
if (plugin_reg_backend(plug) < 0) {
errno = EINVAL;
return -1;
}
#ifdef DEBUG
else {
printf("Registered backend plugin %s %s\n",
plug->name, plug->version);
}
#endif
return 0;
}
static int
listener_plugin_load(void *handle, const char *libpath)
{
const listener_plugin_t *plug = NULL;
double (*modversion)(void);
listener_plugin_t *(*modinfo)(void);
modversion = dlsym(handle, LISTENER_VER_STR);
if (!modversion) {
#ifdef DEBUG
printf("Failed to map %s\n", LISTENER_VER_STR);
#endif
errno = EINVAL;
return -1;
}
if (modversion() != PLUGIN_VERSION_LISTENER) {
#ifdef DEBUG
printf("API version mismatch in %s: \n"
" %f expected; %f received.\n", libpath,
PLUGIN_VERSION_LISTENER, modversion());
#endif
dlclose(handle);
errno = EINVAL;
return -1;
}
modinfo = dlsym(handle, LISTENER_INFO_STR);
if (!modinfo) {
#ifdef DEBUG
printf("Failed to map %s\n", LISTENER_INFO_STR);
#endif
errno = EINVAL;
return -1;
}
plug = modinfo();
if (plugin_reg_listener(plug) < 0) {
errno = EINVAL;
return -1;
}
#ifdef DEBUG
else {
printf("Registered listener plugin %s %s\n",
plug->name, plug->version);
}
#endif
return 0;
}
/**
* Load a cluster plugin .so file and map all the functions
* provided to entries in a backend_plugin_t structure.
@ -142,9 +256,6 @@ int
plugin_load(const char *libpath)
{
void *handle = NULL;
const backend_plugin_t *plug = NULL;
double (*modversion)(void);
backend_plugin_t *(*modinfo)(void);
struct stat sb;
errno = 0;
@ -178,52 +289,140 @@ plugin_load(const char *libpath)
return -1;
}
#ifdef DEBUG
printf("Loading plugin from %s\n", libpath);
#endif
handle = dlopen(libpath, RTLD_LAZY);
if (!handle) {
errno = ELIBACC;
return -1;
}
modversion = dlsym(handle, BACKEND_VER_STR);
if (!modversion) {
#ifdef DEBUG
printf("Failed to map %s\n", BACKEND_VER_STR);
#endif
dlclose(handle);
errno = EINVAL;
if (!backend_plugin_load(handle, libpath) ||
!listener_plugin_load(handle, libpath))
return 0;
dlclose(handle);
errno = EINVAL;
return -1;
}
/**
Free up a null-terminated array of strings
*/
static void
free_dirnames(char **dirnames)
{
int x = 0;
for (; dirnames[x]; x++)
free(dirnames[x]);
free(dirnames);
}
static int
_compare(const void *a, const void *b)
{
return strcmp((const char *)a, (const char *)b);
}
/**
Read all entries in a directory and return them in a NULL-terminated,
sorted array.
*/
static int
read_dirnames_sorted(const char *directory, char ***dirnames)
{
DIR *dir;
struct dirent *entry;
char filename[1024];
int count = 0, x = 0;
dir = opendir(directory);
if (!dir)
return -1;
/* Count the number of plugins */
while ((entry = readdir(dir)) != NULL)
++count;
/* Malloc the entries */
*dirnames = malloc(sizeof(char *) * (count+1));
if (!*dirnames) {
#ifdef DEBUG
printf("%s: Failed to malloc %d bytes",
__FUNCTION__, (int)(sizeof(char *) * (count+1)));
#endif
closedir(dir);
errno = ENOMEM;
return -1;
}
memset(*dirnames, 0, sizeof(char *) * (count + 1));
rewinddir(dir);
/* Store the directory names. */
while ((entry = readdir(dir)) != NULL) {
snprintf(filename, sizeof(filename), "%s/%s", directory,
entry->d_name);
(*dirnames)[x] = strdup(filename);
if (!(*dirnames)[x]) {
#ifdef DEBUG
printf("Failed to duplicate %s\n",
filename);
#endif
free_dirnames(*dirnames);
closedir(dir);
errno = ENOMEM;
return -1;
}
++x;
}
if (modversion() != PLUGIN_VERSION_BACKEND) {
#ifdef DEBUG
printf("API version mismatch in %s: \n"
" %f expected; %f received.\n", libpath,
, modversion());
#endif
dlclose(handle);
errno = EINVAL;
return -1;
}
closedir(dir);
modinfo = dlsym(handle, BACKEND_INFO_STR);
if (!modinfo) {
#ifdef DEBUG
printf("Failed to map %s\n", BACKEND_INFO_STR);
#endif
dlclose(handle);
errno = EINVAL;
return -1;
}
plug = modinfo();
if (plugin_reg_backend(plug) < 0) {
dlclose(handle);
errno = EINVAL;
return -1;
} else {
printf("Registered plugin %s %s\n",
plug->name, plug->version);
}
/* Sort the directory names. */
qsort((*dirnames), count, sizeof(char *), _compare);
return 0;
}
/**
*/
int
plugin_search(const char *pathname)
{
int found = 0;
int fcount = 0;
char **filenames;
#ifdef DEBUG
printf("Trying plugins in %s\n", pathname);
#endif
if (read_dirnames_sorted(pathname, &filenames) != 0) {
return -1;
}
for (fcount = 0; filenames[fcount]; fcount++) {
if (plugin_load(filenames[fcount]) == 0)
++found;
}
free_dirnames(filenames);
if (!found) {
#ifdef DEBUG
printf("No usable plugins found.\n");
#endif
errno = ELIBACC;
return -1;
}
return found;
}