1 /*
2 * SysDB - src/core/plugin.c
3 * Copyright (C) 2012 Sebastian 'tokkee' Harl <sh@tokkee.org>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
19 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
28 #if HAVE_CONFIG_H
29 # include "config.h"
30 #endif /* HAVE_CONFIG_H */
32 #include "sysdb.h"
33 #include "core/plugin.h"
34 #include "core/time.h"
35 #include "utils/error.h"
36 #include "utils/llist.h"
37 #include "utils/strbuf.h"
39 #include <assert.h>
41 #include <errno.h>
43 #include <stdarg.h>
44 #include <stdio.h>
45 #include <string.h>
46 #include <strings.h>
47 #include <unistd.h>
49 #include <ltdl.h>
51 #include <pthread.h>
53 /*
54 * private data types
55 */
57 struct sdb_plugin_info {
58 char *plugin_name;
59 char *filename;
61 /* public attributes */
62 char *name;
64 char *description;
65 char *copyright;
66 char *license;
68 int version;
69 int plugin_version;
70 };
71 #define SDB_PLUGIN_INFO_INIT { \
72 /* plugin_name */ NULL, /* filename */ NULL, \
73 /* name */ NULL, /* desc */ NULL, \
74 /* copyright */ NULL, /* license */ NULL, \
75 /* version */ -1, /* plugin_version */ -1 }
76 #define INFO_GET(i, attr) \
77 ((i)->attr ? (i)->attr : #attr" not set")
79 typedef struct {
80 sdb_object_t super;
81 sdb_plugin_ctx_t public;
83 sdb_plugin_info_t info;
84 } ctx_t;
85 #define CTX_INIT { SDB_OBJECT_INIT, \
86 SDB_PLUGIN_CTX_INIT, SDB_PLUGIN_INFO_INIT }
88 #define CTX(obj) ((ctx_t *)(obj))
90 typedef struct {
91 sdb_object_t super;
92 void *cb_callback;
93 sdb_object_t *cb_user_data;
94 ctx_t *cb_ctx;
95 } sdb_plugin_cb_t;
96 #define SDB_PLUGIN_CB_INIT { SDB_OBJECT_INIT, \
97 /* callback = */ NULL, /* user_data = */ NULL, \
98 SDB_PLUGIN_CTX_INIT }
100 typedef struct {
101 sdb_plugin_cb_t super;
102 #define ccb_callback super.cb_callback
103 #define ccb_user_data super.cb_user_data
104 #define ccb_ctx super.cb_ctx
105 sdb_time_t ccb_interval;
106 sdb_time_t ccb_next_update;
107 } sdb_plugin_collector_cb_t;
109 #define SDB_PLUGIN_CB(obj) ((sdb_plugin_cb_t *)(obj))
110 #define SDB_CONST_PLUGIN_CB(obj) ((const sdb_plugin_cb_t *)(obj))
111 #define SDB_PLUGIN_CCB(obj) ((sdb_plugin_collector_cb_t *)(obj))
112 #define SDB_CONST_PLUGIN_CCB(obj) ((const sdb_plugin_collector_cb_t *)(obj))
114 /*
115 * private variables
116 */
118 static sdb_plugin_ctx_t plugin_default_ctx = SDB_PLUGIN_CTX_INIT;
119 static sdb_plugin_info_t plugin_default_info = SDB_PLUGIN_INFO_INIT;
121 static pthread_key_t plugin_ctx_key;
122 static _Bool plugin_ctx_key_initialized = 0;
124 /* a list of the plugin contexts of all registered plugins */
125 static sdb_llist_t *all_plugins = NULL;
127 static sdb_llist_t *config_list = NULL;
128 static sdb_llist_t *init_list = NULL;
129 static sdb_llist_t *collector_list = NULL;
130 static sdb_llist_t *cname_list = NULL;
131 static sdb_llist_t *shutdown_list = NULL;
132 static sdb_llist_t *log_list = NULL;
134 /*
135 * private helper functions
136 */
138 static void
139 plugin_info_clear(sdb_plugin_info_t *info)
140 {
141 sdb_plugin_info_t empty_info = SDB_PLUGIN_INFO_INIT;
142 if (! info)
143 return;
145 if (info->plugin_name)
146 free(info->plugin_name);
147 if (info->filename)
148 free(info->filename);
150 if (info->name)
151 free(info->name);
152 if (info->description)
153 free(info->description);
154 if (info->copyright)
155 free(info->copyright);
156 if (info->license)
157 free(info->license);
159 *info = empty_info;
160 } /* plugin_info_clear */
162 static void
163 ctx_key_init(void)
164 {
165 if (plugin_ctx_key_initialized)
166 return;
168 pthread_key_create(&plugin_ctx_key, /* destructor */ NULL);
169 plugin_ctx_key_initialized = 1;
170 } /* ctx_key_init */
172 static int
173 plugin_cmp_next_update(const sdb_object_t *a, const sdb_object_t *b)
174 {
175 const sdb_plugin_collector_cb_t *ccb1
176 = (const sdb_plugin_collector_cb_t *)a;
177 const sdb_plugin_collector_cb_t *ccb2
178 = (const sdb_plugin_collector_cb_t *)b;
180 assert(ccb1 && ccb2);
182 return (ccb1->ccb_next_update > ccb2->ccb_next_update)
183 ? 1 : (ccb1->ccb_next_update < ccb2->ccb_next_update)
184 ? -1 : 0;
185 } /* plugin_cmp_next_update */
187 static int
188 plugin_lookup_by_name(const sdb_object_t *obj, const void *id)
189 {
190 const sdb_plugin_cb_t *cb = SDB_CONST_PLUGIN_CB(obj);
191 const char *name = id;
193 assert(cb && id && cb->cb_ctx);
194 if (!strcasecmp(cb->cb_ctx->info.plugin_name, name))
195 return 0;
196 return 1;
197 } /* plugin_lookup_by_name */
199 static void
200 plugin_unregister_by_name(const char *plugin_name)
201 {
202 size_t i;
204 struct {
205 const char *type;
206 sdb_llist_t *list;
207 } all_lists[] = {
208 { "config", config_list },
209 { "init", init_list },
210 { "collector", collector_list },
211 { "cname", cname_list },
212 { "shutdown", shutdown_list },
213 { "log", log_list },
214 };
216 for (i = 0; i < SDB_STATIC_ARRAY_LEN(all_lists); ++i) {
217 const char *type = all_lists[i].type;
218 sdb_llist_t *list = all_lists[i].list;
220 while (1) {
221 sdb_object_t *obj = sdb_llist_remove(list,
222 plugin_lookup_by_name, plugin_name);
223 sdb_plugin_cb_t *cb = SDB_PLUGIN_CB(obj);
225 if (! obj)
226 break;
228 sdb_log(SDB_LOG_INFO, "core: Unregistering "
229 "%s callback '%s' (module %s)", type, obj->name,
230 cb->cb_ctx->info.plugin_name);
231 sdb_object_deref(obj);
232 }
233 }
234 } /* plugin_unregister_by_name */
236 /*
237 * private types
238 */
240 static int
241 ctx_init(sdb_object_t *obj, va_list __attribute__((unused)) ap)
242 {
243 ctx_t *ctx = CTX(obj);
245 assert(ctx);
247 ctx->public = plugin_default_ctx;
248 ctx->info = plugin_default_info;
249 return 0;
250 } /* ctx_init */
252 static void
253 ctx_destroy(sdb_object_t *obj)
254 {
255 ctx_t *ctx = CTX(obj);
256 plugin_info_clear(&ctx->info);
257 } /* ctx_destroy */
259 static sdb_type_t ctx_type = {
260 sizeof(ctx_t),
262 ctx_init,
263 ctx_destroy
264 };
266 static ctx_t *
267 ctx_create(const char *name)
268 {
269 ctx_t *ctx;
271 ctx = CTX(sdb_object_create(name, ctx_type));
272 if (! ctx)
273 return NULL;
275 if (! plugin_ctx_key_initialized)
276 ctx_key_init();
277 pthread_setspecific(plugin_ctx_key, ctx);
278 return ctx;
279 } /* ctx_create */
281 static ctx_t *
282 ctx_get(void)
283 {
284 if (! plugin_ctx_key_initialized)
285 ctx_key_init();
286 return pthread_getspecific(plugin_ctx_key);
287 } /* ctx_get */
289 static ctx_t *
290 ctx_set(ctx_t *new)
291 {
292 ctx_t *old;
294 if (! plugin_ctx_key_initialized)
295 ctx_key_init();
297 old = pthread_getspecific(plugin_ctx_key);
298 pthread_setspecific(plugin_ctx_key, new);
299 return old;
300 } /* ctx_set */
302 static int
303 plugin_cb_init(sdb_object_t *obj, va_list ap)
304 {
305 sdb_llist_t **list = va_arg(ap, sdb_llist_t **);
306 const char *type = va_arg(ap, const char *);
307 void *callback = va_arg(ap, void *);
308 sdb_object_t *ud = va_arg(ap, sdb_object_t *);
310 assert(list);
311 assert(type);
312 assert(obj);
314 if (sdb_llist_search_by_name(*list, obj->name)) {
315 sdb_log(SDB_LOG_WARNING, "core: %s callback '%s' "
316 "has already been registered. Ignoring newly "
317 "registered version.", type, obj->name);
318 return -1;
319 }
321 SDB_PLUGIN_CB(obj)->cb_callback = callback;
322 SDB_PLUGIN_CB(obj)->cb_ctx = ctx_get();
323 sdb_object_ref(SDB_OBJ(SDB_PLUGIN_CB(obj)->cb_ctx));
325 sdb_object_ref(ud);
326 SDB_PLUGIN_CB(obj)->cb_user_data = ud;
327 return 0;
328 } /* plugin_cb_init */
330 static void
331 plugin_cb_destroy(sdb_object_t *obj)
332 {
333 assert(obj);
334 sdb_object_deref(SDB_PLUGIN_CB(obj)->cb_user_data);
335 sdb_object_deref(SDB_OBJ(SDB_PLUGIN_CB(obj)->cb_ctx));
336 } /* plugin_cb_destroy */
338 static sdb_type_t sdb_plugin_cb_type = {
339 sizeof(sdb_plugin_cb_t),
341 plugin_cb_init,
342 plugin_cb_destroy
343 };
345 static sdb_type_t sdb_plugin_collector_cb_type = {
346 sizeof(sdb_plugin_collector_cb_t),
348 plugin_cb_init,
349 plugin_cb_destroy
350 };
352 static int
353 plugin_add_callback(sdb_llist_t **list, const char *type,
354 const char *name, void *callback, sdb_object_t *user_data)
355 {
356 sdb_object_t *obj;
358 if ((! name) || (! callback))
359 return -1;
361 assert(list);
363 if (! *list)
364 *list = sdb_llist_create();
365 if (! *list)
366 return -1;
368 obj = sdb_object_create(name, sdb_plugin_cb_type,
369 list, type, callback, user_data);
370 if (! obj)
371 return -1;
373 if (sdb_llist_append(*list, obj)) {
374 sdb_object_deref(obj);
375 return -1;
376 }
378 /* pass control to the list */
379 sdb_object_deref(obj);
381 sdb_log(SDB_LOG_INFO, "core: Registered %s callback '%s'.",
382 type, name);
383 return 0;
384 } /* plugin_add_callback */
386 /*
387 * public API
388 */
390 int
391 sdb_plugin_load(const char *name, const sdb_plugin_ctx_t *plugin_ctx)
392 {
393 char real_name[name ? strlen(name) + 1 : 1];
394 const char *name_ptr;
395 char *tmp;
397 char filename[1024];
398 ctx_t *ctx;
400 lt_dlhandle lh;
402 int (*mod_init)(sdb_plugin_info_t *);
403 int status;
405 if ((! name) || (! *name))
406 return -1;
408 real_name[0] = '\0';
409 name_ptr = name;
411 while ((tmp = strstr(name_ptr, "::"))) {
412 strncat(real_name, name_ptr, (size_t)(tmp - name_ptr));
413 strcat(real_name, "/");
414 name_ptr = tmp + strlen("::");
415 }
416 strcat(real_name, name_ptr);
418 snprintf(filename, sizeof(filename), "%s/%s.so",
419 PKGLIBDIR, real_name);
420 filename[sizeof(filename) - 1] = '\0';
422 if (access(filename, R_OK)) {
423 char errbuf[1024];
424 sdb_log(SDB_LOG_ERR, "core: Failed to load plugin '%s' (%s): %s",
425 name, filename, sdb_strerror(errno, errbuf, sizeof(errbuf)));
426 return -1;
427 }
429 lt_dlinit();
430 lt_dlerror();
432 lh = lt_dlopen(filename);
433 if (! lh) {
434 sdb_log(SDB_LOG_ERR, "core: Failed to load plugin '%s': %s"
435 "The most common cause for this problem are missing "
436 "dependencies.\n", name, lt_dlerror());
437 return -1;
438 }
440 if (ctx_get())
441 sdb_log(SDB_LOG_WARNING, "core: Discarding old plugin context");
443 ctx = ctx_create(real_name);
444 if (! ctx) {
445 sdb_log(SDB_LOG_ERR, "core: Failed to initialize plugin context");
446 return -1;
447 }
449 ctx->info.plugin_name = strdup(name);
450 ctx->info.filename = strdup(filename);
452 if (plugin_ctx)
453 ctx->public = *plugin_ctx;
455 mod_init = (int (*)(sdb_plugin_info_t *))lt_dlsym(lh, "sdb_module_init");
456 if (! mod_init) {
457 sdb_log(SDB_LOG_ERR, "core: Failed to load plugin '%s': "
458 "could not find symbol 'sdb_module_init'", name);
459 sdb_object_deref(SDB_OBJ(ctx));
460 return -1;
461 }
463 status = mod_init(&ctx->info);
464 if (status) {
465 sdb_log(SDB_LOG_ERR, "core: Failed to initialize "
466 "module '%s'", name);
467 plugin_unregister_by_name(ctx->info.plugin_name);
468 sdb_object_deref(SDB_OBJ(ctx));
469 return -1;
470 }
472 /* compare minor version */
473 if ((ctx->info.version < 0)
474 || ((int)(ctx->info.version / 100) != (int)(SDB_VERSION / 100)))
475 sdb_log(SDB_LOG_WARNING, "core: WARNING: version of "
476 "plugin '%s' (%i.%i.%i) does not match our version "
477 "(%i.%i.%i); this might cause problems",
478 name, SDB_VERSION_DECODE(ctx->info.version),
479 SDB_VERSION_DECODE(SDB_VERSION));
481 if (! all_plugins) {
482 if (! (all_plugins = sdb_llist_create())) {
483 sdb_log(SDB_LOG_ERR, "core: Failed to load plugin '%s': "
484 "internal error while creating linked list", name);
485 plugin_unregister_by_name(ctx->info.plugin_name);
486 sdb_object_deref(SDB_OBJ(ctx));
487 return -1;
488 }
489 }
491 sdb_llist_append(all_plugins, SDB_OBJ(ctx));
493 sdb_log(SDB_LOG_INFO, "core: Successfully loaded "
494 "plugin '%s' v%i (%s)\n\t%s\n\tLicense: %s",
495 INFO_GET(&ctx->info, name), ctx->info.plugin_version,
496 INFO_GET(&ctx->info, description),
497 INFO_GET(&ctx->info, copyright),
498 INFO_GET(&ctx->info, license));
500 /* any registered callbacks took ownership of the context */
501 sdb_object_deref(SDB_OBJ(ctx));
503 /* reset */
504 ctx_set(NULL);
505 return 0;
506 } /* sdb_plugin_load */
508 int
509 sdb_plugin_set_info(sdb_plugin_info_t *info, int type, ...)
510 {
511 va_list ap;
513 if (! info)
514 return -1;
516 va_start(ap, type);
518 switch (type) {
519 case SDB_PLUGIN_INFO_NAME:
520 {
521 char *name = va_arg(ap, char *);
522 if (name) {
523 if (info->name)
524 free(info->name);
525 info->name = strdup(name);
526 }
527 }
528 break;
529 case SDB_PLUGIN_INFO_DESC:
530 {
531 char *desc = va_arg(ap, char *);
532 if (desc) {
533 if (info->description)
534 free(info->description);
535 info->description = strdup(desc);
536 }
537 }
538 break;
539 case SDB_PLUGIN_INFO_COPYRIGHT:
540 {
541 char *copyright = va_arg(ap, char *);
542 if (copyright)
543 info->copyright = strdup(copyright);
544 }
545 break;
546 case SDB_PLUGIN_INFO_LICENSE:
547 {
548 char *license = va_arg(ap, char *);
549 if (license) {
550 if (info->license)
551 free(info->license);
552 info->license = strdup(license);
553 }
554 }
555 break;
556 case SDB_PLUGIN_INFO_VERSION:
557 {
558 int version = va_arg(ap, int);
559 info->version = version;
560 }
561 break;
562 case SDB_PLUGIN_INFO_PLUGIN_VERSION:
563 {
564 int version = va_arg(ap, int);
565 info->plugin_version = version;
566 }
567 break;
568 default:
569 va_end(ap);
570 return -1;
571 }
573 va_end(ap);
574 return 0;
575 } /* sdb_plugin_set_info */
577 int
578 sdb_plugin_register_config(const char *name, sdb_plugin_config_cb callback)
579 {
580 return plugin_add_callback(&config_list, "init", name,
581 (void *)callback, NULL);
582 } /* sdb_plugin_register_config */
584 int
585 sdb_plugin_register_init(const char *name, sdb_plugin_init_cb callback,
586 sdb_object_t *user_data)
587 {
588 return plugin_add_callback(&init_list, "init", name,
589 (void *)callback, user_data);
590 } /* sdb_plugin_register_init */
592 int
593 sdb_plugin_register_shutdown(const char *name, sdb_plugin_shutdown_cb callback,
594 sdb_object_t *user_data)
595 {
596 return plugin_add_callback(&shutdown_list, "shutdown", name,
597 (void *)callback, user_data);
598 } /* sdb_plugin_register_shutdown */
600 int
601 sdb_plugin_register_log(const char *name, sdb_plugin_log_cb callback,
602 sdb_object_t *user_data)
603 {
604 return plugin_add_callback(&log_list, "log", name, (void *)callback,
605 user_data);
606 } /* sdb_plugin_register_log */
608 int
609 sdb_plugin_register_cname(const char *name, sdb_plugin_cname_cb callback,
610 sdb_object_t *user_data)
611 {
612 return plugin_add_callback(&cname_list, "cname", name, (void *)callback,
613 user_data);
614 } /* sdb_plugin_register_cname */
616 int
617 sdb_plugin_register_collector(const char *name, sdb_plugin_collector_cb callback,
618 const sdb_time_t *interval, sdb_object_t *user_data)
619 {
620 sdb_object_t *obj;
622 if ((! name) || (! callback))
623 return -1;
625 if (! collector_list)
626 collector_list = sdb_llist_create();
627 if (! collector_list)
628 return -1;
630 obj = sdb_object_create(name, sdb_plugin_collector_cb_type,
631 &collector_list, "collector", callback, user_data);
632 if (! obj)
633 return -1;
635 if (interval)
636 SDB_PLUGIN_CCB(obj)->ccb_interval = *interval;
637 else {
638 sdb_time_t tmp = sdb_plugin_get_ctx().interval;
640 if (tmp > 0)
641 SDB_PLUGIN_CCB(obj)->ccb_interval = tmp;
642 else
643 SDB_PLUGIN_CCB(obj)->ccb_interval = 0;
644 }
646 if (! (SDB_PLUGIN_CCB(obj)->ccb_next_update = sdb_gettime())) {
647 char errbuf[1024];
648 sdb_log(SDB_LOG_ERR, "core: Failed to determine current "
649 "time: %s", sdb_strerror(errno, errbuf, sizeof(errbuf)));
650 sdb_object_deref(obj);
651 return -1;
652 }
654 if (sdb_llist_insert_sorted(collector_list, obj,
655 plugin_cmp_next_update)) {
656 sdb_object_deref(obj);
657 return -1;
658 }
660 /* pass control to the list */
661 sdb_object_deref(obj);
663 sdb_log(SDB_LOG_INFO, "core: Registered collector callback '%s' "
664 "(interval = %.3fs).", name,
665 SDB_TIME_TO_DOUBLE(SDB_PLUGIN_CCB(obj)->ccb_interval));
666 return 0;
667 } /* sdb_plugin_register_collector */
669 sdb_plugin_ctx_t
670 sdb_plugin_get_ctx(void)
671 {
672 ctx_t *c;
674 c = ctx_get();
675 if (! c) {
676 sdb_plugin_log(SDB_LOG_ERR, "core: Invalid read access to plugin "
677 "context outside a plugin");
678 return plugin_default_ctx;
679 }
680 return c->public;
681 } /* sdb_plugin_get_ctx */
683 int
684 sdb_plugin_set_ctx(sdb_plugin_ctx_t ctx, sdb_plugin_ctx_t *old)
685 {
686 ctx_t *c;
688 c = ctx_get();
689 if (! c) {
690 sdb_plugin_log(SDB_LOG_ERR, "core: Invalid write access to plugin "
691 "context outside a plugin");
692 return -1;
693 }
695 if (old)
696 *old = c->public;
697 c->public = ctx;
698 return 0;
699 } /* sdb_plugin_set_ctx */
701 int
702 sdb_plugin_configure(const char *name, oconfig_item_t *ci)
703 {
704 sdb_plugin_cb_t *plugin;
705 sdb_plugin_config_cb callback;
707 ctx_t *old_ctx;
709 int status;
711 if ((! name) || (! ci))
712 return -1;
714 plugin = SDB_PLUGIN_CB(sdb_llist_search_by_name(config_list, name));
715 if (! plugin) {
716 /* XXX: check if any such plugin has been loaded */
717 ctx_t *ctx = CTX(sdb_llist_search_by_name(all_plugins, name));
718 if (! ctx)
719 sdb_log(SDB_LOG_ERR, "core: Plugin '%s' not loaded.", name);
720 else
721 sdb_log(SDB_LOG_ERR, "core: Plugin '%s' did not register "
722 "a config callback.", name);
723 errno = ENOENT;
724 return -1;
725 }
727 old_ctx = ctx_set(plugin->cb_ctx);
728 callback = (sdb_plugin_config_cb)plugin->cb_callback;
729 status = callback(ci);
730 ctx_set(old_ctx);
731 return status;
732 } /* sdb_plugin_configure */
734 int
735 sdb_plugin_init_all(void)
736 {
737 sdb_llist_iter_t *iter;
738 int ret = 0;
740 iter = sdb_llist_get_iter(init_list);
741 while (sdb_llist_iter_has_next(iter)) {
742 sdb_plugin_cb_t *cb;
743 sdb_plugin_init_cb callback;
744 ctx_t *old_ctx;
746 sdb_object_t *obj = sdb_llist_iter_get_next(iter);
747 assert(obj);
748 cb = SDB_PLUGIN_CB(obj);
750 callback = (sdb_plugin_init_cb)cb->cb_callback;
752 old_ctx = ctx_set(cb->cb_ctx);
753 if (callback(cb->cb_user_data)) {
754 sdb_log(SDB_LOG_ERR, "core: Failed to initialize plugin "
755 "'%s'. Unregistering all callbacks.", obj->name);
756 plugin_unregister_by_name(cb->cb_ctx->info.plugin_name);
757 ++ret;
758 }
759 ctx_set(old_ctx);
760 }
761 sdb_llist_iter_destroy(iter);
762 return ret;
763 } /* sdb_plugin_init_all */
765 int
766 sdb_plugin_collector_loop(sdb_plugin_loop_t *loop)
767 {
768 if (! collector_list) {
769 sdb_log(SDB_LOG_WARNING, "core: No collectors registered. "
770 "Quiting main loop.");
771 return -1;
772 }
774 if (! loop)
775 return -1;
777 while (loop->do_loop) {
778 sdb_plugin_collector_cb callback;
779 ctx_t *old_ctx;
781 sdb_time_t interval, now;
783 sdb_object_t *obj = sdb_llist_shift(collector_list);
784 if (! obj)
785 return -1;
787 callback = (sdb_plugin_collector_cb)SDB_PLUGIN_CCB(obj)->ccb_callback;
789 if (! (now = sdb_gettime())) {
790 char errbuf[1024];
791 sdb_log(SDB_LOG_ERR, "core: Failed to determine current "
792 "time in collector main loop: %s",
793 sdb_strerror(errno, errbuf, sizeof(errbuf)));
794 now = SDB_PLUGIN_CCB(obj)->ccb_next_update;
795 }
797 if (now < SDB_PLUGIN_CCB(obj)->ccb_next_update) {
798 interval = SDB_PLUGIN_CCB(obj)->ccb_next_update - now;
800 errno = 0;
801 while (loop->do_loop && sdb_sleep(interval, &interval)) {
802 if (errno != EINTR) {
803 char errbuf[1024];
804 sdb_log(SDB_LOG_ERR, "core: Failed to sleep "
805 "in collector main loop: %s",
806 sdb_strerror(errno, errbuf, sizeof(errbuf)));
807 return -1;
808 }
809 errno = 0;
810 }
812 if (! loop->do_loop)
813 return 0;
814 }
816 old_ctx = ctx_set(SDB_PLUGIN_CCB(obj)->ccb_ctx);
817 if (callback(SDB_PLUGIN_CCB(obj)->ccb_user_data)) {
818 /* XXX */
819 }
820 ctx_set(old_ctx);
822 interval = SDB_PLUGIN_CCB(obj)->ccb_interval;
823 if (! interval)
824 interval = loop->default_interval;
825 if (! interval) {
826 sdb_log(SDB_LOG_WARNING, "core: No interval configured "
827 "for plugin '%s'; skipping any further "
828 "iterations.", obj->name);
829 sdb_object_deref(obj);
830 continue;
831 }
833 SDB_PLUGIN_CCB(obj)->ccb_next_update += interval;
835 if (! (now = sdb_gettime())) {
836 char errbuf[1024];
837 sdb_log(SDB_LOG_ERR, "core: Failed to determine current "
838 "time in collector main loop: %s",
839 sdb_strerror(errno, errbuf, sizeof(errbuf)));
840 now = SDB_PLUGIN_CCB(obj)->ccb_next_update;
841 }
843 if (now > SDB_PLUGIN_CCB(obj)->ccb_next_update) {
844 sdb_log(SDB_LOG_WARNING, "core: Plugin '%s' took too "
845 "long; skipping iterations to keep up.",
846 obj->name);
847 SDB_PLUGIN_CCB(obj)->ccb_next_update = now;
848 }
850 if (sdb_llist_insert_sorted(collector_list, obj,
851 plugin_cmp_next_update)) {
852 sdb_log(SDB_LOG_ERR, "core: Failed to re-insert "
853 "plugin '%s' into collector list. Unable to further "
854 "use the plugin.",
855 obj->name);
856 sdb_object_deref(obj);
857 return -1;
858 }
860 /* pass control back to the list */
861 sdb_object_deref(obj);
862 }
863 return 0;
864 } /* sdb_plugin_read_loop */
866 char *
867 sdb_plugin_cname(char *hostname)
868 {
869 sdb_llist_iter_t *iter;
871 if (! hostname)
872 return NULL;
874 if (! cname_list)
875 return hostname;
877 iter = sdb_llist_get_iter(cname_list);
878 while (sdb_llist_iter_has_next(iter)) {
879 sdb_plugin_cname_cb callback;
880 char *cname;
882 sdb_object_t *obj = sdb_llist_iter_get_next(iter);
883 assert(obj);
885 callback = (sdb_plugin_cname_cb)SDB_PLUGIN_CB(obj)->cb_callback;
886 cname = callback(hostname, SDB_PLUGIN_CB(obj)->cb_user_data);
887 if (cname) {
888 free(hostname);
889 hostname = cname;
890 }
891 /* else: don't change hostname */
892 }
893 sdb_llist_iter_destroy(iter);
894 return hostname;
895 } /* sdb_plugin_cname */
897 int
898 sdb_plugin_log(int prio, const char *msg)
899 {
900 sdb_llist_iter_t *iter;
901 int ret = -1;
903 if (! msg)
904 return 0;
906 if (! log_list)
907 return fprintf(stderr, "[%s] %s\n", SDB_LOG_PRIO_TO_STRING(prio), msg);
909 iter = sdb_llist_get_iter(log_list);
910 while (sdb_llist_iter_has_next(iter)) {
911 sdb_plugin_log_cb callback;
912 int tmp;
914 sdb_object_t *obj = sdb_llist_iter_get_next(iter);
915 assert(obj);
917 callback = (sdb_plugin_log_cb)SDB_PLUGIN_CB(obj)->cb_callback;
918 tmp = callback(prio, msg, SDB_PLUGIN_CB(obj)->cb_user_data);
919 if (tmp > ret)
920 ret = tmp;
921 }
922 sdb_llist_iter_destroy(iter);
923 return ret;
924 } /* sdb_plugin_log */
926 int
927 sdb_plugin_vlogf(int prio, const char *fmt, va_list ap)
928 {
929 sdb_strbuf_t *buf;
930 int ret;
932 if (! fmt)
933 return 0;
935 buf = sdb_strbuf_create(64);
936 if (! buf) {
937 ret = fprintf(stderr, "[%s] ", SDB_LOG_PRIO_TO_STRING(prio));
938 ret += vfprintf(stderr, fmt, ap);
939 return ret;
940 }
942 if (sdb_strbuf_vsprintf(buf, fmt, ap) < 0) {
943 sdb_strbuf_destroy(buf);
944 return -1;
945 }
947 ret = sdb_plugin_log(prio, sdb_strbuf_string(buf));
948 sdb_strbuf_destroy(buf);
949 return ret;
950 } /* sdb_plugin_vlogf */
952 int
953 sdb_plugin_logf(int prio, const char *fmt, ...)
954 {
955 va_list ap;
956 int ret;
958 if (! fmt)
959 return 0;
961 va_start(ap, fmt);
962 ret = sdb_plugin_vlogf(prio, fmt, ap);
963 va_end(ap);
964 return ret;
965 } /* sdb_plugin_logf */
967 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */