Browse Source

scheme: Working on plugin

Serj Kalichev 3 years ago
parent
commit
72a08d698c
3 changed files with 118 additions and 1 deletions
  1. 17 1
      klish/kplugin.h
  2. 1 0
      klish/kscheme/iplugin.c
  3. 100 0
      klish/kscheme/kplugin.c

+ 17 - 1
klish/kplugin.h

@@ -11,10 +11,24 @@
 
 #include <klish/ksym.h>
 
-// Plugin API version
+// Current API version
 #define KPLUGIN_MAJOR 1
 #define KPLUGIN_MINOR 0
 
+// Shared object filename template. Insert plugin ID or plugin "name" field
+// instead "%s". Consider plugin ID as an "internal native name". The "name"
+// field can differ from ID and it's just used within scheme to refer plugin.
+// Consider it as alias of ID.
+#define KPLUGIN_SONAME_FMT "kplugin_%s.so"
+
+// Plugin's API version symbols
+#define KPLUGIN_MAJOR_FMT "kplugin_%s_major"
+#define KPLUGIN_MINOR_FMT "kplugin_%s_minor"
+
+// Plugin's init and fini functions
+#define KPLUGIN_INIT_FMT "kplugin_%s_init"
+#define KPLUGIN_FINI_FMT "kplugin_%s_fini"
+
 
 typedef struct kplugin_s kplugin_t;
 
@@ -64,6 +78,8 @@ uint8_t kplugin_major(const kplugin_t *plugin);
 bool_t kplugin_set_major(kplugin_t *plugin, uint8_t major);
 uint8_t kplugin_minor(const kplugin_t *plugin);
 bool_t kplugin_set_minor(kplugin_t *plugin, uint8_t minor);
+void *kplugin_udata(const kplugin_t *plugin);
+bool_t kplugin_set_udata(kplugin_t *plugin, void *udata);
 
 bool_t kplugin_add_sym(kplugin_t *plugin, ksym_t *sym);
 ksym_t *kplugin_find_sym(const kplugin_t *plugin, const char *name);

+ 1 - 0
klish/kscheme/iplugin.c

@@ -22,6 +22,7 @@ char *iplugin_to_text(const iplugin_t *iplugin, int level)
 	attr2ctext(&str, "id", iplugin->id, level + 1);
 	attr2ctext(&str, "file", iplugin->file, level + 1);
 	attr2ctext(&str, "global", iplugin->global, level + 1);
+	attr2ctext(&str, "conf", iplugin->conf, level + 1);
 
 	tmp = faux_str_sprintf("%*c},\n\n", level, ' ');
 	faux_str_cat(&str, tmp);

+ 100 - 0
klish/kscheme/kplugin.c

@@ -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;
+}