Code

plugin: Unregister all callbacks if module/plugin init failed.
[sysdb.git] / src / core / plugin.c
index efbbcf78b7fb87d29250ef73c305a77e4e711dd0..472396fa5bb0efd20944d06c5e60e8ac733c5741 100644 (file)
  */
 
 struct sdb_plugin_info {
+       char *plugin_name;
+       char *filename;
+
+       /* public attributes */
        char *name;
 
        char *description;
@@ -60,7 +64,9 @@ struct sdb_plugin_info {
        int   version;
        int   plugin_version;
 };
-#define SDB_PLUGIN_INFO_INIT { /* name */ NULL, /* desc */ NULL, \
+#define SDB_PLUGIN_INFO_INIT { \
+       /* plugin_name */ NULL, /* filename */ NULL, \
+       /* name */ NULL, /* desc */ NULL, \
        /* copyright */ NULL, /* license */ NULL, \
        /* version */ -1, /* plugin_version */ -1 }
 #define INFO_GET(i, attr) \
@@ -97,7 +103,9 @@ typedef struct {
 } sdb_plugin_collector_cb_t;
 
 #define SDB_PLUGIN_CB(obj) ((sdb_plugin_cb_t *)(obj))
+#define SDB_CONST_PLUGIN_CB(obj) ((const sdb_plugin_cb_t *)(obj))
 #define SDB_PLUGIN_CCB(obj) ((sdb_plugin_collector_cb_t *)(obj))
+#define SDB_CONST_PLUGIN_CCB(obj) ((const sdb_plugin_collector_cb_t *)(obj))
 
 /*
  * private variables
@@ -121,12 +129,17 @@ static sdb_llist_t      *log_list = NULL;
  */
 
 static void
-sdb_plugin_info_clear(sdb_plugin_info_t *info)
+plugin_info_clear(sdb_plugin_info_t *info)
 {
        sdb_plugin_info_t empty_info = SDB_PLUGIN_INFO_INIT;
        if (! info)
                return;
 
+       if (info->plugin_name)
+               free(info->plugin_name);
+       if (info->filename)
+               free(info->filename);
+
        if (info->name)
                free(info->name);
        if (info->description)
@@ -137,7 +150,7 @@ sdb_plugin_info_clear(sdb_plugin_info_t *info)
                free(info->license);
 
        *info = empty_info;
-} /* sdb_plugin_info_clear */
+} /* plugin_info_clear */
 
 static void
 ctx_key_init(void)
@@ -150,7 +163,7 @@ ctx_key_init(void)
 } /* ctx_key_init */
 
 static int
-sdb_plugin_cmp_next_update(const sdb_object_t *a, const sdb_object_t *b)
+plugin_cmp_next_update(const sdb_object_t *a, const sdb_object_t *b)
 {
        const sdb_plugin_collector_cb_t *ccb1
                = (const sdb_plugin_collector_cb_t *)a;
@@ -162,7 +175,56 @@ sdb_plugin_cmp_next_update(const sdb_object_t *a, const sdb_object_t *b)
        return (ccb1->ccb_next_update > ccb2->ccb_next_update)
                ? 1 : (ccb1->ccb_next_update < ccb2->ccb_next_update)
                ? -1 : 0;
-} /* sdb_plugin_cmp_next_update */
+} /* plugin_cmp_next_update */
+
+static int
+plugin_lookup_by_name(const sdb_object_t *obj, const void *id)
+{
+       const sdb_plugin_cb_t *cb = SDB_CONST_PLUGIN_CB(obj);
+       const char *name = id;
+
+       assert(cb && id && cb->cb_ctx);
+       if (!strcasecmp(cb->cb_ctx->info.plugin_name, name))
+               return 0;
+       return 1;
+} /* plugin_lookup_by_name */
+
+static void
+plugin_unregister_by_name(const char *plugin_name)
+{
+       size_t i;
+
+       struct {
+               const char  *type;
+               sdb_llist_t *list;
+       } all_lists[] = {
+               { "config",    config_list },
+               { "init",      init_list },
+               { "collector", collector_list },
+               { "cname",     cname_list },
+               { "shutdown",  shutdown_list },
+               { "log",       log_list },
+       };
+
+       for (i = 0; i < SDB_STATIC_ARRAY_LEN(all_lists); ++i) {
+               const char  *type = all_lists[i].type;
+               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);
+
+                       if (! obj)
+                               break;
+
+                       sdb_log(SDB_LOG_INFO, "plugin: Unregistering "
+                                       "%s callback '%s' (module %s)", type, obj->name,
+                                       cb->cb_ctx->info.plugin_name);
+                       sdb_object_deref(obj);
+               }
+       }
+} /* plugin_unregister_by_name */
 
 /*
  * private types
@@ -184,7 +246,7 @@ static void
 ctx_destroy(sdb_object_t *obj)
 {
        ctx_t *ctx = CTX(obj);
-       sdb_plugin_info_clear(&ctx->info);
+       plugin_info_clear(&ctx->info);
 } /* ctx_destroy */
 
 static sdb_type_t ctx_type = {
@@ -231,7 +293,7 @@ ctx_set(ctx_t *new)
 } /* ctx_set */
 
 static int
-sdb_plugin_cb_init(sdb_object_t *obj, va_list ap)
+plugin_cb_init(sdb_object_t *obj, va_list ap)
 {
        sdb_llist_t **list = va_arg(ap, sdb_llist_t **);
        const char   *type = va_arg(ap, const char *);
@@ -256,32 +318,32 @@ sdb_plugin_cb_init(sdb_object_t *obj, va_list ap)
        sdb_object_ref(ud);
        SDB_PLUGIN_CB(obj)->cb_user_data = ud;
        return 0;
-} /* sdb_plugin_cb_init */
+} /* plugin_cb_init */
 
 static void
-sdb_plugin_cb_destroy(sdb_object_t *obj)
+plugin_cb_destroy(sdb_object_t *obj)
 {
        assert(obj);
        sdb_object_deref(SDB_PLUGIN_CB(obj)->cb_user_data);
        sdb_object_deref(SDB_OBJ(SDB_PLUGIN_CB(obj)->cb_ctx));
-} /* sdb_plugin_cb_destroy */
+} /* plugin_cb_destroy */
 
 static sdb_type_t sdb_plugin_cb_type = {
        sizeof(sdb_plugin_cb_t),
 
-       sdb_plugin_cb_init,
-       sdb_plugin_cb_destroy
+       plugin_cb_init,
+       plugin_cb_destroy
 };
 
 static sdb_type_t sdb_plugin_collector_cb_type = {
        sizeof(sdb_plugin_collector_cb_t),
 
-       sdb_plugin_cb_init,
-       sdb_plugin_cb_destroy
+       plugin_cb_init,
+       plugin_cb_destroy
 };
 
 static int
-sdb_plugin_add_callback(sdb_llist_t **list, const char *type,
+plugin_add_callback(sdb_llist_t **list, const char *type,
                const char *name, void *callback, sdb_object_t *user_data)
 {
        sdb_object_t *obj;
@@ -312,7 +374,7 @@ sdb_plugin_add_callback(sdb_llist_t **list, const char *type,
        sdb_log(SDB_LOG_INFO, "plugin: Registered %s callback '%s'.",
                        type, name);
        return 0;
-} /* sdb_plugin_add_callback */
+} /* plugin_add_callback */
 
 /*
  * public API
@@ -377,6 +439,9 @@ sdb_plugin_load(const char *name, const sdb_plugin_ctx_t *plugin_ctx)
                return -1;
        }
 
+       ctx->info.plugin_name = strdup(name);
+       ctx->info.filename = strdup(filename);
+
        if (plugin_ctx)
                ctx->public = *plugin_ctx;
 
@@ -391,7 +456,8 @@ sdb_plugin_load(const char *name, const sdb_plugin_ctx_t *plugin_ctx)
        status = mod_init(&ctx->info);
        if (status) {
                sdb_log(SDB_LOG_ERR, "plugin: Failed to initialize "
-                               "plugin '%s'", name);
+                               "module '%s'", name);
+               plugin_unregister_by_name(ctx->info.plugin_name);
                sdb_object_deref(SDB_OBJ(ctx));
                return -1;
        }
@@ -492,7 +558,7 @@ sdb_plugin_set_info(sdb_plugin_info_t *info, int type, ...)
 int
 sdb_plugin_register_config(const char *name, sdb_plugin_config_cb callback)
 {
-       return sdb_plugin_add_callback(&config_list, "init", name,
+       return plugin_add_callback(&config_list, "init", name,
                        callback, NULL);
 } /* sdb_plugin_register_config */
 
@@ -500,7 +566,7 @@ int
 sdb_plugin_register_init(const char *name, sdb_plugin_init_cb callback,
                sdb_object_t *user_data)
 {
-       return sdb_plugin_add_callback(&init_list, "init", name,
+       return plugin_add_callback(&init_list, "init", name,
                        callback, user_data);
 } /* sdb_plugin_register_init */
 
@@ -508,7 +574,7 @@ int
 sdb_plugin_register_shutdown(const char *name, sdb_plugin_shutdown_cb callback,
                sdb_object_t *user_data)
 {
-       return sdb_plugin_add_callback(&shutdown_list, "shutdown", name,
+       return plugin_add_callback(&shutdown_list, "shutdown", name,
                        callback, user_data);
 } /* sdb_plugin_register_shutdown */
 
@@ -516,7 +582,7 @@ int
 sdb_plugin_register_log(const char *name, sdb_plugin_log_cb callback,
                sdb_object_t *user_data)
 {
-       return sdb_plugin_add_callback(&log_list, "log", name, callback,
+       return plugin_add_callback(&log_list, "log", name, callback,
                        user_data);
 } /* sdb_plugin_register_log */
 
@@ -524,7 +590,7 @@ int
 sdb_plugin_register_cname(const char *name, sdb_plugin_cname_cb callback,
                sdb_object_t *user_data)
 {
-       return sdb_plugin_add_callback(&cname_list, "cname", name, callback,
+       return plugin_add_callback(&cname_list, "cname", name, callback,
                        user_data);
 } /* sdb_plugin_register_cname */
 
@@ -567,7 +633,7 @@ sdb_plugin_register_collector(const char *name, sdb_plugin_collector_cb callback
        }
 
        if (sdb_llist_insert_sorted(collector_list, obj,
-                               sdb_plugin_cmp_next_update)) {
+                               plugin_cmp_next_update)) {
                sdb_object_deref(obj);
                return -1;
        }
@@ -646,25 +712,31 @@ int
 sdb_plugin_init_all(void)
 {
        sdb_llist_iter_t *iter;
+       int ret = 0;
 
        iter = sdb_llist_get_iter(init_list);
        while (sdb_llist_iter_has_next(iter)) {
+               sdb_plugin_cb_t *cb;
                sdb_plugin_init_cb callback;
                ctx_t *old_ctx;
 
                sdb_object_t *obj = sdb_llist_iter_get_next(iter);
                assert(obj);
+               cb = SDB_PLUGIN_CB(obj);
 
-               callback = SDB_PLUGIN_CB(obj)->cb_callback;
+               callback = cb->cb_callback;
 
-               old_ctx = ctx_set(SDB_PLUGIN_CB(obj)->cb_ctx);
-               if (callback(SDB_PLUGIN_CB(obj)->cb_user_data)) {
-                       /* XXX: unload plugin */
+               old_ctx = ctx_set(cb->cb_ctx);
+               if (callback(cb->cb_user_data)) {
+                       sdb_log(SDB_LOG_ERR, "plugin: Failed to initialize plugin "
+                                       "'%s'. Unregistering all callbacks.", obj->name);
+                       plugin_unregister_by_name(cb->cb_ctx->info.plugin_name);
+                       ++ret;
                }
                ctx_set(old_ctx);
        }
        sdb_llist_iter_destroy(iter);
-       return 0;
+       return ret;
 } /* sdb_plugin_init_all */
 
 int
@@ -750,7 +822,7 @@ sdb_plugin_collector_loop(sdb_plugin_loop_t *loop)
                }
 
                if (sdb_llist_insert_sorted(collector_list, obj,
-                                       sdb_plugin_cmp_next_update)) {
+                                       plugin_cmp_next_update)) {
                        sdb_log(SDB_LOG_ERR, "plugin: Failed to re-insert "
                                        "plugin '%s' into collector list. Unable to further "
                                        "use the plugin.",