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 #include "sysdb.h"
29 #include "core/plugin.h"
30 #include "core/time.h"
31 #include "utils/error.h"
32 #include "utils/llist.h"
33 #include "utils/strbuf.h"
35 #include <assert.h>
37 #include <errno.h>
39 #include <stdarg.h>
40 #include <stdio.h>
41 #include <string.h>
42 #include <strings.h>
43 #include <unistd.h>
45 #include <ltdl.h>
47 #include <pthread.h>
49 /*
50 * private data types
51 */
53 struct sdb_plugin_info {
54 char *plugin_name;
55 char *filename;
57 /* public attributes */
58 char *name;
60 char *description;
61 char *copyright;
62 char *license;
64 int version;
65 int plugin_version;
66 };
67 #define SDB_PLUGIN_INFO_INIT { \
68 /* plugin_name */ NULL, /* filename */ NULL, \
69 /* name */ NULL, /* desc */ NULL, \
70 /* copyright */ NULL, /* license */ NULL, \
71 /* version */ -1, /* plugin_version */ -1 }
72 #define INFO_GET(i, attr) \
73 ((i)->attr ? (i)->attr : #attr" not set")
75 typedef struct {
76 sdb_object_t super;
77 sdb_plugin_ctx_t public;
79 sdb_plugin_info_t info;
80 } ctx_t;
81 #define CTX_INIT { SDB_OBJECT_INIT, \
82 SDB_PLUGIN_CTX_INIT, SDB_PLUGIN_INFO_INIT }
84 #define CTX(obj) ((ctx_t *)(obj))
86 typedef struct {
87 sdb_object_t super;
88 void *cb_callback;
89 sdb_object_t *cb_user_data;
90 ctx_t *cb_ctx;
91 } sdb_plugin_cb_t;
92 #define SDB_PLUGIN_CB_INIT { SDB_OBJECT_INIT, \
93 /* callback = */ NULL, /* user_data = */ NULL, \
94 SDB_PLUGIN_CTX_INIT }
96 typedef struct {
97 sdb_plugin_cb_t super;
98 #define ccb_callback super.cb_callback
99 #define ccb_user_data super.cb_user_data
100 #define ccb_ctx super.cb_ctx
101 sdb_time_t ccb_interval;
102 sdb_time_t ccb_next_update;
103 } sdb_plugin_collector_cb_t;
105 #define SDB_PLUGIN_CB(obj) ((sdb_plugin_cb_t *)(obj))
106 #define SDB_CONST_PLUGIN_CB(obj) ((const sdb_plugin_cb_t *)(obj))
107 #define SDB_PLUGIN_CCB(obj) ((sdb_plugin_collector_cb_t *)(obj))
108 #define SDB_CONST_PLUGIN_CCB(obj) ((const sdb_plugin_collector_cb_t *)(obj))
110 /*
111 * private variables
112 */
114 static sdb_plugin_ctx_t plugin_default_ctx = SDB_PLUGIN_CTX_INIT;
115 static sdb_plugin_info_t plugin_default_info = SDB_PLUGIN_INFO_INIT;
117 static pthread_key_t plugin_ctx_key;
118 static _Bool plugin_ctx_key_initialized = 0;
120 static sdb_llist_t *config_list = NULL;
121 static sdb_llist_t *init_list = NULL;
122 static sdb_llist_t *collector_list = NULL;
123 static sdb_llist_t *cname_list = NULL;
124 static sdb_llist_t *shutdown_list = NULL;
125 static sdb_llist_t *log_list = NULL;
127 /*
128 * private helper functions
129 */
131 static void
132 plugin_info_clear(sdb_plugin_info_t *info)
133 {
134 sdb_plugin_info_t empty_info = SDB_PLUGIN_INFO_INIT;
135 if (! info)
136 return;
138 if (info->plugin_name)
139 free(info->plugin_name);
140 if (info->filename)
141 free(info->filename);
143 if (info->name)
144 free(info->name);
145 if (info->description)
146 free(info->description);
147 if (info->copyright)
148 free(info->copyright);
149 if (info->license)
150 free(info->license);
152 *info = empty_info;
153 } /* plugin_info_clear */
155 static void
156 ctx_key_init(void)
157 {
158 if (plugin_ctx_key_initialized)
159 return;
161 pthread_key_create(&plugin_ctx_key, /* destructor */ NULL);
162 plugin_ctx_key_initialized = 1;
163 } /* ctx_key_init */
165 static int
166 plugin_cmp_next_update(const sdb_object_t *a, const sdb_object_t *b)
167 {
168 const sdb_plugin_collector_cb_t *ccb1
169 = (const sdb_plugin_collector_cb_t *)a;
170 const sdb_plugin_collector_cb_t *ccb2
171 = (const sdb_plugin_collector_cb_t *)b;
173 assert(ccb1 && ccb2);
175 return (ccb1->ccb_next_update > ccb2->ccb_next_update)
176 ? 1 : (ccb1->ccb_next_update < ccb2->ccb_next_update)
177 ? -1 : 0;
178 } /* plugin_cmp_next_update */
180 static int
181 plugin_lookup_by_name(const sdb_object_t *obj, const void *id)
182 {
183 const sdb_plugin_cb_t *cb = SDB_CONST_PLUGIN_CB(obj);
184 const char *name = id;
186 assert(cb && id && cb->cb_ctx);
187 if (!strcasecmp(cb->cb_ctx->info.plugin_name, name))
188 return 0;
189 return 1;
190 } /* plugin_lookup_by_name */
192 static void
193 plugin_unregister_by_name(const char *plugin_name)
194 {
195 size_t i;
197 struct {
198 const char *type;
199 sdb_llist_t *list;
200 } all_lists[] = {
201 { "config", config_list },
202 { "init", init_list },
203 { "collector", collector_list },
204 { "cname", cname_list },
205 { "shutdown", shutdown_list },
206 { "log", log_list },
207 };
209 for (i = 0; i < SDB_STATIC_ARRAY_LEN(all_lists); ++i) {
210 const char *type = all_lists[i].type;
211 sdb_llist_t *list = all_lists[i].list;
213 while (1) {
214 sdb_object_t *obj = sdb_llist_remove(list,
215 plugin_lookup_by_name, plugin_name);
216 sdb_plugin_cb_t *cb = SDB_PLUGIN_CB(obj);
218 if (! obj)
219 break;
221 sdb_log(SDB_LOG_INFO, "core: Unregistering "
222 "%s callback '%s' (module %s)", type, obj->name,
223 cb->cb_ctx->info.plugin_name);
224 sdb_object_deref(obj);
225 }
226 }
227 } /* plugin_unregister_by_name */
229 /*
230 * private types
231 */
233 static int
234 ctx_init(sdb_object_t *obj, va_list __attribute__((unused)) ap)
235 {
236 ctx_t *ctx = CTX(obj);
238 assert(ctx);
240 ctx->public = plugin_default_ctx;
241 ctx->info = plugin_default_info;
242 return 0;
243 } /* ctx_init */
245 static void
246 ctx_destroy(sdb_object_t *obj)
247 {
248 ctx_t *ctx = CTX(obj);
249 plugin_info_clear(&ctx->info);
250 } /* ctx_destroy */
252 static sdb_type_t ctx_type = {
253 sizeof(ctx_t),
255 ctx_init,
256 ctx_destroy
257 };
259 static ctx_t *
260 ctx_create(void)
261 {
262 ctx_t *ctx;
264 ctx = CTX(sdb_object_create("plugin-context", ctx_type));
265 if (! ctx)
266 return NULL;
268 if (! plugin_ctx_key_initialized)
269 ctx_key_init();
270 pthread_setspecific(plugin_ctx_key, ctx);
271 return ctx;
272 } /* ctx_create */
274 static ctx_t *
275 ctx_get(void)
276 {
277 if (! plugin_ctx_key_initialized)
278 ctx_key_init();
279 return pthread_getspecific(plugin_ctx_key);
280 } /* ctx_get */
282 static ctx_t *
283 ctx_set(ctx_t *new)
284 {
285 ctx_t *old;
287 if (! plugin_ctx_key_initialized)
288 ctx_key_init();
290 old = pthread_getspecific(plugin_ctx_key);
291 pthread_setspecific(plugin_ctx_key, new);
292 return old;
293 } /* ctx_set */
295 static int
296 plugin_cb_init(sdb_object_t *obj, va_list ap)
297 {
298 sdb_llist_t **list = va_arg(ap, sdb_llist_t **);
299 const char *type = va_arg(ap, const char *);
300 void *callback = va_arg(ap, void *);
301 sdb_object_t *ud = va_arg(ap, sdb_object_t *);
303 assert(list);
304 assert(type);
305 assert(obj);
307 if (sdb_llist_search_by_name(*list, obj->name)) {
308 sdb_log(SDB_LOG_WARNING, "core: %s callback '%s' "
309 "has already been registered. Ignoring newly "
310 "registered version.", type, obj->name);
311 return -1;
312 }
314 SDB_PLUGIN_CB(obj)->cb_callback = callback;
315 SDB_PLUGIN_CB(obj)->cb_ctx = ctx_get();
316 sdb_object_ref(SDB_OBJ(SDB_PLUGIN_CB(obj)->cb_ctx));
318 sdb_object_ref(ud);
319 SDB_PLUGIN_CB(obj)->cb_user_data = ud;
320 return 0;
321 } /* plugin_cb_init */
323 static void
324 plugin_cb_destroy(sdb_object_t *obj)
325 {
326 assert(obj);
327 sdb_object_deref(SDB_PLUGIN_CB(obj)->cb_user_data);
328 sdb_object_deref(SDB_OBJ(SDB_PLUGIN_CB(obj)->cb_ctx));
329 } /* plugin_cb_destroy */
331 static sdb_type_t sdb_plugin_cb_type = {
332 sizeof(sdb_plugin_cb_t),
334 plugin_cb_init,
335 plugin_cb_destroy
336 };
338 static sdb_type_t sdb_plugin_collector_cb_type = {
339 sizeof(sdb_plugin_collector_cb_t),
341 plugin_cb_init,
342 plugin_cb_destroy
343 };
345 static int
346 plugin_add_callback(sdb_llist_t **list, const char *type,
347 const char *name, void *callback, sdb_object_t *user_data)
348 {
349 sdb_object_t *obj;
351 if ((! name) || (! callback))
352 return -1;
354 assert(list);
356 if (! *list)
357 *list = sdb_llist_create();
358 if (! *list)
359 return -1;
361 obj = sdb_object_create(name, sdb_plugin_cb_type,
362 list, type, callback, user_data);
363 if (! obj)
364 return -1;
366 if (sdb_llist_append(*list, obj)) {
367 sdb_object_deref(obj);
368 return -1;
369 }
371 /* pass control to the list */
372 sdb_object_deref(obj);
374 sdb_log(SDB_LOG_INFO, "core: Registered %s callback '%s'.",
375 type, name);
376 return 0;
377 } /* plugin_add_callback */
379 /*
380 * public API
381 */
383 int
384 sdb_plugin_load(const char *name, const sdb_plugin_ctx_t *plugin_ctx)
385 {
386 char real_name[strlen(name) > 0 ? strlen(name) : 1];
387 const char *name_ptr;
388 char *tmp;
390 char filename[1024];
391 ctx_t *ctx;
393 lt_dlhandle lh;
395 int (*mod_init)(sdb_plugin_info_t *);
396 int status;
398 if ((! name) || (! *name))
399 return -1;
401 real_name[0] = '\0';
402 name_ptr = name;
404 while ((tmp = strstr(name_ptr, "::"))) {
405 strncat(real_name, name_ptr, (size_t)(tmp - name_ptr));
406 strcat(real_name, "/");
407 name_ptr = tmp + strlen("::");
408 }
409 strcat(real_name, name_ptr);
411 snprintf(filename, sizeof(filename), "%s/%s.so",
412 PKGLIBDIR, real_name);
413 filename[sizeof(filename) - 1] = '\0';
415 if (access(filename, R_OK)) {
416 char errbuf[1024];
417 sdb_log(SDB_LOG_ERR, "core: Failed to load plugin '%s' (%s): %s",
418 name, filename, sdb_strerror(errno, errbuf, sizeof(errbuf)));
419 return -1;
420 }
422 lt_dlinit();
423 lt_dlerror();
425 lh = lt_dlopen(filename);
426 if (! lh) {
427 sdb_log(SDB_LOG_ERR, "core: Failed to load plugin '%s': %s"
428 "The most common cause for this problem are missing "
429 "dependencies.\n", name, lt_dlerror());
430 return -1;
431 }
433 if (ctx_get())
434 sdb_log(SDB_LOG_WARNING, "core: Discarding old plugin context");
436 ctx = ctx_create();
437 if (! ctx) {
438 sdb_log(SDB_LOG_ERR, "core: Failed to initialize plugin context");
439 return -1;
440 }
442 ctx->info.plugin_name = strdup(name);
443 ctx->info.filename = strdup(filename);
445 if (plugin_ctx)
446 ctx->public = *plugin_ctx;
448 mod_init = (int (*)(sdb_plugin_info_t *))lt_dlsym(lh, "sdb_module_init");
449 if (! mod_init) {
450 sdb_log(SDB_LOG_ERR, "core: Failed to load plugin '%s': "
451 "could not find symbol 'sdb_module_init'", name);
452 sdb_object_deref(SDB_OBJ(ctx));
453 return -1;
454 }
456 status = mod_init(&ctx->info);
457 if (status) {
458 sdb_log(SDB_LOG_ERR, "core: Failed to initialize "
459 "module '%s'", name);
460 plugin_unregister_by_name(ctx->info.plugin_name);
461 sdb_object_deref(SDB_OBJ(ctx));
462 return -1;
463 }
465 /* compare minor version */
466 if ((ctx->info.version < 0)
467 || ((int)(ctx->info.version / 100) != (int)(SDB_VERSION / 100)))
468 sdb_log(SDB_LOG_WARNING, "core: WARNING: version of "
469 "plugin '%s' (%i.%i.%i) does not match our version "
470 "(%i.%i.%i); this might cause problems",
471 name, SDB_VERSION_DECODE(ctx->info.version),
472 SDB_VERSION_DECODE(SDB_VERSION));
474 sdb_log(SDB_LOG_INFO, "core: Successfully loaded "
475 "plugin '%s' v%i (%s)\n\t%s\n\tLicense: %s",
476 INFO_GET(&ctx->info, name), ctx->info.plugin_version,
477 INFO_GET(&ctx->info, description),
478 INFO_GET(&ctx->info, copyright),
479 INFO_GET(&ctx->info, license));
481 /* any registered callbacks took ownership of the context */
482 sdb_object_deref(SDB_OBJ(ctx));
484 /* reset */
485 ctx_set(NULL);
486 return 0;
487 } /* sdb_plugin_load */
489 int
490 sdb_plugin_set_info(sdb_plugin_info_t *info, int type, ...)
491 {
492 va_list ap;
494 if (! info)
495 return -1;
497 va_start(ap, type);
499 switch (type) {
500 case SDB_PLUGIN_INFO_NAME:
501 {
502 char *name = va_arg(ap, char *);
503 if (name) {
504 if (info->name)
505 free(info->name);
506 info->name = strdup(name);
507 }
508 }
509 break;
510 case SDB_PLUGIN_INFO_DESC:
511 {
512 char *desc = va_arg(ap, char *);
513 if (desc) {
514 if (info->description)
515 free(info->description);
516 info->description = strdup(desc);
517 }
518 }
519 break;
520 case SDB_PLUGIN_INFO_COPYRIGHT:
521 {
522 char *copyright = va_arg(ap, char *);
523 if (copyright)
524 info->copyright = strdup(copyright);
525 }
526 break;
527 case SDB_PLUGIN_INFO_LICENSE:
528 {
529 char *license = va_arg(ap, char *);
530 if (license) {
531 if (info->license)
532 free(info->license);
533 info->license = strdup(license);
534 }
535 }
536 break;
537 case SDB_PLUGIN_INFO_VERSION:
538 {
539 int version = va_arg(ap, int);
540 info->version = version;
541 }
542 break;
543 case SDB_PLUGIN_INFO_PLUGIN_VERSION:
544 {
545 int version = va_arg(ap, int);
546 info->plugin_version = version;
547 }
548 break;
549 default:
550 va_end(ap);
551 return -1;
552 }
554 va_end(ap);
555 return 0;
556 } /* sdb_plugin_set_info */
558 int
559 sdb_plugin_register_config(const char *name, sdb_plugin_config_cb callback)
560 {
561 return plugin_add_callback(&config_list, "init", name,
562 callback, NULL);
563 } /* sdb_plugin_register_config */
565 int
566 sdb_plugin_register_init(const char *name, sdb_plugin_init_cb callback,
567 sdb_object_t *user_data)
568 {
569 return plugin_add_callback(&init_list, "init", name,
570 callback, user_data);
571 } /* sdb_plugin_register_init */
573 int
574 sdb_plugin_register_shutdown(const char *name, sdb_plugin_shutdown_cb callback,
575 sdb_object_t *user_data)
576 {
577 return plugin_add_callback(&shutdown_list, "shutdown", name,
578 callback, user_data);
579 } /* sdb_plugin_register_shutdown */
581 int
582 sdb_plugin_register_log(const char *name, sdb_plugin_log_cb callback,
583 sdb_object_t *user_data)
584 {
585 return plugin_add_callback(&log_list, "log", name, callback,
586 user_data);
587 } /* sdb_plugin_register_log */
589 int
590 sdb_plugin_register_cname(const char *name, sdb_plugin_cname_cb callback,
591 sdb_object_t *user_data)
592 {
593 return plugin_add_callback(&cname_list, "cname", name, callback,
594 user_data);
595 } /* sdb_plugin_register_cname */
597 int
598 sdb_plugin_register_collector(const char *name, sdb_plugin_collector_cb callback,
599 const sdb_time_t *interval, sdb_object_t *user_data)
600 {
601 sdb_object_t *obj;
603 if ((! name) || (! callback))
604 return -1;
606 if (! collector_list)
607 collector_list = sdb_llist_create();
608 if (! collector_list)
609 return -1;
611 obj = sdb_object_create(name, sdb_plugin_collector_cb_type,
612 &collector_list, "collector", callback, user_data);
613 if (! obj)
614 return -1;
616 if (interval)
617 SDB_PLUGIN_CCB(obj)->ccb_interval = *interval;
618 else {
619 sdb_time_t tmp = sdb_plugin_get_ctx().interval;
621 if (tmp > 0)
622 SDB_PLUGIN_CCB(obj)->ccb_interval = tmp;
623 else
624 SDB_PLUGIN_CCB(obj)->ccb_interval = 0;
625 }
627 if (! (SDB_PLUGIN_CCB(obj)->ccb_next_update = sdb_gettime())) {
628 char errbuf[1024];
629 sdb_log(SDB_LOG_ERR, "core: Failed to determine current "
630 "time: %s", sdb_strerror(errno, errbuf, sizeof(errbuf)));
631 sdb_object_deref(obj);
632 return -1;
633 }
635 if (sdb_llist_insert_sorted(collector_list, obj,
636 plugin_cmp_next_update)) {
637 sdb_object_deref(obj);
638 return -1;
639 }
641 /* pass control to the list */
642 sdb_object_deref(obj);
644 sdb_log(SDB_LOG_INFO, "core: Registered collector callback '%s' "
645 "(interval = %.3fs).", name,
646 SDB_TIME_TO_DOUBLE(SDB_PLUGIN_CCB(obj)->ccb_interval));
647 return 0;
648 } /* sdb_plugin_register_collector */
650 sdb_plugin_ctx_t
651 sdb_plugin_get_ctx(void)
652 {
653 ctx_t *c;
655 c = ctx_get();
656 if (! c) {
657 sdb_plugin_log(SDB_LOG_ERR, "core: Invalid read access to plugin "
658 "context outside a plugin");
659 return plugin_default_ctx;
660 }
661 return c->public;
662 } /* sdb_plugin_get_ctx */
664 int
665 sdb_plugin_set_ctx(sdb_plugin_ctx_t ctx, sdb_plugin_ctx_t *old)
666 {
667 ctx_t *c;
669 c = ctx_get();
670 if (! c) {
671 sdb_plugin_log(SDB_LOG_ERR, "core: Invalid write access to plugin "
672 "context outside a plugin");
673 return -1;
674 }
676 if (old)
677 *old = c->public;
678 c->public = ctx;
679 return 0;
680 } /* sdb_plugin_set_ctx */
682 int
683 sdb_plugin_configure(const char *name, oconfig_item_t *ci)
684 {
685 sdb_plugin_cb_t *plugin;
686 sdb_plugin_config_cb callback;
688 ctx_t *old_ctx;
690 int status;
692 if ((! name) || (! ci))
693 return -1;
695 plugin = SDB_PLUGIN_CB(sdb_llist_search_by_name(config_list, name));
696 if (! plugin) {
697 /* XXX: check if any such plugin has been loaded */
698 sdb_log(SDB_LOG_ERR, "core: Plugin '%s' did not register "
699 "a config callback.", name);
700 errno = ENOENT;
701 return -1;
702 }
704 old_ctx = ctx_set(plugin->cb_ctx);
705 callback = plugin->cb_callback;
706 status = callback(ci);
707 ctx_set(old_ctx);
708 return status;
709 } /* sdb_plugin_configure */
711 int
712 sdb_plugin_init_all(void)
713 {
714 sdb_llist_iter_t *iter;
715 int ret = 0;
717 iter = sdb_llist_get_iter(init_list);
718 while (sdb_llist_iter_has_next(iter)) {
719 sdb_plugin_cb_t *cb;
720 sdb_plugin_init_cb callback;
721 ctx_t *old_ctx;
723 sdb_object_t *obj = sdb_llist_iter_get_next(iter);
724 assert(obj);
725 cb = SDB_PLUGIN_CB(obj);
727 callback = cb->cb_callback;
729 old_ctx = ctx_set(cb->cb_ctx);
730 if (callback(cb->cb_user_data)) {
731 sdb_log(SDB_LOG_ERR, "core: Failed to initialize plugin "
732 "'%s'. Unregistering all callbacks.", obj->name);
733 plugin_unregister_by_name(cb->cb_ctx->info.plugin_name);
734 ++ret;
735 }
736 ctx_set(old_ctx);
737 }
738 sdb_llist_iter_destroy(iter);
739 return ret;
740 } /* sdb_plugin_init_all */
742 int
743 sdb_plugin_collector_loop(sdb_plugin_loop_t *loop)
744 {
745 if (! collector_list) {
746 sdb_log(SDB_LOG_WARNING, "core: No collectors registered. "
747 "Quiting main loop.");
748 return -1;
749 }
751 if (! loop)
752 return -1;
754 while (loop->do_loop) {
755 sdb_plugin_collector_cb callback;
756 ctx_t *old_ctx;
758 sdb_time_t interval, now;
760 sdb_object_t *obj = sdb_llist_shift(collector_list);
761 if (! obj)
762 return -1;
764 callback = SDB_PLUGIN_CCB(obj)->ccb_callback;
766 if (! (now = sdb_gettime())) {
767 char errbuf[1024];
768 sdb_log(SDB_LOG_ERR, "core: Failed to determine current "
769 "time in collector main loop: %s",
770 sdb_strerror(errno, errbuf, sizeof(errbuf)));
771 now = SDB_PLUGIN_CCB(obj)->ccb_next_update;
772 }
774 if (now < SDB_PLUGIN_CCB(obj)->ccb_next_update) {
775 interval = SDB_PLUGIN_CCB(obj)->ccb_next_update - now;
777 errno = 0;
778 while (loop->do_loop && sdb_sleep(interval, &interval)) {
779 if (errno != EINTR) {
780 char errbuf[1024];
781 sdb_log(SDB_LOG_ERR, "core: Failed to sleep "
782 "in collector main loop: %s",
783 sdb_strerror(errno, errbuf, sizeof(errbuf)));
784 return -1;
785 }
786 errno = 0;
787 }
789 if (! loop->do_loop)
790 return 0;
791 }
793 old_ctx = ctx_set(SDB_PLUGIN_CCB(obj)->ccb_ctx);
794 if (callback(SDB_PLUGIN_CCB(obj)->ccb_user_data)) {
795 /* XXX */
796 }
797 ctx_set(old_ctx);
799 interval = SDB_PLUGIN_CCB(obj)->ccb_interval;
800 if (! interval)
801 interval = loop->default_interval;
802 if (! interval) {
803 sdb_log(SDB_LOG_WARNING, "core: No interval configured "
804 "for plugin '%s'; skipping any further "
805 "iterations.", obj->name);
806 sdb_object_deref(obj);
807 continue;
808 }
810 SDB_PLUGIN_CCB(obj)->ccb_next_update += interval;
812 if (! (now = sdb_gettime())) {
813 char errbuf[1024];
814 sdb_log(SDB_LOG_ERR, "core: Failed to determine current "
815 "time in collector main loop: %s",
816 sdb_strerror(errno, errbuf, sizeof(errbuf)));
817 now = SDB_PLUGIN_CCB(obj)->ccb_next_update;
818 }
820 if (now > SDB_PLUGIN_CCB(obj)->ccb_next_update) {
821 sdb_log(SDB_LOG_WARNING, "core: Plugin '%s' took too "
822 "long; skipping iterations to keep up.",
823 obj->name);
824 SDB_PLUGIN_CCB(obj)->ccb_next_update = now;
825 }
827 if (sdb_llist_insert_sorted(collector_list, obj,
828 plugin_cmp_next_update)) {
829 sdb_log(SDB_LOG_ERR, "core: Failed to re-insert "
830 "plugin '%s' into collector list. Unable to further "
831 "use the plugin.",
832 obj->name);
833 sdb_object_deref(obj);
834 return -1;
835 }
837 /* pass control back to the list */
838 sdb_object_deref(obj);
839 }
840 return 0;
841 } /* sdb_plugin_read_loop */
843 char *
844 sdb_plugin_cname(char *hostname)
845 {
846 sdb_llist_iter_t *iter;
848 if (! hostname)
849 return NULL;
851 if (! cname_list)
852 return hostname;
854 iter = sdb_llist_get_iter(cname_list);
855 while (sdb_llist_iter_has_next(iter)) {
856 sdb_plugin_cname_cb callback;
857 char *cname;
859 sdb_object_t *obj = sdb_llist_iter_get_next(iter);
860 assert(obj);
862 callback = SDB_PLUGIN_CB(obj)->cb_callback;
863 cname = callback(hostname, SDB_PLUGIN_CB(obj)->cb_user_data);
864 if (cname) {
865 free(hostname);
866 hostname = cname;
867 }
868 /* else: don't change hostname */
869 }
870 sdb_llist_iter_destroy(iter);
871 return hostname;
872 } /* sdb_plugin_cname */
874 int
875 sdb_plugin_log(int prio, const char *msg)
876 {
877 sdb_llist_iter_t *iter;
878 int ret = -1;
880 if (! msg)
881 return 0;
883 if (! log_list)
884 return fprintf(stderr, "[%s] %s\n", SDB_LOG_PRIO_TO_STRING(prio), msg);
886 iter = sdb_llist_get_iter(log_list);
887 while (sdb_llist_iter_has_next(iter)) {
888 sdb_plugin_log_cb callback;
889 int tmp;
891 sdb_object_t *obj = sdb_llist_iter_get_next(iter);
892 assert(obj);
894 callback = SDB_PLUGIN_CB(obj)->cb_callback;
895 tmp = callback(prio, msg, SDB_PLUGIN_CB(obj)->cb_user_data);
896 if (tmp > ret)
897 ret = tmp;
898 }
899 sdb_llist_iter_destroy(iter);
900 return ret;
901 } /* sdb_plugin_log */
903 int
904 sdb_plugin_vlogf(int prio, const char *fmt, va_list ap)
905 {
906 sdb_strbuf_t *buf;
907 int ret;
909 if (! fmt)
910 return 0;
912 buf = sdb_strbuf_create(64);
913 if (! buf) {
914 ret = fprintf(stderr, "[%s] ", SDB_LOG_PRIO_TO_STRING(prio));
915 ret += vfprintf(stderr, fmt, ap);
916 return ret;
917 }
919 if (sdb_strbuf_vsprintf(buf, fmt, ap) < 0) {
920 sdb_strbuf_destroy(buf);
921 return -1;
922 }
924 ret = sdb_plugin_log(prio, sdb_strbuf_string(buf));
925 sdb_strbuf_destroy(buf);
926 return ret;
927 } /* sdb_plugin_vlogf */
929 int
930 sdb_plugin_logf(int prio, const char *fmt, ...)
931 {
932 va_list ap;
933 int ret;
935 if (! fmt)
936 return 0;
938 va_start(ap, fmt);
939 ret = sdb_plugin_vlogf(prio, fmt, ap);
940 va_end(ap);
941 return ret;
942 } /* sdb_plugin_logf */
944 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */