|
@@ -3,6 +3,7 @@
|
|
|
#include <stdint.h>
|
|
|
#include <string.h>
|
|
|
#include <assert.h>
|
|
|
+#include <dlfcn.h>
|
|
|
|
|
|
#include <faux/str.h>
|
|
|
#include <faux/list.h>
|
|
@@ -21,6 +22,10 @@ struct kplugin_s {
|
|
|
char *conf;
|
|
|
uint8_t major;
|
|
|
uint8_t minor;
|
|
|
+ void *dlhan; // dlopen() handler
|
|
|
+ void *init_fn;
|
|
|
+ void *fini_fn;
|
|
|
+ void *udata; // User data
|
|
|
faux_list_t *syms;
|
|
|
};
|
|
|
|
|
@@ -55,6 +60,10 @@ KSET(plugin, uint8_t, major);
|
|
|
KGET(plugin, uint8_t, minor);
|
|
|
KSET(plugin, uint8_t, minor);
|
|
|
|
|
|
+// User data
|
|
|
+KGET(plugin, void *, udata);
|
|
|
+KSET(plugin, void *, udata);
|
|
|
+
|
|
|
// COMMAND list
|
|
|
static KCMP_NESTED(plugin, sym, name);
|
|
|
static KCMP_NESTED_BY_KEY(plugin, sym, name);
|
|
@@ -79,6 +88,10 @@ static kplugin_t *kplugin_new_empty(void)
|
|
|
plugin->conf = NULL;
|
|
|
plugin->major = 0;
|
|
|
plugin->minor = 0;
|
|
|
+ plugin->dlhan = NULL;
|
|
|
+ plugin->init_fn = NULL;
|
|
|
+ plugin->fini_fn = NULL;
|
|
|
+ plugin->udata = NULL;
|
|
|
|
|
|
// SYM list
|
|
|
plugin->syms = faux_list_new(FAUX_LIST_SORTED, FAUX_LIST_UNIQUE,
|
|
@@ -125,6 +138,9 @@ void kplugin_free(kplugin_t *plugin)
|
|
|
faux_str_free(plugin->conf);
|
|
|
faux_list_free(plugin->syms);
|
|
|
|
|
|
+ if (plugin->dlhan)
|
|
|
+ dlclose(plugin->dlhan);
|
|
|
+
|
|
|
faux_free(plugin);
|
|
|
}
|
|
|
|
|
@@ -239,3 +255,87 @@ kplugin_t *kplugin_from_iplugin(iplugin_t *iplugin, faux_error_t *error_stack)
|
|
|
|
|
|
return kplugin;
|
|
|
}
|
|
|
+
|
|
|
+
|
|
|
+bool_t kplugin_load(kplugin_t *plugin)
|
|
|
+{
|
|
|
+ char *file_name = NULL;
|
|
|
+ char *init_name = NULL;
|
|
|
+ char *fini_name = NULL;
|
|
|
+ char *major_name = NULL;
|
|
|
+ char *minor_name = NULL;
|
|
|
+ int flag = RTLD_NOW;
|
|
|
+ const char *id = NULL;
|
|
|
+ bool_t retcode = BOOL_FALSE;
|
|
|
+ uint8_t *ver = NULL;
|
|
|
+
|
|
|
+ assert(plugin);
|
|
|
+ if (!plugin)
|
|
|
+ return BOOL_FALSE;
|
|
|
+
|
|
|
+ if (kplugin_id(plugin))
|
|
|
+ id = kplugin_id(plugin);
|
|
|
+ else
|
|
|
+ id = kplugin_name(plugin);
|
|
|
+
|
|
|
+ // Shared object file name
|
|
|
+ if (kplugin_file(plugin))
|
|
|
+ file_name = faux_str_dup(kplugin_file(plugin));
|
|
|
+ else
|
|
|
+ file_name = faux_str_sprintf(KPLUGIN_SONAME_FMT, id);
|
|
|
+
|
|
|
+ // Symbol names
|
|
|
+ major_name = faux_str_sprintf(KPLUGIN_MAJOR_FMT, id);
|
|
|
+ minor_name = faux_str_sprintf(KPLUGIN_MINOR_FMT, id);
|
|
|
+ init_name = faux_str_sprintf(KPLUGIN_INIT_FMT, id);
|
|
|
+ fini_name = faux_str_sprintf(KPLUGIN_FINI_FMT, id);
|
|
|
+
|
|
|
+ // SO flags
|
|
|
+ if (kplugin_global(plugin))
|
|
|
+ flag |= RTLD_GLOBAL;
|
|
|
+ else
|
|
|
+ flag |= RTLD_LOCAL;
|
|
|
+
|
|
|
+ // Open shared object
|
|
|
+ plugin->dlhan = dlopen(file_name, flag);
|
|
|
+ if (!plugin->dlhan) {
|
|
|
+// fprintf(stderr, "Error: Can't open plugin \"%s\": %s\n",
|
|
|
+// this->name, dlerror());
|
|
|
+ goto err;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Get plugin version
|
|
|
+ ver = (uint8_t *)dlsym(plugin->dlhan, major_name);
|
|
|
+ if (!ver)
|
|
|
+ goto err;
|
|
|
+ kplugin_set_major(plugin, *ver);
|
|
|
+ ver = (uint8_t *)dlsym(plugin->dlhan, minor_name);
|
|
|
+ if (!ver)
|
|
|
+ goto err;
|
|
|
+ kplugin_set_minor(plugin, *ver);
|
|
|
+
|
|
|
+ // Get plugin init function
|
|
|
+ plugin->init_fn = dlsym(plugin->dlhan, init_name);
|
|
|
+ if (!plugin->init_fn) {
|
|
|
+// fprintf(stderr, "Error: Can't get plugin \"%s\" init function: %s\n",
|
|
|
+// this->name, dlerror());
|
|
|
+ goto err;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Get plugin fini function
|
|
|
+ plugin->fini_fn = dlsym(plugin->dlhan, fini_name);
|
|
|
+
|
|
|
+
|
|
|
+ retcode = BOOL_TRUE;
|
|
|
+err:
|
|
|
+ faux_str_free(file_name);
|
|
|
+ faux_str_free(major_name);
|
|
|
+ faux_str_free(minor_name);
|
|
|
+ faux_str_free(init_name);
|
|
|
+ faux_str_free(fini_name);
|
|
|
+
|
|
|
+ if (!retcode && plugin->dlhan)
|
|
|
+ dlclose(plugin->dlhan);
|
|
|
+
|
|
|
+ return retcode;
|
|
|
+}
|