diff --git a/config/example.conf b/config/example.conf index a79c6be..f937e59 100644 --- a/config/example.conf +++ b/config/example.conf @@ -3,6 +3,7 @@ fence_virtd { listener = "multicast"; backend = "libvirt"; name_mode = "name"; + module_path = "/usr/lib64/fence_virt"; } listeners { diff --git a/include/server_plugin.h b/include/server_plugin.h index e96047d..e9c44b5 100644 --- a/include/server_plugin.h +++ b/include/server_plugin.h @@ -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 diff --git a/server/Makefile b/server/Makefile index 9f0a005..c7d3314 100644 --- a/server/Makefile +++ b/server/Makefile @@ -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 diff --git a/server/main.c b/server/main.c index 40e31ed..8a5b956 100644 --- a/server/main.c +++ b/server/main.c @@ -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) { diff --git a/server/mcast.c b/server/mcast.c index 8ff676a..ef8f545 100644 --- a/server/mcast.c +++ b/server/mcast.c @@ -552,7 +552,7 @@ static listener_plugin_t mcast_plugin = { }; -#ifdef _MODULE_FOO +#ifdef _MODULE double LISTENER_VER_SYM(void) { diff --git a/server/plugin.c b/server/plugin.c index 521716f..03188c5 100644 --- a/server/plugin.c +++ b/server/plugin.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include @@ -33,7 +32,7 @@ #include #include #include - +#include 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; +} + +