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 ctx_t *ctx = CTX(sdb_llist_search_by_name(all_plugins, name));
717 if (! ctx)
718 sdb_log(SDB_LOG_ERR, "core: Plugin '%s' not loaded.", name);
719 else
720 sdb_log(SDB_LOG_ERR, "core: Plugin '%s' did not register "
721 "a config callback.", name);
722 errno = ENOENT;
723 return -1;
724 }
726 old_ctx = ctx_set(plugin->cb_ctx);
727 callback = (sdb_plugin_config_cb)plugin->cb_callback;
728 status = callback(ci);
729 ctx_set(old_ctx);
730 return status;
731 } /* sdb_plugin_configure */
733 int
734 sdb_plugin_init_all(void)
735 {
736 sdb_llist_iter_t *iter;
737 int ret = 0;
739 iter = sdb_llist_get_iter(init_list);
740 while (sdb_llist_iter_has_next(iter)) {
741 sdb_plugin_cb_t *cb;
742 sdb_plugin_init_cb callback;
743 ctx_t *old_ctx;
745 sdb_object_t *obj = sdb_llist_iter_get_next(iter);
746 assert(obj);
747 cb = SDB_PLUGIN_CB(obj);
749 callback = (sdb_plugin_init_cb)cb->cb_callback;
751 old_ctx = ctx_set(cb->cb_ctx);
752 if (callback(cb->cb_user_data)) {
753 sdb_log(SDB_LOG_ERR, "core: Failed to initialize plugin "
754 "'%s'. Unregistering all callbacks.", obj->name);
755 plugin_unregister_by_name(cb->cb_ctx->info.plugin_name);
756 ++ret;
757 }
758 ctx_set(old_ctx);
759 }
760 sdb_llist_iter_destroy(iter);
761 return ret;
762 } /* sdb_plugin_init_all */
764 int
765 sdb_plugin_collector_loop(sdb_plugin_loop_t *loop)
766 {
767 if (! collector_list) {
768 sdb_log(SDB_LOG_WARNING, "core: No collectors registered. "
769 "Quiting main loop.");
770 return -1;
771 }
773 if (! loop)
774 return -1;
776 while (loop->do_loop) {
777 sdb_plugin_collector_cb callback;
778 ctx_t *old_ctx;
780 sdb_time_t interval, now;
782 sdb_object_t *obj = sdb_llist_shift(collector_list);
783 if (! obj)
784 return -1;
786 callback = (sdb_plugin_collector_cb)SDB_PLUGIN_CCB(obj)->ccb_callback;
788 if (! (now = sdb_gettime())) {
789 char errbuf[1024];
790 sdb_log(SDB_LOG_ERR, "core: Failed to determine current "
791 "time in collector main loop: %s",
792 sdb_strerror(errno, errbuf, sizeof(errbuf)));
793 now = SDB_PLUGIN_CCB(obj)->ccb_next_update;
794 }
796 if (now < SDB_PLUGIN_CCB(obj)->ccb_next_update) {
797 interval = SDB_PLUGIN_CCB(obj)->ccb_next_update - now;
799 errno = 0;
800 while (loop->do_loop && sdb_sleep(interval, &interval)) {
801 if (errno != EINTR) {
802 char errbuf[1024];
803 sdb_log(SDB_LOG_ERR, "core: Failed to sleep "
804 "in collector main loop: %s",
805 sdb_strerror(errno, errbuf, sizeof(errbuf)));
806 return -1;
807 }
808 errno = 0;
809 }
811 if (! loop->do_loop)
812 return 0;
813 }
815 old_ctx = ctx_set(SDB_PLUGIN_CCB(obj)->ccb_ctx);
816 if (callback(SDB_PLUGIN_CCB(obj)->ccb_user_data)) {
817 /* XXX */
818 }
819 ctx_set(old_ctx);
821 interval = SDB_PLUGIN_CCB(obj)->ccb_interval;
822 if (! interval)
823 interval = loop->default_interval;
824 if (! interval) {
825 sdb_log(SDB_LOG_WARNING, "core: No interval configured "
826 "for plugin '%s'; skipping any further "
827 "iterations.", obj->name);
828 sdb_object_deref(obj);
829 continue;
830 }
832 SDB_PLUGIN_CCB(obj)->ccb_next_update += interval;
834 if (! (now = sdb_gettime())) {
835 char errbuf[1024];
836 sdb_log(SDB_LOG_ERR, "core: Failed to determine current "
837 "time in collector main loop: %s",
838 sdb_strerror(errno, errbuf, sizeof(errbuf)));
839 now = SDB_PLUGIN_CCB(obj)->ccb_next_update;
840 }
842 if (now > SDB_PLUGIN_CCB(obj)->ccb_next_update) {
843 sdb_log(SDB_LOG_WARNING, "core: Plugin '%s' took too "
844 "long; skipping iterations to keep up.",
845 obj->name);
846 SDB_PLUGIN_CCB(obj)->ccb_next_update = now;
847 }
849 if (sdb_llist_insert_sorted(collector_list, obj,
850 plugin_cmp_next_update)) {
851 sdb_log(SDB_LOG_ERR, "core: Failed to re-insert "
852 "plugin '%s' into collector list. Unable to further "
853 "use the plugin.",
854 obj->name);
855 sdb_object_deref(obj);
856 return -1;
857 }
859 /* pass control back to the list */
860 sdb_object_deref(obj);
861 }
862 return 0;
863 } /* sdb_plugin_read_loop */
865 char *
866 sdb_plugin_cname(char *hostname)
867 {
868 sdb_llist_iter_t *iter;
870 if (! hostname)
871 return NULL;
873 if (! cname_list)
874 return hostname;
876 iter = sdb_llist_get_iter(cname_list);
877 while (sdb_llist_iter_has_next(iter)) {
878 sdb_plugin_cname_cb callback;
879 char *cname;
881 sdb_object_t *obj = sdb_llist_iter_get_next(iter);
882 assert(obj);
884 callback = (sdb_plugin_cname_cb)SDB_PLUGIN_CB(obj)->cb_callback;
885 cname = callback(hostname, SDB_PLUGIN_CB(obj)->cb_user_data);
886 if (cname) {
887 free(hostname);
888 hostname = cname;
889 }
890 /* else: don't change hostname */
891 }
892 sdb_llist_iter_destroy(iter);
893 return hostname;
894 } /* sdb_plugin_cname */
896 int
897 sdb_plugin_log(int prio, const char *msg)
898 {
899 sdb_llist_iter_t *iter;
900 int ret = -1;
902 if (! msg)
903 return 0;
905 if (! log_list)
906 return fprintf(stderr, "[%s] %s\n", SDB_LOG_PRIO_TO_STRING(prio), msg);
908 iter = sdb_llist_get_iter(log_list);
909 while (sdb_llist_iter_has_next(iter)) {
910 sdb_plugin_log_cb callback;
911 int tmp;
913 sdb_object_t *obj = sdb_llist_iter_get_next(iter);
914 assert(obj);
916 callback = (sdb_plugin_log_cb)SDB_PLUGIN_CB(obj)->cb_callback;
917 tmp = callback(prio, msg, SDB_PLUGIN_CB(obj)->cb_user_data);
918 if (tmp > ret)
919 ret = tmp;
920 }
921 sdb_llist_iter_destroy(iter);
922 return ret;
923 } /* sdb_plugin_log */
925 int
926 sdb_plugin_vlogf(int prio, const char *fmt, va_list ap)
927 {
928 sdb_strbuf_t *buf;
929 int ret;
931 if (! fmt)
932 return 0;
934 buf = sdb_strbuf_create(64);
935 if (! buf) {
936 ret = fprintf(stderr, "[%s] ", SDB_LOG_PRIO_TO_STRING(prio));
937 ret += vfprintf(stderr, fmt, ap);
938 return ret;
939 }
941 if (sdb_strbuf_vsprintf(buf, fmt, ap) < 0) {
942 sdb_strbuf_destroy(buf);
943 return -1;
944 }
946 ret = sdb_plugin_log(prio, sdb_strbuf_string(buf));
947 sdb_strbuf_destroy(buf);
948 return ret;
949 } /* sdb_plugin_vlogf */
951 int
952 sdb_plugin_logf(int prio, const char *fmt, ...)
953 {
954 va_list ap;
955 int ret;
957 if (! fmt)
958 return 0;
960 va_start(ap, fmt);
961 ret = sdb_plugin_vlogf(prio, fmt, ap);
962 va_end(ap);
963 return ret;
964 } /* sdb_plugin_logf */
966 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */