#include <dirent.h>
#include <string.h>
#include <queue.h>
#include "util.h"
#include "out.h"
#include "plugin.h"
#include "dlsym.h"
struct plugin {
const char *module_name;
const char *name;
unsigned version;
void *funcs;
void *handle;
int loaded;
struct plugin_ops p_ops;
SLIST_ENTRY(plugin) e;
};
static SLIST_HEAD(, plugin) plugins;
#define PMEM_PLUGIN_LOAD_SYMBOL(plugin, symbol, path, error)\
if (((plugin)->p_ops.symbol = util_dlsym((plugin)->handle, #symbol)) == NULL) {\
LOG(3, "%s: unable to load %s symbol", (path), #symbol);\
goto error; }
static int
plugin_new_entry(const char *plugin_path)
{
LOG(3, "%s", plugin_path);
struct plugin *p = Malloc(sizeof(*p));
if (p == NULL) {
LOG(3, "%s: unable to allocate plugin", plugin_path);
goto error_plugin_alloc;
}
p->loaded = 0;
p->handle = util_dlopen(plugin_path);
if (p->handle == NULL) {
LOG(3, "%s: unable to dlopen plugin (%s)",
plugin_path, util_dlerror());
goto error_plugin_open;
}
PMEM_PLUGIN_LOAD_SYMBOL(p, pmem_plugin_desc,
plugin_path, error_symbol);
PMEM_PLUGIN_LOAD_SYMBOL(p, pmem_plugin_load,
plugin_path, error_symbol);
PMEM_PLUGIN_LOAD_SYMBOL(p, pmem_plugin_unload,
plugin_path, error_symbol);
p->p_ops.pmem_plugin_desc(&p->module_name,
&p->name, &p->version, &p->funcs);
SLIST_INSERT_HEAD(&plugins, p, e);
return 0;
error_symbol:
util_dlclose(p->handle);
error_plugin_open:
Free(p);
error_plugin_alloc:
return -1;
}
int
plugin_init(const char *plugin_dir)
{
LOG(3, "%s", plugin_dir);
struct dirent *entry;
DIR *pdir = opendir(plugin_dir);
if (pdir == NULL)
return -1;
size_t dirlen = strlen(plugin_dir);
char *plugin_path = Malloc(dirlen + PATH_MAX + 1);
if (plugin_path == NULL) {
closedir(pdir);
return -1;
}
strcpy(plugin_path, plugin_dir);
plugin_path[dirlen] = '/';
while ((entry = readdir(pdir)) != NULL) {
const char *extension = strrchr(entry->d_name, '.');
if (extension == NULL || strcmp(extension, ".so") != 0)
continue;
strcpy(plugin_path + dirlen + 1, entry->d_name);
plugin_new_entry(plugin_path);
}
closedir(pdir);
Free(plugin_path);
return 0;
}
void
plugin_fini(void)
{
LOG(3, NULL);
struct plugin *p;
while (!SLIST_EMPTY(&plugins)) {
p = SLIST_FIRST(&plugins);
SLIST_REMOVE_HEAD(&plugins, e);
if (p->loaded)
p->p_ops.pmem_plugin_unload();
if (p->handle != NULL)
util_dlclose(p->handle);
Free(p);
}
}
int
plugin_add(const struct plugin_ops *p_ops)
{
LOG(3, NULL);
struct plugin *p = Malloc(sizeof(*p));
if (p == NULL) {
LOG(3, "unable to allocate static plugin");
return -1;
}
p->loaded = 0;
p->handle = NULL;
p->p_ops = *p_ops;
p->p_ops.pmem_plugin_desc(&p->module_name,
&p->name, &p->version, &p->funcs);
SLIST_INSERT_HEAD(&plugins, p, e);
return 0;
}
void
plugin_load(const char *module_name, unsigned version,
void (*plugin_cb)(const char *name, void *funcs, void *arg), void *arg)
{
LOG(3, "module_name %s version %u", module_name, version);
struct plugin *p;
SLIST_FOREACH(p, &plugins, e) {
if (strcmp(module_name, p->module_name) != 0)
continue;
if (version != p->version)
continue;
if (!p->loaded) {
if (p->p_ops.pmem_plugin_load() != 0) {
ERR("unable to load %s plugin", p->name);
continue;
}
p->loaded = 1;
LOG(3, "loaded %s plugin from module %s",
p->name, p->module_name);
}
plugin_cb(p->name, p->funcs, arg);
}
}