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/error.h"
31 #include "core/time.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 *name;
56 char *description;
57 char *copyright;
58 char *license;
60 int version;
61 int plugin_version;
62 };
63 #define SDB_PLUGIN_INFO_INIT { /* name */ NULL, /* desc */ NULL, \
64 /* copyright */ NULL, /* license */ NULL, \
65 /* version */ -1, /* plugin_version */ -1 }
66 #define INFO_GET(i, attr) \
67 ((i)->attr ? (i)->attr : #attr" not set")
69 typedef struct {
70 sdb_object_t super;
71 sdb_plugin_ctx_t public;
73 sdb_plugin_info_t info;
74 } ctx_t;
75 #define CTX_INIT { SDB_OBJECT_INIT, \
76 SDB_PLUGIN_CTX_INIT, SDB_PLUGIN_INFO_INIT }
78 #define CTX(obj) ((ctx_t *)(obj))
80 typedef struct {
81 sdb_object_t super;
82 void *cb_callback;
83 sdb_object_t *cb_user_data;
84 ctx_t *cb_ctx;
85 } sdb_plugin_cb_t;
86 #define SDB_PLUGIN_CB_INIT { SDB_OBJECT_INIT, \
87 /* callback = */ NULL, /* user_data = */ NULL, \
88 SDB_PLUGIN_CTX_INIT }
90 typedef struct {
91 sdb_plugin_cb_t super;
92 #define ccb_callback super.cb_callback
93 #define ccb_user_data super.cb_user_data
94 #define ccb_ctx super.cb_ctx
95 sdb_time_t ccb_interval;
96 sdb_time_t ccb_next_update;
97 } sdb_plugin_collector_cb_t;
99 #define SDB_PLUGIN_CB(obj) ((sdb_plugin_cb_t *)(obj))
100 #define SDB_PLUGIN_CCB(obj) ((sdb_plugin_collector_cb_t *)(obj))
102 /*
103 * private variables
104 */
106 static sdb_plugin_ctx_t plugin_default_ctx = SDB_PLUGIN_CTX_INIT;
107 static sdb_plugin_info_t plugin_default_info = SDB_PLUGIN_INFO_INIT;
109 static pthread_key_t plugin_ctx_key;
110 static _Bool plugin_ctx_key_initialized = 0;
112 static sdb_llist_t *config_list = NULL;
113 static sdb_llist_t *init_list = NULL;
114 static sdb_llist_t *collector_list = NULL;
115 static sdb_llist_t *cname_list = NULL;
116 static sdb_llist_t *shutdown_list = NULL;
117 static sdb_llist_t *log_list = NULL;
119 /*
120 * private helper functions
121 */
123 static void
124 sdb_plugin_info_clear(sdb_plugin_info_t *info)
125 {
126 sdb_plugin_info_t empty_info = SDB_PLUGIN_INFO_INIT;
127 if (! info)
128 return;
130 if (info->name)
131 free(info->name);
132 if (info->description)
133 free(info->description);
134 if (info->copyright)
135 free(info->copyright);
136 if (info->license)
137 free(info->license);
139 *info = empty_info;
140 } /* sdb_plugin_info_clear */
142 static void
143 ctx_key_init(void)
144 {
145 if (plugin_ctx_key_initialized)
146 return;
148 pthread_key_create(&plugin_ctx_key, /* destructor */ NULL);
149 plugin_ctx_key_initialized = 1;
150 } /* ctx_key_init */
152 static int
153 sdb_plugin_cmp_next_update(const sdb_object_t *a, const sdb_object_t *b)
154 {
155 const sdb_plugin_collector_cb_t *ccb1
156 = (const sdb_plugin_collector_cb_t *)a;
157 const sdb_plugin_collector_cb_t *ccb2
158 = (const sdb_plugin_collector_cb_t *)b;
160 assert(ccb1 && ccb2);
162 return (ccb1->ccb_next_update > ccb2->ccb_next_update)
163 ? 1 : (ccb1->ccb_next_update < ccb2->ccb_next_update)
164 ? -1 : 0;
165 } /* sdb_plugin_cmp_next_update */
167 /*
168 * private types
169 */
171 static int
172 ctx_init(sdb_object_t *obj, va_list __attribute__((unused)) ap)
173 {
174 ctx_t *ctx = CTX(obj);
176 assert(ctx);
178 ctx->public = plugin_default_ctx;
179 ctx->info = plugin_default_info;
180 return 0;
181 } /* ctx_init */
183 static void
184 ctx_destroy(sdb_object_t *obj)
185 {
186 ctx_t *ctx = CTX(obj);
187 sdb_plugin_info_clear(&ctx->info);
188 } /* ctx_destroy */
190 static sdb_type_t ctx_type = {
191 sizeof(ctx_t),
193 ctx_init,
194 ctx_destroy
195 };
197 static ctx_t *
198 ctx_create(void)
199 {
200 ctx_t *ctx;
202 ctx = CTX(sdb_object_create("plugin-context", ctx_type));
203 if (! ctx)
204 return NULL;
206 if (! plugin_ctx_key_initialized)
207 ctx_key_init();
208 pthread_setspecific(plugin_ctx_key, ctx);
209 return ctx;
210 } /* ctx_create */
212 static ctx_t *
213 ctx_get(void)
214 {
215 if (! plugin_ctx_key_initialized)
216 ctx_key_init();
217 return pthread_getspecific(plugin_ctx_key);
218 } /* ctx_get */
220 static ctx_t *
221 ctx_set(ctx_t *new)
222 {
223 ctx_t *old;
225 if (! plugin_ctx_key_initialized)
226 ctx_key_init();
228 old = pthread_getspecific(plugin_ctx_key);
229 pthread_setspecific(plugin_ctx_key, new);
230 return old;
231 } /* ctx_set */
233 static int
234 sdb_plugin_cb_init(sdb_object_t *obj, va_list ap)
235 {
236 sdb_llist_t **list = va_arg(ap, sdb_llist_t **);
237 const char *type = va_arg(ap, const char *);
238 void *callback = va_arg(ap, void *);
239 sdb_object_t *ud = va_arg(ap, sdb_object_t *);
241 assert(list);
242 assert(type);
243 assert(obj);
245 if (sdb_llist_search_by_name(*list, obj->name)) {
246 sdb_log(SDB_LOG_WARNING, "plugin: %s callback '%s' "
247 "has already been registered. Ignoring newly "
248 "registered version.", type, obj->name);
249 return -1;
250 }
252 SDB_PLUGIN_CB(obj)->cb_callback = callback;
253 SDB_PLUGIN_CB(obj)->cb_ctx = ctx_get();
254 sdb_object_ref(SDB_OBJ(SDB_PLUGIN_CB(obj)->cb_ctx));
256 sdb_object_ref(ud);
257 SDB_PLUGIN_CB(obj)->cb_user_data = ud;
258 return 0;
259 } /* sdb_plugin_cb_init */
261 static void
262 sdb_plugin_cb_destroy(sdb_object_t *obj)
263 {
264 assert(obj);
265 sdb_object_deref(SDB_PLUGIN_CB(obj)->cb_user_data);
266 sdb_object_deref(SDB_OBJ(SDB_PLUGIN_CB(obj)->cb_ctx));
267 } /* sdb_plugin_cb_destroy */
269 static sdb_type_t sdb_plugin_cb_type = {
270 sizeof(sdb_plugin_cb_t),
272 sdb_plugin_cb_init,
273 sdb_plugin_cb_destroy
274 };
276 static sdb_type_t sdb_plugin_collector_cb_type = {
277 sizeof(sdb_plugin_collector_cb_t),
279 sdb_plugin_cb_init,
280 sdb_plugin_cb_destroy
281 };
283 static int
284 sdb_plugin_add_callback(sdb_llist_t **list, const char *type,
285 const char *name, void *callback, sdb_object_t *user_data)
286 {
287 sdb_object_t *obj;
289 if ((! name) || (! callback))
290 return -1;
292 assert(list);
294 if (! *list)
295 *list = sdb_llist_create();
296 if (! *list)
297 return -1;
299 obj = sdb_object_create(name, sdb_plugin_cb_type,
300 list, type, callback, user_data);
301 if (! obj)
302 return -1;
304 if (sdb_llist_append(*list, obj)) {
305 sdb_object_deref(obj);
306 return -1;
307 }
309 /* pass control to the list */
310 sdb_object_deref(obj);
312 sdb_log(SDB_LOG_INFO, "plugin: Registered %s callback '%s'.",
313 type, name);
314 return 0;
315 } /* sdb_plugin_add_callback */
317 /*
318 * public API
319 */
321 int
322 sdb_plugin_load(const char *name, const sdb_plugin_ctx_t *plugin_ctx)
323 {
324 char real_name[strlen(name) > 0 ? strlen(name) : 1];
325 const char *name_ptr;
326 char *tmp;
328 char filename[1024];
329 ctx_t *ctx;
331 lt_dlhandle lh;
333 int (*mod_init)(sdb_plugin_info_t *);
334 int status;
336 if ((! name) || (! *name))
337 return -1;
339 real_name[0] = '\0';
340 name_ptr = name;
342 while ((tmp = strstr(name_ptr, "::"))) {
343 strncat(real_name, name_ptr, (size_t)(tmp - name_ptr));
344 strcat(real_name, "/");
345 name_ptr = tmp + strlen("::");
346 }
347 strcat(real_name, name_ptr);
349 snprintf(filename, sizeof(filename), "%s/%s.so",
350 PKGLIBDIR, real_name);
351 filename[sizeof(filename) - 1] = '\0';
353 if (access(filename, R_OK)) {
354 char errbuf[1024];
355 sdb_log(SDB_LOG_ERR, "plugin: Failed to load plugin '%s' (%s): %s",
356 name, filename, sdb_strerror(errno, errbuf, sizeof(errbuf)));
357 return -1;
358 }
360 lt_dlinit();
361 lt_dlerror();
363 lh = lt_dlopen(filename);
364 if (! lh) {
365 sdb_log(SDB_LOG_ERR, "plugin: Failed to load plugin '%s': %s"
366 "The most common cause for this problem are missing "
367 "dependencies.\n", name, lt_dlerror());
368 return -1;
369 }
371 if (ctx_get())
372 sdb_log(SDB_LOG_WARNING, "plugin: Discarding old plugin context");
374 ctx = ctx_create();
375 if (! ctx) {
376 sdb_log(SDB_LOG_ERR, "plugin: Failed to initialize plugin context");
377 return -1;
378 }
380 if (plugin_ctx)
381 ctx->public = *plugin_ctx;
383 mod_init = (int (*)(sdb_plugin_info_t *))lt_dlsym(lh, "sdb_module_init");
384 if (! mod_init) {
385 sdb_log(SDB_LOG_ERR, "plugin: Failed to load plugin '%s': "
386 "could not find symbol 'sdb_module_init'", name);
387 sdb_object_deref(SDB_OBJ(ctx));
388 return -1;
389 }
391 status = mod_init(&ctx->info);
392 if (status) {
393 sdb_log(SDB_LOG_ERR, "plugin: Failed to initialize "
394 "plugin '%s'", name);
395 sdb_object_deref(SDB_OBJ(ctx));
396 return -1;
397 }
399 /* compare minor version */
400 if ((ctx->info.version < 0)
401 || ((int)(ctx->info.version / 100) != (int)(SDB_VERSION / 100)))
402 sdb_log(SDB_LOG_WARNING, "plugin: WARNING: version of "
403 "plugin '%s' (%i.%i.%i) does not match our version "
404 "(%i.%i.%i); this might cause problems",
405 name, SDB_VERSION_DECODE(ctx->info.version),
406 SDB_VERSION_DECODE(SDB_VERSION));
408 sdb_log(SDB_LOG_INFO, "plugin: Successfully loaded "
409 "plugin '%s' v%i (%s)\n\t%s\n\tLicense: %s",
410 INFO_GET(&ctx->info, name), ctx->info.plugin_version,
411 INFO_GET(&ctx->info, description),
412 INFO_GET(&ctx->info, copyright),
413 INFO_GET(&ctx->info, license));
415 /* any registered callbacks took ownership of the context */
416 sdb_object_deref(SDB_OBJ(ctx));
418 /* reset */
419 ctx_set(NULL);
420 return 0;
421 } /* sdb_plugin_load */
423 int
424 sdb_plugin_set_info(sdb_plugin_info_t *info, int type, ...)
425 {
426 va_list ap;
428 if (! info)
429 return -1;
431 va_start(ap, type);
433 switch (type) {
434 case SDB_PLUGIN_INFO_NAME:
435 {
436 char *name = va_arg(ap, char *);
437 if (name) {
438 if (info->name)
439 free(info->name);
440 info->name = strdup(name);
441 }
442 }
443 break;
444 case SDB_PLUGIN_INFO_DESC:
445 {
446 char *desc = va_arg(ap, char *);
447 if (desc) {
448 if (info->description)
449 free(info->description);
450 info->description = strdup(desc);
451 }
452 }
453 break;
454 case SDB_PLUGIN_INFO_COPYRIGHT:
455 {
456 char *copyright = va_arg(ap, char *);
457 if (copyright)
458 info->copyright = strdup(copyright);
459 }
460 break;
461 case SDB_PLUGIN_INFO_LICENSE:
462 {
463 char *license = va_arg(ap, char *);
464 if (license) {
465 if (info->license)
466 free(info->license);
467 info->license = strdup(license);
468 }
469 }
470 break;
471 case SDB_PLUGIN_INFO_VERSION:
472 {
473 int version = va_arg(ap, int);
474 info->version = version;
475 }
476 break;
477 case SDB_PLUGIN_INFO_PLUGIN_VERSION:
478 {
479 int version = va_arg(ap, int);
480 info->plugin_version = version;
481 }
482 break;
483 default:
484 va_end(ap);
485 return -1;
486 }
488 va_end(ap);
489 return 0;
490 } /* sdb_plugin_set_info */
492 int
493 sdb_plugin_register_config(const char *name, sdb_plugin_config_cb callback)
494 {
495 return sdb_plugin_add_callback(&config_list, "init", name,
496 callback, NULL);
497 } /* sdb_plugin_register_config */
499 int
500 sdb_plugin_register_init(const char *name, sdb_plugin_init_cb callback,
501 sdb_object_t *user_data)
502 {
503 return sdb_plugin_add_callback(&init_list, "init", name,
504 callback, user_data);
505 } /* sdb_plugin_register_init */
507 int
508 sdb_plugin_register_shutdown(const char *name, sdb_plugin_shutdown_cb callback,
509 sdb_object_t *user_data)
510 {
511 return sdb_plugin_add_callback(&shutdown_list, "shutdown", name,
512 callback, user_data);
513 } /* sdb_plugin_register_shutdown */
515 int
516 sdb_plugin_register_log(const char *name, sdb_plugin_log_cb callback,
517 sdb_object_t *user_data)
518 {
519 return sdb_plugin_add_callback(&log_list, "log", name, callback,
520 user_data);
521 } /* sdb_plugin_register_log */
523 int
524 sdb_plugin_register_cname(const char *name, sdb_plugin_cname_cb callback,
525 sdb_object_t *user_data)
526 {
527 return sdb_plugin_add_callback(&cname_list, "cname", name, callback,
528 user_data);
529 } /* sdb_plugin_register_cname */
531 int
532 sdb_plugin_register_collector(const char *name, sdb_plugin_collector_cb callback,
533 const sdb_time_t *interval, sdb_object_t *user_data)
534 {
535 sdb_object_t *obj;
537 if ((! name) || (! callback))
538 return -1;
540 if (! collector_list)
541 collector_list = sdb_llist_create();
542 if (! collector_list)
543 return -1;
545 obj = sdb_object_create(name, sdb_plugin_collector_cb_type,
546 &collector_list, "collector", callback, user_data);
547 if (! obj)
548 return -1;
550 if (interval)
551 SDB_PLUGIN_CCB(obj)->ccb_interval = *interval;
552 else {
553 sdb_time_t tmp = sdb_plugin_get_ctx().interval;
555 if (tmp > 0)
556 SDB_PLUGIN_CCB(obj)->ccb_interval = tmp;
557 else
558 SDB_PLUGIN_CCB(obj)->ccb_interval = 0;
559 }
561 if (! (SDB_PLUGIN_CCB(obj)->ccb_next_update = sdb_gettime())) {
562 char errbuf[1024];
563 sdb_log(SDB_LOG_ERR, "plugin: Failed to determine current "
564 "time: %s", sdb_strerror(errno, errbuf, sizeof(errbuf)));
565 sdb_object_deref(obj);
566 return -1;
567 }
569 if (sdb_llist_insert_sorted(collector_list, obj,
570 sdb_plugin_cmp_next_update)) {
571 sdb_object_deref(obj);
572 return -1;
573 }
575 /* pass control to the list */
576 sdb_object_deref(obj);
578 sdb_log(SDB_LOG_INFO, "plugin: Registered collector callback '%s' "
579 "(interval = %.3fs).", name,
580 SDB_TIME_TO_DOUBLE(SDB_PLUGIN_CCB(obj)->ccb_interval));
581 return 0;
582 } /* sdb_plugin_register_collector */
584 sdb_plugin_ctx_t
585 sdb_plugin_get_ctx(void)
586 {
587 ctx_t *c;
589 c = ctx_get();
590 if (! c) {
591 sdb_plugin_log(SDB_LOG_ERR, "plugin: Invalid read access to plugin "
592 "context outside a plugin");
593 return plugin_default_ctx;
594 }
595 return c->public;
596 } /* sdb_plugin_get_ctx */
598 int
599 sdb_plugin_set_ctx(sdb_plugin_ctx_t ctx, sdb_plugin_ctx_t *old)
600 {
601 ctx_t *c;
603 c = ctx_get();
604 if (! c) {
605 sdb_plugin_log(SDB_LOG_ERR, "plugin: Invalid write access to plugin "
606 "context outside a plugin");
607 return -1;
608 }
610 if (old)
611 *old = c->public;
612 c->public = ctx;
613 return 0;
614 } /* sdb_plugin_set_ctx */
616 int
617 sdb_plugin_configure(const char *name, oconfig_item_t *ci)
618 {
619 sdb_plugin_cb_t *plugin;
620 sdb_plugin_config_cb callback;
622 ctx_t *old_ctx;
624 int status;
626 if ((! name) || (! ci))
627 return -1;
629 plugin = SDB_PLUGIN_CB(sdb_llist_search_by_name(config_list, name));
630 if (! plugin) {
631 /* XXX: check if any such plugin has been loaded */
632 sdb_log(SDB_LOG_ERR, "plugin: Plugin '%s' did not register "
633 "a config callback.", name);
634 errno = ENOENT;
635 return -1;
636 }
638 old_ctx = ctx_set(plugin->cb_ctx);
639 callback = plugin->cb_callback;
640 status = callback(ci);
641 ctx_set(old_ctx);
642 return status;
643 } /* sdb_plugin_configure */
645 int
646 sdb_plugin_init_all(void)
647 {
648 sdb_llist_iter_t *iter;
650 iter = sdb_llist_get_iter(init_list);
651 while (sdb_llist_iter_has_next(iter)) {
652 sdb_plugin_init_cb callback;
653 ctx_t *old_ctx;
655 sdb_object_t *obj = sdb_llist_iter_get_next(iter);
656 assert(obj);
658 callback = SDB_PLUGIN_CB(obj)->cb_callback;
660 old_ctx = ctx_set(SDB_PLUGIN_CB(obj)->cb_ctx);
661 if (callback(SDB_PLUGIN_CB(obj)->cb_user_data)) {
662 /* XXX: unload plugin */
663 }
664 ctx_set(old_ctx);
665 }
666 sdb_llist_iter_destroy(iter);
667 return 0;
668 } /* sdb_plugin_init_all */
670 int
671 sdb_plugin_collector_loop(sdb_plugin_loop_t *loop)
672 {
673 if (! collector_list) {
674 sdb_log(SDB_LOG_WARNING, "plugin: No collectors registered. "
675 "Quiting main loop.");
676 return -1;
677 }
679 if (! loop)
680 return -1;
682 while (loop->do_loop) {
683 sdb_plugin_collector_cb callback;
684 ctx_t *old_ctx;
686 sdb_time_t interval, now;
688 sdb_object_t *obj = sdb_llist_shift(collector_list);
689 if (! obj)
690 return -1;
692 callback = SDB_PLUGIN_CCB(obj)->ccb_callback;
694 if (! (now = sdb_gettime())) {
695 char errbuf[1024];
696 sdb_log(SDB_LOG_ERR, "plugin: Failed to determine current "
697 "time: %s", sdb_strerror(errno, errbuf, sizeof(errbuf)));
698 now = SDB_PLUGIN_CCB(obj)->ccb_next_update;
699 }
701 if (now < SDB_PLUGIN_CCB(obj)->ccb_next_update) {
702 interval = SDB_PLUGIN_CCB(obj)->ccb_next_update - now;
704 errno = 0;
705 while (loop->do_loop && sdb_sleep(interval, &interval)) {
706 if (errno != EINTR) {
707 char errbuf[1024];
708 sdb_log(SDB_LOG_ERR, "plugin: Failed to sleep: %s",
709 sdb_strerror(errno, errbuf, sizeof(errbuf)));
710 return -1;
711 }
712 errno = 0;
713 }
715 if (! loop->do_loop)
716 return 0;
717 }
719 old_ctx = ctx_set(SDB_PLUGIN_CCB(obj)->ccb_ctx);
720 if (callback(SDB_PLUGIN_CCB(obj)->ccb_user_data)) {
721 /* XXX */
722 }
723 ctx_set(old_ctx);
725 interval = SDB_PLUGIN_CCB(obj)->ccb_interval;
726 if (! interval)
727 interval = loop->default_interval;
728 if (! interval) {
729 sdb_log(SDB_LOG_WARNING, "plugin: No interval configured "
730 "for plugin '%s'; skipping any further "
731 "iterations.", obj->name);
732 sdb_object_deref(obj);
733 continue;
734 }
736 SDB_PLUGIN_CCB(obj)->ccb_next_update += interval;
738 if (! (now = sdb_gettime())) {
739 char errbuf[1024];
740 sdb_log(SDB_LOG_ERR, "plugin: Failed to determine current "
741 "time: %s", sdb_strerror(errno, errbuf, sizeof(errbuf)));
742 now = SDB_PLUGIN_CCB(obj)->ccb_next_update;
743 }
745 if (now > SDB_PLUGIN_CCB(obj)->ccb_next_update) {
746 sdb_log(SDB_LOG_WARNING, "plugin: Plugin '%s' took too "
747 "long; skipping iterations to keep up.",
748 obj->name);
749 SDB_PLUGIN_CCB(obj)->ccb_next_update = now;
750 }
752 if (sdb_llist_insert_sorted(collector_list, obj,
753 sdb_plugin_cmp_next_update)) {
754 sdb_log(SDB_LOG_ERR, "plugin: Failed to re-insert "
755 "plugin '%s' into collector list. Unable to further "
756 "use the plugin.",
757 obj->name);
758 sdb_object_deref(obj);
759 return -1;
760 }
762 /* pass control back to the list */
763 sdb_object_deref(obj);
764 }
765 return 0;
766 } /* sdb_plugin_read_loop */
768 char *
769 sdb_plugin_cname(char *hostname)
770 {
771 sdb_llist_iter_t *iter;
773 if (! hostname)
774 return NULL;
776 if (! cname_list)
777 return hostname;
779 iter = sdb_llist_get_iter(cname_list);
780 while (sdb_llist_iter_has_next(iter)) {
781 sdb_plugin_cname_cb callback;
782 char *cname;
784 sdb_object_t *obj = sdb_llist_iter_get_next(iter);
785 assert(obj);
787 callback = SDB_PLUGIN_CB(obj)->cb_callback;
788 cname = callback(hostname, SDB_PLUGIN_CB(obj)->cb_user_data);
789 if (cname) {
790 free(hostname);
791 hostname = cname;
792 }
793 /* else: don't change hostname */
794 }
795 sdb_llist_iter_destroy(iter);
796 return hostname;
797 } /* sdb_plugin_cname */
799 int
800 sdb_plugin_log(int prio, const char *msg)
801 {
802 sdb_llist_iter_t *iter;
803 int ret = -1;
805 if (! msg)
806 return 0;
808 if (! log_list)
809 return fprintf(stderr, "[%s] %s\n", SDB_LOG_PRIO_TO_STRING(prio), msg);
811 iter = sdb_llist_get_iter(log_list);
812 while (sdb_llist_iter_has_next(iter)) {
813 sdb_plugin_log_cb callback;
814 int tmp;
816 sdb_object_t *obj = sdb_llist_iter_get_next(iter);
817 assert(obj);
819 callback = SDB_PLUGIN_CB(obj)->cb_callback;
820 tmp = callback(prio, msg, SDB_PLUGIN_CB(obj)->cb_user_data);
821 if (tmp > ret)
822 ret = tmp;
823 }
824 sdb_llist_iter_destroy(iter);
825 return ret;
826 } /* sdb_plugin_log */
828 int
829 sdb_plugin_vlogf(int prio, const char *fmt, va_list ap)
830 {
831 sdb_strbuf_t *buf;
832 int ret;
834 if (! fmt)
835 return 0;
837 buf = sdb_strbuf_create(64);
838 if (! buf) {
839 ret = fprintf(stderr, "[%s] ", SDB_LOG_PRIO_TO_STRING(prio));
840 ret += vfprintf(stderr, fmt, ap);
841 return ret;
842 }
844 if (sdb_strbuf_vsprintf(buf, fmt, ap) < 0) {
845 sdb_strbuf_destroy(buf);
846 return -1;
847 }
849 ret = sdb_plugin_log(prio, sdb_strbuf_string(buf));
850 sdb_strbuf_destroy(buf);
851 return ret;
852 } /* sdb_plugin_vlogf */
854 int
855 sdb_plugin_logf(int prio, const char *fmt, ...)
856 {
857 va_list ap;
858 int ret;
860 if (! fmt)
861 return 0;
863 va_start(ap, fmt);
864 ret = sdb_plugin_vlogf(prio, fmt, ap);
865 va_end(ap);
866 return ret;
867 } /* sdb_plugin_logf */
869 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */