X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Fcore%2Fplugin.c;h=e6df9e9c2a9da7b1746fba2121492dbce630f0bc;hb=7bea0dab48f1b8665e8f003c48b80aa996cf75a5;hp=8200338a9d8fbb0804869b96f9267ed7b776e683;hpb=ddb7ffc175e49abfa69c82777b88d73e1f1103fb;p=sysdb.git diff --git a/src/core/plugin.c b/src/core/plugin.c index 8200338..e6df9e9 100644 --- a/src/core/plugin.c +++ b/src/core/plugin.c @@ -25,6 +25,10 @@ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#if HAVE_CONFIG_H +# include "config.h" +#endif /* HAVE_CONFIG_H */ + #include "sysdb.h" #include "core/plugin.h" #include "core/time.h" @@ -77,9 +81,15 @@ typedef struct { sdb_plugin_ctx_t public; sdb_plugin_info_t info; + lt_dlhandle handle; + + /* The usage count differs from the object's ref count + * in that it provides higher level information about how + * the plugin is in use. */ + size_t use_cnt; } ctx_t; #define CTX_INIT { SDB_OBJECT_INIT, \ - SDB_PLUGIN_CTX_INIT, SDB_PLUGIN_INFO_INIT } + SDB_PLUGIN_CTX_INIT, SDB_PLUGIN_INFO_INIT, NULL, 0 } #define CTX(obj) ((ctx_t *)(obj)) @@ -117,6 +127,9 @@ static sdb_plugin_info_t plugin_default_info = SDB_PLUGIN_INFO_INIT; static pthread_key_t plugin_ctx_key; static _Bool plugin_ctx_key_initialized = 0; +/* a list of the plugin contexts of all registered plugins */ +static sdb_llist_t *all_plugins = NULL; + static sdb_llist_t *config_list = NULL; static sdb_llist_t *init_list = NULL; static sdb_llist_t *collector_list = NULL; @@ -192,6 +205,7 @@ plugin_lookup_by_name(const sdb_object_t *obj, const void *id) static void plugin_unregister_by_name(const char *plugin_name) { + sdb_object_t *obj; size_t i; struct { @@ -211,19 +225,25 @@ plugin_unregister_by_name(const char *plugin_name) sdb_llist_t *list = all_lists[i].list; while (1) { - sdb_object_t *obj = sdb_llist_remove(list, - plugin_lookup_by_name, plugin_name); - sdb_plugin_cb_t *cb = SDB_PLUGIN_CB(obj); + sdb_plugin_cb_t *cb; - if (! obj) + cb = SDB_PLUGIN_CB(sdb_llist_remove(list, + plugin_lookup_by_name, plugin_name)); + if (! cb) break; sdb_log(SDB_LOG_INFO, "core: Unregistering " - "%s callback '%s' (module %s)", type, obj->name, + "%s callback '%s' (module %s)", type, cb->super.name, cb->cb_ctx->info.plugin_name); - sdb_object_deref(obj); + sdb_object_deref(SDB_OBJ(cb)); } } + + obj = sdb_llist_search_by_name(all_plugins, plugin_name); + if (obj->ref_cnt <= 1) + sdb_llist_remove_by_name(all_plugins, plugin_name); + /* else: other callbacks still reference it */ + sdb_object_deref(obj); } /* plugin_unregister_by_name */ /* @@ -239,6 +259,8 @@ ctx_init(sdb_object_t *obj, va_list __attribute__((unused)) ap) ctx->public = plugin_default_ctx; ctx->info = plugin_default_info; + ctx->handle = NULL; + ctx->use_cnt = 1; return 0; } /* ctx_init */ @@ -246,6 +268,20 @@ static void ctx_destroy(sdb_object_t *obj) { ctx_t *ctx = CTX(obj); + + if (ctx->handle) { + const char *err; + + sdb_log(SDB_LOG_INFO, "core: Unloading module %s", + ctx->info.plugin_name); + + lt_dlerror(); + lt_dlclose(ctx->handle); + if ((err = lt_dlerror())) + sdb_log(SDB_LOG_WARNING, "core: Failed to unload module %s: %s", + ctx->info.plugin_name, err); + } + plugin_info_clear(&ctx->info); } /* ctx_destroy */ @@ -257,16 +293,17 @@ static sdb_type_t ctx_type = { }; static ctx_t * -ctx_create(void) +ctx_create(const char *name) { ctx_t *ctx; - ctx = CTX(sdb_object_create("plugin-context", ctx_type)); + ctx = CTX(sdb_object_create(name, ctx_type)); if (! ctx) return NULL; if (! plugin_ctx_key_initialized) ctx_key_init(); + sdb_object_ref(SDB_OBJ(ctx)); pthread_setspecific(plugin_ctx_key, ctx); return ctx; } /* ctx_create */ @@ -288,6 +325,10 @@ ctx_set(ctx_t *new) ctx_key_init(); old = pthread_getspecific(plugin_ctx_key); + if (old) + sdb_object_deref(SDB_OBJ(old)); + if (new) + sdb_object_ref(SDB_OBJ(new)); pthread_setspecific(plugin_ctx_key, new); return old; } /* ctx_set */ @@ -383,7 +424,7 @@ plugin_add_callback(sdb_llist_t **list, const char *type, int sdb_plugin_load(const char *name, const sdb_plugin_ctx_t *plugin_ctx) { - char real_name[strlen(name) > 0 ? strlen(name) : 1]; + char base_name[name ? strlen(name) + 1 : 1]; const char *name_ptr; char *tmp; @@ -398,18 +439,25 @@ sdb_plugin_load(const char *name, const sdb_plugin_ctx_t *plugin_ctx) if ((! name) || (! *name)) return -1; - real_name[0] = '\0'; + base_name[0] = '\0'; name_ptr = name; while ((tmp = strstr(name_ptr, "::"))) { - strncat(real_name, name_ptr, (size_t)(tmp - name_ptr)); - strcat(real_name, "/"); + strncat(base_name, name_ptr, (size_t)(tmp - name_ptr)); + strcat(base_name, "/"); name_ptr = tmp + strlen("::"); } - strcat(real_name, name_ptr); + strcat(base_name, name_ptr); + + ctx = CTX(sdb_llist_search_by_name(all_plugins, base_name)); + if (ctx) { + /* plugin already loaded */ + ++ctx->use_cnt; + return 0; + } snprintf(filename, sizeof(filename), "%s/%s.so", - PKGLIBDIR, real_name); + PKGLIBDIR, base_name); filename[sizeof(filename) - 1] = '\0'; if (access(filename, R_OK)) { @@ -433,7 +481,7 @@ sdb_plugin_load(const char *name, const sdb_plugin_ctx_t *plugin_ctx) if (ctx_get()) sdb_log(SDB_LOG_WARNING, "core: Discarding old plugin context"); - ctx = ctx_create(); + ctx = ctx_create(name); if (! ctx) { sdb_log(SDB_LOG_ERR, "core: Failed to initialize plugin context"); return -1; @@ -441,6 +489,7 @@ sdb_plugin_load(const char *name, const sdb_plugin_ctx_t *plugin_ctx) ctx->info.plugin_name = strdup(name); ctx->info.filename = strdup(filename); + ctx->handle = lh; if (plugin_ctx) ctx->public = *plugin_ctx; @@ -471,6 +520,18 @@ sdb_plugin_load(const char *name, const sdb_plugin_ctx_t *plugin_ctx) name, SDB_VERSION_DECODE(ctx->info.version), SDB_VERSION_DECODE(SDB_VERSION)); + if (! all_plugins) { + if (! (all_plugins = sdb_llist_create())) { + sdb_log(SDB_LOG_ERR, "core: Failed to load plugin '%s': " + "internal error while creating linked list", name); + plugin_unregister_by_name(ctx->info.plugin_name); + sdb_object_deref(SDB_OBJ(ctx)); + return -1; + } + } + + sdb_llist_append(all_plugins, SDB_OBJ(ctx)); + sdb_log(SDB_LOG_INFO, "core: Successfully loaded " "plugin '%s' v%i (%s)\n\t%s\n\tLicense: %s", INFO_GET(&ctx->info, name), ctx->info.plugin_version, @@ -559,7 +620,7 @@ int sdb_plugin_register_config(const char *name, sdb_plugin_config_cb callback) { return plugin_add_callback(&config_list, "init", name, - callback, NULL); + (void *)callback, NULL); } /* sdb_plugin_register_config */ int @@ -567,7 +628,7 @@ sdb_plugin_register_init(const char *name, sdb_plugin_init_cb callback, sdb_object_t *user_data) { return plugin_add_callback(&init_list, "init", name, - callback, user_data); + (void *)callback, user_data); } /* sdb_plugin_register_init */ int @@ -575,14 +636,14 @@ sdb_plugin_register_shutdown(const char *name, sdb_plugin_shutdown_cb callback, sdb_object_t *user_data) { return plugin_add_callback(&shutdown_list, "shutdown", name, - callback, user_data); + (void *)callback, user_data); } /* sdb_plugin_register_shutdown */ int sdb_plugin_register_log(const char *name, sdb_plugin_log_cb callback, sdb_object_t *user_data) { - return plugin_add_callback(&log_list, "log", name, callback, + return plugin_add_callback(&log_list, "log", name, (void *)callback, user_data); } /* sdb_plugin_register_log */ @@ -590,7 +651,7 @@ int sdb_plugin_register_cname(const char *name, sdb_plugin_cname_cb callback, sdb_object_t *user_data) { - return plugin_add_callback(&cname_list, "cname", name, callback, + return plugin_add_callback(&cname_list, "cname", name, (void *)callback, user_data); } /* sdb_plugin_register_cname */ @@ -694,15 +755,18 @@ sdb_plugin_configure(const char *name, oconfig_item_t *ci) plugin = SDB_PLUGIN_CB(sdb_llist_search_by_name(config_list, name)); if (! plugin) { - /* XXX: check if any such plugin has been loaded */ - sdb_log(SDB_LOG_ERR, "core: Plugin '%s' did not register " - "a config callback.", name); + ctx_t *ctx = CTX(sdb_llist_search_by_name(all_plugins, name)); + if (! ctx) + sdb_log(SDB_LOG_ERR, "core: Plugin '%s' not loaded.", name); + else + sdb_log(SDB_LOG_ERR, "core: Plugin '%s' did not register " + "a config callback.", name); errno = ENOENT; return -1; } old_ctx = ctx_set(plugin->cb_ctx); - callback = plugin->cb_callback; + callback = (sdb_plugin_config_cb)plugin->cb_callback; status = callback(ci); ctx_set(old_ctx); return status; @@ -724,7 +788,7 @@ sdb_plugin_init_all(void) assert(obj); cb = SDB_PLUGIN_CB(obj); - callback = cb->cb_callback; + callback = (sdb_plugin_init_cb)cb->cb_callback; old_ctx = ctx_set(cb->cb_ctx); if (callback(cb->cb_user_data)) { @@ -761,7 +825,7 @@ sdb_plugin_collector_loop(sdb_plugin_loop_t *loop) if (! obj) return -1; - callback = SDB_PLUGIN_CCB(obj)->ccb_callback; + callback = (sdb_plugin_collector_cb)SDB_PLUGIN_CCB(obj)->ccb_callback; if (! (now = sdb_gettime())) { char errbuf[1024]; @@ -859,7 +923,7 @@ sdb_plugin_cname(char *hostname) sdb_object_t *obj = sdb_llist_iter_get_next(iter); assert(obj); - callback = SDB_PLUGIN_CB(obj)->cb_callback; + callback = (sdb_plugin_cname_cb)SDB_PLUGIN_CB(obj)->cb_callback; cname = callback(hostname, SDB_PLUGIN_CB(obj)->cb_user_data); if (cname) { free(hostname); @@ -891,7 +955,7 @@ sdb_plugin_log(int prio, const char *msg) sdb_object_t *obj = sdb_llist_iter_get_next(iter); assert(obj); - callback = SDB_PLUGIN_CB(obj)->cb_callback; + callback = (sdb_plugin_log_cb)SDB_PLUGIN_CB(obj)->cb_callback; tmp = callback(prio, msg, SDB_PLUGIN_CB(obj)->cb_user_data); if (tmp > ret) ret = tmp;