diff --git a/src/core/plugin.c b/src/core/plugin.c
index 5fdaca0db885b9ba3c0870ac301cd13c17017602..eb9797fb40f8ba694f687acec082792877d115fd 100644 (file)
--- a/src/core/plugin.c
+++ b/src/core/plugin.c
* 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/error.h"
#include "core/time.h"
+#include "utils/error.h"
#include "utils/llist.h"
+#include "utils/strbuf.h"
#include <assert.h>
*/
struct sdb_plugin_info {
+ char *plugin_name;
+ char *filename;
+
+ /* public attributes */
char *name;
char *description;
int version;
int plugin_version;
};
-#define SDB_PLUGIN_INFO_INIT { "no name set", "no description set", \
- /* copyright */ "", /* license */ "", \
+#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) \
+ ((i)->attr ? (i)->attr : #attr" not set")
+
+typedef struct {
+ sdb_object_t super;
+ 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, NULL, 0 }
+
+#define CTX(obj) ((ctx_t *)(obj))
typedef struct {
sdb_object_t super;
- char cb_name[64];
void *cb_callback;
sdb_object_t *cb_user_data;
- sdb_plugin_ctx_t cb_ctx;
+ ctx_t *cb_ctx;
} sdb_plugin_cb_t;
-#define SDB_PLUGIN_CB_INIT { SDB_OBJECT_INIT, /* name = */ "", \
+#define SDB_PLUGIN_CB_INIT { SDB_OBJECT_INIT, \
/* callback = */ NULL, /* user_data = */ NULL, \
SDB_PLUGIN_CTX_INIT }
typedef struct {
sdb_plugin_cb_t super;
-#define ccb_name super.cb_name
#define ccb_callback super.cb_callback
#define ccb_user_data super.cb_user_data
#define ccb_ctx super.cb_ctx
} 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
*/
-static sdb_plugin_ctx_t plugin_default_ctx = SDB_PLUGIN_CTX_INIT;
+static sdb_plugin_ctx_t plugin_default_ctx = SDB_PLUGIN_CTX_INIT;
+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;
+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;
+static sdb_llist_t *cname_list = NULL;
static sdb_llist_t *shutdown_list = NULL;
+static sdb_llist_t *log_list = NULL;
+
+static 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 },
+};
/*
* private helper functions
*/
static void
-sdb_plugin_ctx_destructor(void *ctx)
+plugin_info_clear(sdb_plugin_info_t *info)
{
- if (! ctx)
+ sdb_plugin_info_t empty_info = SDB_PLUGIN_INFO_INIT;
+ if (! info)
return;
- free(ctx);
-} /* sdb_plugin_ctx_destructor */
+
+ if (info->plugin_name)
+ free(info->plugin_name);
+ if (info->filename)
+ free(info->filename);
+
+ if (info->name)
+ free(info->name);
+ if (info->description)
+ free(info->description);
+ if (info->copyright)
+ free(info->copyright);
+ if (info->license)
+ free(info->license);
+
+ *info = empty_info;
+} /* plugin_info_clear */
static void
-sdb_plugin_ctx_init(void)
+ctx_key_init(void)
{
if (plugin_ctx_key_initialized)
return;
- pthread_key_create(&plugin_ctx_key, sdb_plugin_ctx_destructor);
+ pthread_key_create(&plugin_ctx_key, /* destructor */ NULL);
plugin_ctx_key_initialized = 1;
-} /* sdb_plugin_ctx_init */
-
-static sdb_plugin_ctx_t *
-sdb_plugin_ctx_create(void)
-{
- sdb_plugin_ctx_t *ctx;
-
- ctx = malloc(sizeof(*ctx));
- if (! ctx)
- return NULL;
-
- *ctx = plugin_default_ctx;
-
- if (! plugin_ctx_key_initialized)
- sdb_plugin_ctx_init();
- pthread_setspecific(plugin_ctx_key, ctx);
- return ctx;
-} /* sdb_plugin_ctx_create */
+} /* ctx_key_init */
static int
-sdb_plugin_cmp_name(const sdb_object_t *a, const sdb_object_t *b)
-{
- const sdb_plugin_cb_t *cb1 = (const sdb_plugin_cb_t *)a;
- const sdb_plugin_cb_t *cb2 = (const sdb_plugin_cb_t *)b;
-
- assert(cb1 && cb2);
- return strcasecmp(cb1->cb_name, cb2->cb_name);
-} /* sdb_plugin_cmp_name */
-
-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;
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 sdb_plugin_cb_t *
-sdb_plugin_find_by_name(sdb_llist_t *list, const char *name)
+static int
+plugin_lookup_by_name(const sdb_object_t *obj, const void *id)
{
- sdb_plugin_cb_t tmp = SDB_PLUGIN_CB_INIT;
+ const sdb_plugin_cb_t *cb = SDB_CONST_PLUGIN_CB(obj);
+ const char *name = id;
+ assert(cb && id);
+
+ /* when a plugin was registered from outside a plugin (e.g. the core),
+ * we don't have a plugin context */
+ if (! cb->cb_ctx)
+ return 1;
+
+ if (!strcasecmp(cb->cb_ctx->info.plugin_name, name))
+ return 0;
+ return 1;
+} /* plugin_lookup_by_name */
+
+/* since this function is called from sdb_plugin_reconfigure_finish()
+ * when iterating through all_plugins, we may not do any additional
+ * modifications to all_plugins except for the optional removal */
+static void
+plugin_unregister_by_name(const char *plugin_name)
+{
sdb_object_t *obj;
- assert(name);
+ size_t i;
- if (! list)
- return NULL;
+ 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;
- snprintf(tmp.cb_name, sizeof(tmp.cb_name), "%s", name);
- tmp.cb_name[sizeof(tmp.cb_name) - 1] = '\0';
- obj = sdb_llist_search(list, SDB_OBJ(&tmp), sdb_plugin_cmp_name);
- if (! obj)
+ while (1) {
+ sdb_plugin_cb_t *cb;
+
+ cb = SDB_PLUGIN_CB(sdb_llist_remove(list,
+ plugin_lookup_by_name, plugin_name));
+ if (! cb)
+ break;
+
+ assert(cb->cb_ctx);
+
+ sdb_log(SDB_LOG_INFO, "core: Unregistering "
+ "%s callback '%s' (module %s)", type, cb->super.name,
+ cb->cb_ctx->info.plugin_name);
+ sdb_object_deref(SDB_OBJ(cb));
+ }
+ }
+
+ obj = sdb_llist_search_by_name(all_plugins, plugin_name);
+ /* when called from sdb_plugin_reconfigure_finish, the object has already
+ * been removed from the list */
+ if (obj && (obj->ref_cnt <= 1)) {
+ sdb_llist_remove_by_name(all_plugins, plugin_name);
+ sdb_object_deref(obj);
+ }
+ /* else: other callbacks still reference it */
+} /* plugin_unregister_by_name */
+
+static void
+plugin_unregister_all(void)
+{
+ size_t i;
+
+ 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;
+
+ size_t len = sdb_llist_len(list);
+
+ if (! len)
+ continue;
+
+ sdb_llist_clear(list);
+ sdb_log(SDB_LOG_INFO, "core: Unregistered %zu %s callback%s",
+ len, type, len == 1 ? "" : "s");
+ }
+} /* plugin_unregister_all */
+
+/*
+ * private types
+ */
+
+static int
+ctx_init(sdb_object_t *obj, va_list __attribute__((unused)) ap)
+{
+ ctx_t *ctx = CTX(obj);
+
+ assert(ctx);
+
+ ctx->public = plugin_default_ctx;
+ ctx->info = plugin_default_info;
+ ctx->handle = NULL;
+ ctx->use_cnt = 1;
+ return 0;
+} /* ctx_init */
+
+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 */
+
+static sdb_type_t ctx_type = {
+ sizeof(ctx_t),
+
+ ctx_init,
+ ctx_destroy
+};
+
+static ctx_t *
+ctx_get(void)
+{
+ if (! plugin_ctx_key_initialized)
+ ctx_key_init();
+ return pthread_getspecific(plugin_ctx_key);
+} /* ctx_get */
+
+static ctx_t *
+ctx_set(ctx_t *new)
+{
+ ctx_t *old;
+
+ if (! plugin_ctx_key_initialized)
+ 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 */
+
+static ctx_t *
+ctx_create(const char *name)
+{
+ ctx_t *ctx;
+
+ ctx = CTX(sdb_object_create(name, ctx_type));
+ if (! ctx)
return NULL;
- return SDB_PLUGIN_CB(obj);
-} /* sdb_plugin_find_by_name */
+
+ if (! plugin_ctx_key_initialized)
+ ctx_key_init();
+ ctx_set(ctx);
+ return ctx;
+} /* ctx_create */
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 *);
- const char *name = va_arg(ap, const char *);
- void *callback = va_arg(ap, void *);
+ const char *type = va_arg(ap, const char *);
+ void *callback = va_arg(ap, void *);
sdb_object_t *ud = va_arg(ap, sdb_object_t *);
assert(list);
assert(type);
assert(obj);
- if (sdb_plugin_find_by_name(*list, name)) {
- sdb_log(SDB_LOG_WARNING, "plugin: %s callback '%s' "
+ if (sdb_llist_search_by_name(*list, obj->name)) {
+ sdb_log(SDB_LOG_WARNING, "core: %s callback '%s' "
"has already been registered. Ignoring newly "
- "registered version.", type, name);
+ "registered version.", type, obj->name);
return -1;
}
- snprintf(SDB_PLUGIN_CB(obj)->cb_name,
- sizeof(SDB_PLUGIN_CB(obj)->cb_name),
- "%s", name);
- SDB_PLUGIN_CB(obj)->cb_name[sizeof(SDB_PLUGIN_CB(obj)->cb_name) - 1] = '\0';
+ /* cb_ctx may be NULL if the plugin was not registered by a plugin */
+
SDB_PLUGIN_CB(obj)->cb_callback = callback;
- SDB_PLUGIN_CB(obj)->cb_ctx = sdb_plugin_get_ctx();
+ SDB_PLUGIN_CB(obj)->cb_ctx = ctx_get();
+ sdb_object_ref(SDB_OBJ(SDB_PLUGIN_CB(obj)->cb_ctx));
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_plugin_cb_destroy */
+ sdb_object_deref(SDB_OBJ(SDB_PLUGIN_CB(obj)->cb_ctx));
+} /* plugin_cb_destroy */
-static int
-sdb_plugin_add_callback(sdb_llist_t **list, const char *type,
- const char *name, void *callback, sdb_object_t *user_data)
-{
- sdb_object_t *obj;
+static sdb_type_t sdb_plugin_cb_type = {
+ sizeof(sdb_plugin_cb_t),
- if ((! name) || (! callback))
- return -1;
+ plugin_cb_init,
+ plugin_cb_destroy
+};
- assert(list);
+static sdb_type_t sdb_plugin_collector_cb_type = {
+ sizeof(sdb_plugin_collector_cb_t),
- if (! *list)
- *list = sdb_llist_create();
- if (! *list)
- return -1;
+ plugin_cb_init,
+ plugin_cb_destroy
+};
- obj = sdb_object_create(sizeof(sdb_plugin_cb_t), sdb_plugin_cb_init,
- sdb_plugin_cb_destroy, list, type, name, callback, user_data);
- if (! obj)
- return -1;
+static int
+module_init(const char *name, lt_dlhandle lh, sdb_plugin_info_t *info)
+{
+ int (*mod_init)(sdb_plugin_info_t *);
+ int status;
- if (sdb_llist_append(*list, obj)) {
- sdb_object_deref(obj);
+ mod_init = (int (*)(sdb_plugin_info_t *))lt_dlsym(lh, "sdb_module_init");
+ if (! mod_init) {
+ sdb_log(SDB_LOG_ERR, "core: Failed to load plugin '%s': "
+ "could not find symbol 'sdb_module_init'", name);
return -1;
}
- /* pass control to the list */
- sdb_object_deref(obj);
-
- sdb_log(SDB_LOG_INFO, "plugin: Registered %s callback '%s'.",
- type, name);
+ status = mod_init(info);
+ if (status) {
+ sdb_log(SDB_LOG_ERR, "core: Failed to initialize "
+ "module '%s'", name);
+ plugin_unregister_by_name(name);
+ return -1;
+ }
return 0;
-} /* sdb_plugin_add_callback */
+} /* module_init */
-/*
- * public API
- */
-
-int
-sdb_plugin_load(const char *name)
+static int
+module_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;
char filename[1024];
-
lt_dlhandle lh;
- int (*mod_init)(sdb_plugin_info_t *);
- sdb_plugin_info_t plugin_info = SDB_PLUGIN_INFO_INIT;
+ ctx_t *ctx;
int status;
- if ((! name) || (! *name))
- return -1;
+ assert(name);
- 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);
snprintf(filename, sizeof(filename), "%s/%s.so",
- PKGLIBDIR, real_name);
+ PKGLIBDIR, base_name);
filename[sizeof(filename) - 1] = '\0';
if (access(filename, R_OK)) {
char errbuf[1024];
- sdb_log(SDB_LOG_ERR, "plugin: Failed to load plugin '%s' (%s): %s",
+ sdb_log(SDB_LOG_ERR, "core: Failed to load plugin '%s' (%s): %s",
name, filename, sdb_strerror(errno, errbuf, sizeof(errbuf)));
return -1;
}
lh = lt_dlopen(filename);
if (! lh) {
- sdb_log(SDB_LOG_ERR, "plugin: Failed to load plugin '%s': %s"
+ sdb_log(SDB_LOG_ERR, "core: Failed to load plugin '%s': %s"
"The most common cause for this problem are missing "
"dependencies.\n", name, lt_dlerror());
return -1;
}
- mod_init = (int (*)(sdb_plugin_info_t *))lt_dlsym(lh, "sdb_module_init");
- if (! mod_init) {
- sdb_log(SDB_LOG_ERR, "plugin: Failed to load plugin '%s': "
- "could not find symbol 'sdb_module_init'", name);
+ if (ctx_get())
+ sdb_log(SDB_LOG_WARNING, "core: Discarding old plugin context");
+
+ ctx = ctx_create(name);
+ if (! ctx) {
+ sdb_log(SDB_LOG_ERR, "core: Failed to initialize plugin context");
return -1;
}
- status = mod_init(&plugin_info);
- if (status) {
- sdb_log(SDB_LOG_ERR, "plugin: Failed to initialize "
- "plugin '%s'", name);
- return -1;
+ ctx->info.plugin_name = strdup(name);
+ ctx->info.filename = strdup(filename);
+ ctx->handle = lh;
+
+ if (plugin_ctx)
+ ctx->public = *plugin_ctx;
+
+ if ((status = module_init(name, lh, &ctx->info))) {
+ sdb_object_deref(SDB_OBJ(ctx));
+ return status;
}
/* compare minor version */
- if ((plugin_info.version < 0)
- || ((int)(plugin_info.version / 100) != (int)(SDB_VERSION / 100)))
- sdb_log(SDB_LOG_WARNING, "plugin: WARNING: version of "
+ if ((ctx->info.version < 0)
+ || ((int)(ctx->info.version / 100) != (int)(SDB_VERSION / 100)))
+ sdb_log(SDB_LOG_WARNING, "core: WARNING: version of "
"plugin '%s' (%i.%i.%i) does not match our version "
"(%i.%i.%i); this might cause problems",
- name, SDB_VERSION_DECODE(plugin_info.version),
+ name, SDB_VERSION_DECODE(ctx->info.version),
SDB_VERSION_DECODE(SDB_VERSION));
- sdb_log(SDB_LOG_INFO, "plugin: Successfully loaded "
- "plugin '%s' v%i (%s)\n\t%s",
- plugin_info.name, plugin_info.plugin_version,
- plugin_info.description, plugin_info.copyright);
+ 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,
+ INFO_GET(&ctx->info, description),
+ INFO_GET(&ctx->info, copyright),
+ INFO_GET(&ctx->info, license));
+
+ /* any registered callbacks took ownership of the context */
+ sdb_object_deref(SDB_OBJ(ctx));
+
+ /* reset */
+ ctx_set(NULL);
+ return 0;
+} /* module_load */
+
+static int
+plugin_add_callback(sdb_llist_t **list, const char *type,
+ const char *name, void *callback, sdb_object_t *user_data)
+{
+ sdb_object_t *obj;
+
+ if ((! name) || (! callback))
+ return -1;
+
+ assert(list);
+
+ if (! *list)
+ *list = sdb_llist_create();
+ if (! *list)
+ return -1;
+
+ obj = sdb_object_create(name, sdb_plugin_cb_type,
+ list, type, callback, user_data);
+ if (! obj)
+ return -1;
+
+ if (sdb_llist_append(*list, obj)) {
+ sdb_object_deref(obj);
+ return -1;
+ }
+
+ /* pass control to the list */
+ sdb_object_deref(obj);
+
+ sdb_log(SDB_LOG_INFO, "core: Registered %s callback '%s'.",
+ type, name);
return 0;
+} /* plugin_add_callback */
+
+/*
+ * public API
+ */
+
+int
+sdb_plugin_load(const char *name, const sdb_plugin_ctx_t *plugin_ctx)
+{
+ ctx_t *ctx;
+
+ int status;
+
+ if ((! name) || (! *name))
+ return -1;
+
+ 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);
+ return -1;
+ }
+ }
+
+ ctx = CTX(sdb_llist_search_by_name(all_plugins, name));
+ if (ctx) {
+ /* plugin already loaded */
+ if (! ctx->use_cnt) {
+ /* reloading plugin */
+ ctx_t *old_ctx = ctx_set(ctx);
+
+ status = module_init(ctx->info.plugin_name, ctx->handle, NULL);
+ if (status)
+ return status;
+
+ sdb_log(SDB_LOG_INFO, "core: Successfully reloaded plugin "
+ "'%s' (%s)", INFO_GET(&ctx->info, name),
+ INFO_GET(&ctx->info, description));
+ ctx_set(old_ctx);
+ }
+ ++ctx->use_cnt;
+ return 0;
+ }
+
+ return module_load(name, plugin_ctx);
} /* sdb_plugin_load */
int
case SDB_PLUGIN_INFO_NAME:
{
char *name = va_arg(ap, char *);
- info->name = name;
+ if (name) {
+ if (info->name)
+ free(info->name);
+ info->name = strdup(name);
+ }
}
break;
case SDB_PLUGIN_INFO_DESC:
{
char *desc = va_arg(ap, char *);
- info->description = desc;
+ if (desc) {
+ if (info->description)
+ free(info->description);
+ info->description = strdup(desc);
+ }
}
break;
case SDB_PLUGIN_INFO_COPYRIGHT:
{
char *copyright = va_arg(ap, char *);
- info->copyright = copyright;
+ if (copyright)
+ info->copyright = strdup(copyright);
}
break;
case SDB_PLUGIN_INFO_LICENSE:
{
char *license = va_arg(ap, char *);
- info->license = license;
+ if (license) {
+ if (info->license)
+ free(info->license);
+ info->license = strdup(license);
+ }
}
break;
case SDB_PLUGIN_INFO_VERSION:
int
sdb_plugin_register_config(const char *name, sdb_plugin_config_cb callback)
{
- return sdb_plugin_add_callback(&config_list, "init", name,
- callback, NULL);
+ return plugin_add_callback(&config_list, "init", name,
+ (void *)callback, NULL);
} /* sdb_plugin_register_config */
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,
- callback, user_data);
+ return plugin_add_callback(&init_list, "init", name,
+ (void *)callback, user_data);
} /* sdb_plugin_register_init */
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,
- callback, user_data);
+ return plugin_add_callback(&shutdown_list, "shutdown", name,
+ (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, (void *)callback,
+ user_data);
+} /* sdb_plugin_register_log */
+
+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, (void *)callback,
+ user_data);
+} /* sdb_plugin_register_cname */
+
int
sdb_plugin_register_collector(const char *name, sdb_plugin_collector_cb callback,
const sdb_time_t *interval, sdb_object_t *user_data)
@@ -435,9 +737,8 @@ sdb_plugin_register_collector(const char *name, sdb_plugin_collector_cb callback
if (! collector_list)
return -1;
- obj = sdb_object_create(sizeof(sdb_plugin_collector_cb_t),
- sdb_plugin_cb_init, sdb_plugin_cb_destroy,
- &collector_list, "collector", name, callback, user_data);
+ obj = sdb_object_create(name, sdb_plugin_collector_cb_type,
+ &collector_list, "collector", callback, user_data);
if (! obj)
return -1;
@@ -454,14 +755,14 @@ sdb_plugin_register_collector(const char *name, sdb_plugin_collector_cb callback
if (! (SDB_PLUGIN_CCB(obj)->ccb_next_update = sdb_gettime())) {
char errbuf[1024];
- sdb_log(SDB_LOG_ERR, "plugin: Failed to determine current "
+ sdb_log(SDB_LOG_ERR, "core: Failed to determine current "
"time: %s", sdb_strerror(errno, errbuf, sizeof(errbuf)));
sdb_object_deref(obj);
return -1;
}
if (sdb_llist_insert_sorted(collector_list, obj,
- sdb_plugin_cmp_next_update)) {
+ plugin_cmp_next_update)) {
sdb_object_deref(obj);
return -1;
}
@@ -469,7 +770,7 @@ sdb_plugin_register_collector(const char *name, sdb_plugin_collector_cb callback
/* pass control to the list */
sdb_object_deref(obj);
- sdb_log(SDB_LOG_INFO, "plugin: Registered collector callback '%s' "
+ sdb_log(SDB_LOG_INFO, "core: Registered collector callback '%s' "
"(interval = %.3fs).", name,
SDB_TIME_TO_DOUBLE(SDB_PLUGIN_CCB(obj)->ccb_interval));
return 0;
@@ -478,37 +779,33 @@ sdb_plugin_register_collector(const char *name, sdb_plugin_collector_cb callback
sdb_plugin_ctx_t
sdb_plugin_get_ctx(void)
{
- sdb_plugin_ctx_t *ctx;
-
- if (! plugin_ctx_key_initialized)
- sdb_plugin_ctx_init();
- ctx = pthread_getspecific(plugin_ctx_key);
+ ctx_t *c;
- if (! ctx)
- ctx = sdb_plugin_ctx_create();
- if (! ctx)
+ c = ctx_get();
+ if (! c) {
+ sdb_plugin_log(SDB_LOG_ERR, "core: Invalid read access to plugin "
+ "context outside a plugin");
return plugin_default_ctx;
- return *ctx;
+ }
+ return c->public;
} /* sdb_plugin_get_ctx */
-sdb_plugin_ctx_t
-sdb_plugin_set_ctx(sdb_plugin_ctx_t ctx)
+int
+sdb_plugin_set_ctx(sdb_plugin_ctx_t ctx, sdb_plugin_ctx_t *old)
{
- sdb_plugin_ctx_t *tmp;
- sdb_plugin_ctx_t old;
-
- if (! plugin_ctx_key_initialized)
- sdb_plugin_ctx_init();
- tmp = pthread_getspecific(plugin_ctx_key);
+ ctx_t *c;
- if (! tmp)
- tmp = sdb_plugin_ctx_create();
- if (! tmp)
- return plugin_default_ctx;
+ c = ctx_get();
+ if (! c) {
+ sdb_plugin_log(SDB_LOG_ERR, "core: Invalid write access to plugin "
+ "context outside a plugin");
+ return -1;
+ }
- old = *tmp;
- *tmp = ctx;
- return old;
+ if (old)
+ *old = c->public;
+ c->public = ctx;
+ return 0;
} /* sdb_plugin_set_ctx */
int
sdb_plugin_cb_t *plugin;
sdb_plugin_config_cb callback;
- sdb_plugin_ctx_t old_ctx;
+ ctx_t *old_ctx;
int status;
if ((! name) || (! ci))
return -1;
- plugin = sdb_plugin_find_by_name(config_list, name);
+ 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, "plugin: 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 = sdb_plugin_set_ctx(plugin->cb_ctx);
- callback = plugin->cb_callback;
+ old_ctx = ctx_set(plugin->cb_ctx);
+ callback = (sdb_plugin_config_cb)plugin->cb_callback;
status = callback(ci);
- sdb_plugin_set_ctx(old_ctx);
+ ctx_set(old_ctx);
return status;
} /* sdb_plugin_configure */
+int
+sdb_plugin_reconfigure_init(void)
+{
+ sdb_llist_iter_t *iter;
+
+ iter = sdb_llist_get_iter(config_list);
+ if (config_list && (! iter))
+ return -1;
+
+ /* deconfigure all plugins */
+ while (sdb_llist_iter_has_next(iter)) {
+ sdb_plugin_cb_t *plugin;
+ sdb_plugin_config_cb callback;
+ ctx_t *old_ctx;
+
+ plugin = SDB_PLUGIN_CB(sdb_llist_iter_get_next(iter));
+ old_ctx = ctx_set(plugin->cb_ctx);
+ callback = (sdb_plugin_config_cb)plugin->cb_callback;
+ callback(NULL);
+ ctx_set(old_ctx);
+ }
+ sdb_llist_iter_destroy(iter);
+
+ iter = sdb_llist_get_iter(all_plugins);
+ if (all_plugins && (! iter))
+ return -1;
+
+ /* record all plugins as being unused */
+ while (sdb_llist_iter_has_next(iter))
+ CTX(sdb_llist_iter_get_next(iter))->use_cnt = 0;
+ sdb_llist_iter_destroy(iter);
+
+ plugin_unregister_all();
+ return 0;
+} /* sdb_plugin_reconfigure_init */
+
+int
+sdb_plugin_reconfigure_finish(void)
+{
+ sdb_llist_iter_t *iter;
+
+ iter = sdb_llist_get_iter(all_plugins);
+ if (all_plugins && (! iter))
+ return -1;
+
+ while (sdb_llist_iter_has_next(iter)) {
+ ctx_t *ctx = CTX(sdb_llist_iter_get_next(iter));
+ if (ctx->use_cnt)
+ continue;
+
+ sdb_log(SDB_LOG_INFO, "core: Module %s no longer in use",
+ ctx->info.plugin_name);
+ sdb_llist_iter_remove_current(iter);
+ plugin_unregister_by_name(ctx->info.plugin_name);
+ sdb_object_deref(SDB_OBJ(ctx));
+ }
+ sdb_llist_iter_destroy(iter);
+ return 0;
+} /* sdb_plugin_reconfigure_finish */
+
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;
- sdb_plugin_ctx_t old_ctx;
+ 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 = (sdb_plugin_init_cb)cb->cb_callback;
- old_ctx = sdb_plugin_set_ctx(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, "core: Failed to initialize plugin "
+ "'%s'. Unregistering all callbacks.", obj->name);
+ ctx_set(old_ctx);
+ plugin_unregister_by_name(cb->cb_ctx->info.plugin_name);
+ ++ret;
}
- sdb_plugin_set_ctx(old_ctx);
+ else
+ ctx_set(old_ctx);
}
- return 0;
+ sdb_llist_iter_destroy(iter);
+ return ret;
} /* sdb_plugin_init_all */
+int
+sdb_plugin_shutdown_all(void)
+{
+ sdb_llist_iter_t *iter;
+ int ret = 0;
+
+ iter = sdb_llist_get_iter(shutdown_list);
+ while (sdb_llist_iter_has_next(iter)) {
+ sdb_plugin_cb_t *cb;
+ sdb_plugin_shutdown_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_shutdown_cb)cb->cb_callback;
+
+ old_ctx = ctx_set(cb->cb_ctx);
+ if (callback(cb->cb_user_data)) {
+ sdb_log(SDB_LOG_ERR, "core: Failed to shutdown plugin '%s'.",
+ obj->name);
+ ++ret;
+ }
+ ctx_set(old_ctx);
+ }
+ sdb_llist_iter_destroy(iter);
+ return ret;
+} /* sdb_plugin_shutdown_all */
+
int
sdb_plugin_collector_loop(sdb_plugin_loop_t *loop)
{
if (! collector_list) {
- sdb_log(SDB_LOG_WARNING, "plugin: No collectors registered. "
+ sdb_log(SDB_LOG_WARNING, "core: No collectors registered. "
"Quiting main loop.");
return -1;
}
while (loop->do_loop) {
sdb_plugin_collector_cb callback;
- sdb_plugin_ctx_t old_ctx;
+ ctx_t *old_ctx;
sdb_time_t interval, now;
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];
- sdb_log(SDB_LOG_ERR, "plugin: Failed to determine current "
- "time: %s", sdb_strerror(errno, errbuf, sizeof(errbuf)));
+ sdb_log(SDB_LOG_ERR, "core: Failed to determine current "
+ "time in collector main loop: %s",
+ sdb_strerror(errno, errbuf, sizeof(errbuf)));
now = SDB_PLUGIN_CCB(obj)->ccb_next_update;
}
while (loop->do_loop && sdb_sleep(interval, &interval)) {
if (errno != EINTR) {
char errbuf[1024];
- sdb_log(SDB_LOG_ERR, "plugin: Failed to sleep: %s",
+ sdb_log(SDB_LOG_ERR, "core: Failed to sleep "
+ "in collector main loop: %s",
sdb_strerror(errno, errbuf, sizeof(errbuf)));
+ sdb_llist_insert_sorted(collector_list, obj,
+ plugin_cmp_next_update);
+ sdb_object_deref(obj);
return -1;
}
errno = 0;
}
- if (! loop->do_loop)
+ if (! loop->do_loop) {
+ /* put back; don't worry about errors */
+ sdb_llist_insert_sorted(collector_list, obj,
+ plugin_cmp_next_update);
+ sdb_object_deref(obj);
return 0;
+ }
}
- old_ctx = sdb_plugin_set_ctx(SDB_PLUGIN_CCB(obj)->ccb_ctx);
+ old_ctx = ctx_set(SDB_PLUGIN_CCB(obj)->ccb_ctx);
if (callback(SDB_PLUGIN_CCB(obj)->ccb_user_data)) {
/* XXX */
}
- sdb_plugin_set_ctx(old_ctx);
+ ctx_set(old_ctx);
interval = SDB_PLUGIN_CCB(obj)->ccb_interval;
if (! interval)
interval = loop->default_interval;
if (! interval) {
- sdb_log(SDB_LOG_WARNING, "plugin: No interval configured "
+ sdb_log(SDB_LOG_WARNING, "core: No interval configured "
"for plugin '%s'; skipping any further "
- "iterations.", SDB_PLUGIN_CCB(obj)->ccb_name);
+ "iterations.", obj->name);
sdb_object_deref(obj);
continue;
}
if (! (now = sdb_gettime())) {
char errbuf[1024];
- sdb_log(SDB_LOG_ERR, "plugin: Failed to determine current "
- "time: %s", sdb_strerror(errno, errbuf, sizeof(errbuf)));
+ sdb_log(SDB_LOG_ERR, "core: Failed to determine current "
+ "time in collector main loop: %s",
+ sdb_strerror(errno, errbuf, sizeof(errbuf)));
now = SDB_PLUGIN_CCB(obj)->ccb_next_update;
}
if (now > SDB_PLUGIN_CCB(obj)->ccb_next_update) {
- sdb_log(SDB_LOG_WARNING, "plugin: Plugin '%s' took too "
+ sdb_log(SDB_LOG_WARNING, "core: Plugin '%s' took too "
"long; skipping iterations to keep up.",
- SDB_PLUGIN_CCB(obj)->ccb_name);
+ obj->name);
SDB_PLUGIN_CCB(obj)->ccb_next_update = now;
}
if (sdb_llist_insert_sorted(collector_list, obj,
- sdb_plugin_cmp_next_update)) {
- sdb_log(SDB_LOG_ERR, "plugin: Failed to re-insert "
+ plugin_cmp_next_update)) {
+ sdb_log(SDB_LOG_ERR, "core: Failed to re-insert "
"plugin '%s' into collector list. Unable to further "
"use the plugin.",
- SDB_PLUGIN_CCB(obj)->ccb_name);
+ obj->name);
sdb_object_deref(obj);
return -1;
}
return 0;
} /* sdb_plugin_read_loop */
+char *
+sdb_plugin_cname(char *hostname)
+{
+ sdb_llist_iter_t *iter;
+
+ if (! hostname)
+ return NULL;
+
+ if (! cname_list)
+ return hostname;
+
+ iter = sdb_llist_get_iter(cname_list);
+ while (sdb_llist_iter_has_next(iter)) {
+ sdb_plugin_cname_cb callback;
+ char *cname;
+
+ sdb_object_t *obj = sdb_llist_iter_get_next(iter);
+ assert(obj);
+
+ 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);
+ hostname = cname;
+ }
+ /* else: don't change hostname */
+ }
+ sdb_llist_iter_destroy(iter);
+ return hostname;
+} /* sdb_plugin_cname */
+
+int
+sdb_plugin_log(int prio, const char *msg)
+{
+ sdb_llist_iter_t *iter;
+ int ret = -1;
+
+ if (! msg)
+ return 0;
+
+ if (! sdb_llist_len(log_list))
+ return fprintf(stderr, "[%s] %s\n", SDB_LOG_PRIO_TO_STRING(prio), msg);
+
+ iter = sdb_llist_get_iter(log_list);
+ while (sdb_llist_iter_has_next(iter)) {
+ sdb_plugin_log_cb callback;
+ int tmp;
+
+ sdb_object_t *obj = sdb_llist_iter_get_next(iter);
+ assert(obj);
+
+ 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;
+ }
+ sdb_llist_iter_destroy(iter);
+ return ret;
+} /* sdb_plugin_log */
+
+int
+sdb_plugin_vlogf(int prio, const char *fmt, va_list ap)
+{
+ sdb_strbuf_t *buf;
+ int ret;
+
+ if (! fmt)
+ return 0;
+
+ buf = sdb_strbuf_create(64);
+ if (! buf) {
+ ret = fprintf(stderr, "[%s] ", SDB_LOG_PRIO_TO_STRING(prio));
+ ret += vfprintf(stderr, fmt, ap);
+ return ret;
+ }
+
+ if (sdb_strbuf_vsprintf(buf, fmt, ap) < 0) {
+ sdb_strbuf_destroy(buf);
+ return -1;
+ }
+
+ ret = sdb_plugin_log(prio, sdb_strbuf_string(buf));
+ sdb_strbuf_destroy(buf);
+ return ret;
+} /* sdb_plugin_vlogf */
+
+int
+sdb_plugin_logf(int prio, const char *fmt, ...)
+{
+ va_list ap;
+ int ret;
+
+ if (! fmt)
+ return 0;
+
+ va_start(ap, fmt);
+ ret = sdb_plugin_vlogf(prio, fmt, ap);
+ va_end(ap);
+ return ret;
+} /* sdb_plugin_logf */
+
/* vim: set tw=78 sw=4 ts=4 noexpandtab : */