diff options
Diffstat (limited to 'pcilib/plugin.c')
-rw-r--r-- | pcilib/plugin.c | 101 |
1 files changed, 101 insertions, 0 deletions
diff --git a/pcilib/plugin.c b/pcilib/plugin.c new file mode 100644 index 0000000..663bb27 --- /dev/null +++ b/pcilib/plugin.c @@ -0,0 +1,101 @@ +#include <stdio.h> +#include <stdlib.h> +#include <dlfcn.h> +#include <dirent.h> +#include <unistd.h> +#include <string.h> +#include <sys/types.h> + +#include "model.h" +#include "pci.h" +#include "config.h" + +void *pcilib_plugin_load(const char *name) { + void *plug; + char *fullname; + const char *path; + + path = getenv("PCILIB_PLUGIN_DIR"); + if (!path) path = PCILIB_PLUGIN_DIR; + + fullname = malloc(strlen(path) + strlen(name) + 2); + if (!fullname) return NULL; + + sprintf(fullname, "%s/%s", path, name); + + plug = dlopen(fullname, RTLD_LAZY|RTLD_LOCAL); + free(fullname); + + return plug; +} + +void pcilib_plugin_close(void *plug) { + if (plug) + dlclose(plug); + +} + +void *pcilib_plugin_get_symbol(void *plug, const char *symbol) { + if ((!plug)||(!symbol)) return NULL; + return dlsym(plug, symbol); +} + +const pcilib_model_description_t *pcilib_get_plugin_model(pcilib_t *pcilib, void *plug, unsigned short vendor_id, unsigned short device_id, const char *model) { + void *get_model; + + if (!plug) return NULL; + + get_model = dlsym(plug, "pcilib_get_event_model"); + if (!get_model) return NULL; + + return ((const pcilib_model_description_t *(*)(pcilib_t *pcilib, unsigned short vendor_id, unsigned short device_id, const char *model))get_model)(pcilib, vendor_id, device_id, model); +} + +const pcilib_model_description_t *pcilib_find_plugin_model(pcilib_t *pcilib, unsigned short vendor_id, unsigned short device_id, const char *model) { + DIR *dir; + const char *path; + struct dirent *entry; + + void *plugin; + const pcilib_model_description_t *model_info = NULL; + + + path = getenv("PCILIB_PLUGIN_DIR"); + if (!path) path = PCILIB_PLUGIN_DIR; + + if (model) { + plugin = pcilib_plugin_load(model); + if (plugin) { + model_info = pcilib_get_plugin_model(pcilib, plugin, vendor_id, device_id, model); + if (model_info) { + pcilib->event_plugin = plugin; + return model_info; + } + pcilib_plugin_close(plugin); + } + } + + dir = opendir(path); + if (!dir) return NULL; + + while ((entry = readdir(dir))) { + const char *suffix = strstr(entry->d_name, ".so"); + if ((!suffix)||(strlen(suffix) != 3)) continue; + + if ((model)&&(!strcmp(entry->d_name, model))) + continue; + + plugin = pcilib_plugin_load(entry->d_name); + if (plugin) { + model_info = pcilib_get_plugin_model(pcilib, plugin, vendor_id, device_id, model); + if (model_info) { + pcilib->event_plugin = plugin; + break; + } + pcilib_plugin_close(plugin); + } + } + + closedir(dir); + return model_info; +} |