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 *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_PLUGIN_CCB(obj) ((sdb_plugin_collector_cb_t *)(obj))
108 /*
109 * private variables
110 */
112 static sdb_plugin_ctx_t plugin_default_ctx = SDB_PLUGIN_CTX_INIT;
113 static sdb_plugin_info_t plugin_default_info = SDB_PLUGIN_INFO_INIT;
115 static pthread_key_t plugin_ctx_key;
116 static _Bool plugin_ctx_key_initialized = 0;
118 static sdb_llist_t *config_list = NULL;
119 static sdb_llist_t *init_list = NULL;
120 static sdb_llist_t *collector_list = NULL;
121 static sdb_llist_t *cname_list = NULL;
122 static sdb_llist_t *shutdown_list = NULL;
123 static sdb_llist_t *log_list = NULL;
125 /*
126 * private helper functions
127 */
129 static void
130 sdb_plugin_info_clear(sdb_plugin_info_t *info)
131 {
132 sdb_plugin_info_t empty_info = SDB_PLUGIN_INFO_INIT;
133 if (! info)
134 return;
136 if (info->plugin_name)
137 free(info->plugin_name);
138 if (info->filename)
139 free(info->filename);
141 if (info->name)
142 free(info->name);
143 if (info->description)
144 free(info->description);
145 if (info->copyright)
146 free(info->copyright);
147 if (info->license)
148 free(info->license);
150 *info = empty_info;
151 } /* sdb_plugin_info_clear */
153 static void
154 ctx_key_init(void)
155 {
156 if (plugin_ctx_key_initialized)
157 return;
159 pthread_key_create(&plugin_ctx_key, /* destructor */ NULL);
160 plugin_ctx_key_initialized = 1;
161 } /* ctx_key_init */
163 static int
164 sdb_plugin_cmp_next_update(const sdb_object_t *a, const sdb_object_t *b)
165 {
166 const sdb_plugin_collector_cb_t *ccb1
167 = (const sdb_plugin_collector_cb_t *)a;
168 const sdb_plugin_collector_cb_t *ccb2
169 = (const sdb_plugin_collector_cb_t *)b;
171 assert(ccb1 && ccb2);
173 return (ccb1->ccb_next_update > ccb2->ccb_next_update)
174 ? 1 : (ccb1->ccb_next_update < ccb2->ccb_next_update)
175 ? -1 : 0;
176 } /* sdb_plugin_cmp_next_update */
178 /*
179 * private types
180 */
182 static int
183 ctx_init(sdb_object_t *obj, va_list __attribute__((unused)) ap)
184 {
185 ctx_t *ctx = CTX(obj);
187 assert(ctx);
189 ctx->public = plugin_default_ctx;
190 ctx->info = plugin_default_info;
191 return 0;
192 } /* ctx_init */
194 static void
195 ctx_destroy(sdb_object_t *obj)
196 {
197 ctx_t *ctx = CTX(obj);
198 sdb_plugin_info_clear(&ctx->info);
199 } /* ctx_destroy */
201 static sdb_type_t ctx_type = {
202 sizeof(ctx_t),
204 ctx_init,
205 ctx_destroy
206 };
208 static ctx_t *
209 ctx_create(void)
210 {
211 ctx_t *ctx;
213 ctx = CTX(sdb_object_create("plugin-context", ctx_type));
214 if (! ctx)
215 return NULL;
217 if (! plugin_ctx_key_initialized)
218 ctx_key_init();
219 pthread_setspecific(plugin_ctx_key, ctx);
220 return ctx;
221 } /* ctx_create */
223 static ctx_t *
224 ctx_get(void)
225 {
226 if (! plugin_ctx_key_initialized)
227 ctx_key_init();
228 return pthread_getspecific(plugin_ctx_key);
229 } /* ctx_get */
231 static ctx_t *
232 ctx_set(ctx_t *new)
233 {
234 ctx_t *old;
236 if (! plugin_ctx_key_initialized)
237 ctx_key_init();
239 old = pthread_getspecific(plugin_ctx_key);
240 pthread_setspecific(plugin_ctx_key, new);
241 return old;
242 } /* ctx_set */
244 static int
245 sdb_plugin_cb_init(sdb_object_t *obj, va_list ap)
246 {
247 sdb_llist_t **list = va_arg(ap, sdb_llist_t **);
248 const char *type = va_arg(ap, const char *);
249 void *callback = va_arg(ap, void *);
250 sdb_object_t *ud = va_arg(ap, sdb_object_t *);
252 assert(list);
253 assert(type);
254 assert(obj);
256 if (sdb_llist_search_by_name(*list, obj->name)) {
257 sdb_log(SDB_LOG_WARNING, "plugin: %s callback '%s' "
258 "has already been registered. Ignoring newly "
259 "registered version.", type, obj->name);
260 return -1;
261 }
263 SDB_PLUGIN_CB(obj)->cb_callback = callback;
264 SDB_PLUGIN_CB(obj)->cb_ctx = ctx_get();
265 sdb_object_ref(SDB_OBJ(SDB_PLUGIN_CB(obj)->cb_ctx));
267 sdb_object_ref(ud);
268 SDB_PLUGIN_CB(obj)->cb_user_data = ud;
269 return 0;
270 } /* sdb_plugin_cb_init */
272 static void
273 sdb_plugin_cb_destroy(sdb_object_t *obj)
274 {
275 assert(obj);
276 sdb_object_deref(SDB_PLUGIN_CB(obj)->cb_user_data);
277 sdb_object_deref(SDB_OBJ(SDB_PLUGIN_CB(obj)->cb_ctx));
278 } /* sdb_plugin_cb_destroy */
280 static sdb_type_t sdb_plugin_cb_type = {
281 sizeof(sdb_plugin_cb_t),
283 sdb_plugin_cb_init,
284 sdb_plugin_cb_destroy
285 };
287 static sdb_type_t sdb_plugin_collector_cb_type = {
288 sizeof(sdb_plugin_collector_cb_t),
290 sdb_plugin_cb_init,
291 sdb_plugin_cb_destroy
292 };
294 static int
295 sdb_plugin_add_callback(sdb_llist_t **list, const char *type,
296 const char *name, void *callback, sdb_object_t *user_data)
297 {
298 sdb_object_t *obj;
300 if ((! name) || (! callback))
301 return -1;
303 assert(list);
305 if (! *list)
306 *list = sdb_llist_create();
307 if (! *list)
308 return -1;
310 obj = sdb_object_create(name, sdb_plugin_cb_type,
311 list, type, callback, user_data);
312 if (! obj)
313 return -1;
315 if (sdb_llist_append(*list, obj)) {
316 sdb_object_deref(obj);
317 return -1;
318 }
320 /* pass control to the list */
321 sdb_object_deref(obj);
323 sdb_log(SDB_LOG_INFO, "plugin: Registered %s callback '%s'.",
324 type, name);
325 return 0;
326 } /* sdb_plugin_add_callback */
328 /*
329 * public API
330 */
332 int
333 sdb_plugin_load(const char *name, const sdb_plugin_ctx_t *plugin_ctx)
334 {
335 char real_name[strlen(name) > 0 ? strlen(name) : 1];
336 const char *name_ptr;
337 char *tmp;
339 char filename[1024];
340 ctx_t *ctx;
342 lt_dlhandle lh;
344 int (*mod_init)(sdb_plugin_info_t *);
345 int status;
347 if ((! name) || (! *name))
348 return -1;
350 real_name[0] = '\0';
351 name_ptr = name;
353 while ((tmp = strstr(name_ptr, "::"))) {
354 strncat(real_name, name_ptr, (size_t)(tmp - name_ptr));
355 strcat(real_name, "/");
356 name_ptr = tmp + strlen("::");
357 }
358 strcat(real_name, name_ptr);
360 snprintf(filename, sizeof(filename), "%s/%s.so",
361 PKGLIBDIR, real_name);
362 filename[sizeof(filename) - 1] = '\0';
364 if (access(filename, R_OK)) {
365 char errbuf[1024];
366 sdb_log(SDB_LOG_ERR, "plugin: Failed to load plugin '%s' (%s): %s",
367 name, filename, sdb_strerror(errno, errbuf, sizeof(errbuf)));
368 return -1;
369 }
371 lt_dlinit();
372 lt_dlerror();
374 lh = lt_dlopen(filename);
375 if (! lh) {
376 sdb_log(SDB_LOG_ERR, "plugin: Failed to load plugin '%s': %s"
377 "The most common cause for this problem are missing "
378 "dependencies.\n", name, lt_dlerror());
379 return -1;
380 }
382 if (ctx_get())
383 sdb_log(SDB_LOG_WARNING, "plugin: Discarding old plugin context");
385 ctx = ctx_create();
386 if (! ctx) {
387 sdb_log(SDB_LOG_ERR, "plugin: Failed to initialize plugin context");
388 return -1;
389 }
391 ctx->info.plugin_name = strdup(name);
392 ctx->info.filename = strdup(filename);
394 if (plugin_ctx)
395 ctx->public = *plugin_ctx;
397 mod_init = (int (*)(sdb_plugin_info_t *))lt_dlsym(lh, "sdb_module_init");
398 if (! mod_init) {
399 sdb_log(SDB_LOG_ERR, "plugin: Failed to load plugin '%s': "
400 "could not find symbol 'sdb_module_init'", name);
401 sdb_object_deref(SDB_OBJ(ctx));
402 return -1;
403 }
405 status = mod_init(&ctx->info);
406 if (status) {
407 sdb_log(SDB_LOG_ERR, "plugin: Failed to initialize "
408 "plugin '%s'", name);
409 sdb_object_deref(SDB_OBJ(ctx));
410 return -1;
411 }
413 /* compare minor version */
414 if ((ctx->info.version < 0)
415 || ((int)(ctx->info.version / 100) != (int)(SDB_VERSION / 100)))
416 sdb_log(SDB_LOG_WARNING, "plugin: WARNING: version of "
417 "plugin '%s' (%i.%i.%i) does not match our version "
418 "(%i.%i.%i); this might cause problems",
419 name, SDB_VERSION_DECODE(ctx->info.version),
420 SDB_VERSION_DECODE(SDB_VERSION));
422 sdb_log(SDB_LOG_INFO, "plugin: Successfully loaded "
423 "plugin '%s' v%i (%s)\n\t%s\n\tLicense: %s",
424 INFO_GET(&ctx->info, name), ctx->info.plugin_version,
425 INFO_GET(&ctx->info, description),
426 INFO_GET(&ctx->info, copyright),
427 INFO_GET(&ctx->info, license));
429 /* any registered callbacks took ownership of the context */
430 sdb_object_deref(SDB_OBJ(ctx));
432 /* reset */
433 ctx_set(NULL);
434 return 0;
435 } /* sdb_plugin_load */
437 int
438 sdb_plugin_set_info(sdb_plugin_info_t *info, int type, ...)
439 {
440 va_list ap;
442 if (! info)
443 return -1;
445 va_start(ap, type);
447 switch (type) {
448 case SDB_PLUGIN_INFO_NAME:
449 {
450 char *name = va_arg(ap, char *);
451 if (name) {
452 if (info->name)
453 free(info->name);
454 info->name = strdup(name);
455 }
456 }
457 break;
458 case SDB_PLUGIN_INFO_DESC:
459 {
460 char *desc = va_arg(ap, char *);
461 if (desc) {
462 if (info->description)
463 free(info->description);
464 info->description = strdup(desc);
465 }
466 }
467 break;
468 case SDB_PLUGIN_INFO_COPYRIGHT:
469 {
470 char *copyright = va_arg(ap, char *);
471 if (copyright)
472 info->copyright = strdup(copyright);
473 }
474 break;
475 case SDB_PLUGIN_INFO_LICENSE:
476 {
477 char *license = va_arg(ap, char *);
478 if (license) {
479 if (info->license)
480 free(info->license);
481 info->license = strdup(license);
482 }
483 }
484 break;
485 case SDB_PLUGIN_INFO_VERSION:
486 {
487 int version = va_arg(ap, int);
488 info->version = version;
489 }
490 break;
491 case SDB_PLUGIN_INFO_PLUGIN_VERSION:
492 {
493 int version = va_arg(ap, int);
494 info->plugin_version = version;
495 }
496 break;
497 default:
498 va_end(ap);
499 return -1;
500 }
502 va_end(ap);
503 return 0;
504 } /* sdb_plugin_set_info */
506 int
507 sdb_plugin_register_config(const char *name, sdb_plugin_config_cb callback)
508 {
509 return sdb_plugin_add_callback(&config_list, "init", name,
510 callback, NULL);
511 } /* sdb_plugin_register_config */
513 int
514 sdb_plugin_register_init(const char *name, sdb_plugin_init_cb callback,
515 sdb_object_t *user_data)
516 {
517 return sdb_plugin_add_callback(&init_list, "init", name,
518 callback, user_data);
519 } /* sdb_plugin_register_init */
521 int
522 sdb_plugin_register_shutdown(const char *name, sdb_plugin_shutdown_cb callback,
523 sdb_object_t *user_data)
524 {
525 return sdb_plugin_add_callback(&shutdown_list, "shutdown", name,
526 callback, user_data);
527 } /* sdb_plugin_register_shutdown */
529 int
530 sdb_plugin_register_log(const char *name, sdb_plugin_log_cb callback,
531 sdb_object_t *user_data)
532 {
533 return sdb_plugin_add_callback(&log_list, "log", name, callback,
534 user_data);
535 } /* sdb_plugin_register_log */
537 int
538 sdb_plugin_register_cname(const char *name, sdb_plugin_cname_cb callback,
539 sdb_object_t *user_data)
540 {
541 return sdb_plugin_add_callback(&cname_list, "cname", name, callback,
542 user_data);
543 } /* sdb_plugin_register_cname */
545 int
546 sdb_plugin_register_collector(const char *name, sdb_plugin_collector_cb callback,
547 const sdb_time_t *interval, sdb_object_t *user_data)
548 {
549 sdb_object_t *obj;
551 if ((! name) || (! callback))
552 return -1;
554 if (! collector_list)
555 collector_list = sdb_llist_create();
556 if (! collector_list)
557 return -1;
559 obj = sdb_object_create(name, sdb_plugin_collector_cb_type,
560 &collector_list, "collector", callback, user_data);
561 if (! obj)
562 return -1;
564 if (interval)
565 SDB_PLUGIN_CCB(obj)->ccb_interval = *interval;
566 else {
567 sdb_time_t tmp = sdb_plugin_get_ctx().interval;
569 if (tmp > 0)
570 SDB_PLUGIN_CCB(obj)->ccb_interval = tmp;
571 else
572 SDB_PLUGIN_CCB(obj)->ccb_interval = 0;
573 }
575 if (! (SDB_PLUGIN_CCB(obj)->ccb_next_update = sdb_gettime())) {
576 char errbuf[1024];
577 sdb_log(SDB_LOG_ERR, "plugin: Failed to determine current "
578 "time: %s", sdb_strerror(errno, errbuf, sizeof(errbuf)));
579 sdb_object_deref(obj);
580 return -1;
581 }
583 if (sdb_llist_insert_sorted(collector_list, obj,
584 sdb_plugin_cmp_next_update)) {
585 sdb_object_deref(obj);
586 return -1;
587 }
589 /* pass control to the list */
590 sdb_object_deref(obj);
592 sdb_log(SDB_LOG_INFO, "plugin: Registered collector callback '%s' "
593 "(interval = %.3fs).", name,
594 SDB_TIME_TO_DOUBLE(SDB_PLUGIN_CCB(obj)->ccb_interval));
595 return 0;
596 } /* sdb_plugin_register_collector */
598 sdb_plugin_ctx_t
599 sdb_plugin_get_ctx(void)
600 {
601 ctx_t *c;
603 c = ctx_get();
604 if (! c) {
605 sdb_plugin_log(SDB_LOG_ERR, "plugin: Invalid read access to plugin "
606 "context outside a plugin");
607 return plugin_default_ctx;
608 }
609 return c->public;
610 } /* sdb_plugin_get_ctx */
612 int
613 sdb_plugin_set_ctx(sdb_plugin_ctx_t ctx, sdb_plugin_ctx_t *old)
614 {
615 ctx_t *c;
617 c = ctx_get();
618 if (! c) {
619 sdb_plugin_log(SDB_LOG_ERR, "plugin: Invalid write access to plugin "
620 "context outside a plugin");
621 return -1;
622 }
624 if (old)
625 *old = c->public;
626 c->public = ctx;
627 return 0;
628 } /* sdb_plugin_set_ctx */
630 int
631 sdb_plugin_configure(const char *name, oconfig_item_t *ci)
632 {
633 sdb_plugin_cb_t *plugin;
634 sdb_plugin_config_cb callback;
636 ctx_t *old_ctx;
638 int status;
640 if ((! name) || (! ci))
641 return -1;
643 plugin = SDB_PLUGIN_CB(sdb_llist_search_by_name(config_list, name));
644 if (! plugin) {
645 /* XXX: check if any such plugin has been loaded */
646 sdb_log(SDB_LOG_ERR, "plugin: Plugin '%s' did not register "
647 "a config callback.", name);
648 errno = ENOENT;
649 return -1;
650 }
652 old_ctx = ctx_set(plugin->cb_ctx);
653 callback = plugin->cb_callback;
654 status = callback(ci);
655 ctx_set(old_ctx);
656 return status;
657 } /* sdb_plugin_configure */
659 int
660 sdb_plugin_init_all(void)
661 {
662 sdb_llist_iter_t *iter;
664 iter = sdb_llist_get_iter(init_list);
665 while (sdb_llist_iter_has_next(iter)) {
666 sdb_plugin_init_cb callback;
667 ctx_t *old_ctx;
669 sdb_object_t *obj = sdb_llist_iter_get_next(iter);
670 assert(obj);
672 callback = SDB_PLUGIN_CB(obj)->cb_callback;
674 old_ctx = ctx_set(SDB_PLUGIN_CB(obj)->cb_ctx);
675 if (callback(SDB_PLUGIN_CB(obj)->cb_user_data)) {
676 /* XXX: unload plugin */
677 }
678 ctx_set(old_ctx);
679 }
680 sdb_llist_iter_destroy(iter);
681 return 0;
682 } /* sdb_plugin_init_all */
684 int
685 sdb_plugin_collector_loop(sdb_plugin_loop_t *loop)
686 {
687 if (! collector_list) {
688 sdb_log(SDB_LOG_WARNING, "plugin: No collectors registered. "
689 "Quiting main loop.");
690 return -1;
691 }
693 if (! loop)
694 return -1;
696 while (loop->do_loop) {
697 sdb_plugin_collector_cb callback;
698 ctx_t *old_ctx;
700 sdb_time_t interval, now;
702 sdb_object_t *obj = sdb_llist_shift(collector_list);
703 if (! obj)
704 return -1;
706 callback = SDB_PLUGIN_CCB(obj)->ccb_callback;
708 if (! (now = sdb_gettime())) {
709 char errbuf[1024];
710 sdb_log(SDB_LOG_ERR, "plugin: Failed to determine current "
711 "time: %s", sdb_strerror(errno, errbuf, sizeof(errbuf)));
712 now = SDB_PLUGIN_CCB(obj)->ccb_next_update;
713 }
715 if (now < SDB_PLUGIN_CCB(obj)->ccb_next_update) {
716 interval = SDB_PLUGIN_CCB(obj)->ccb_next_update - now;
718 errno = 0;
719 while (loop->do_loop && sdb_sleep(interval, &interval)) {
720 if (errno != EINTR) {
721 char errbuf[1024];
722 sdb_log(SDB_LOG_ERR, "plugin: Failed to sleep: %s",
723 sdb_strerror(errno, errbuf, sizeof(errbuf)));
724 return -1;
725 }
726 errno = 0;
727 }
729 if (! loop->do_loop)
730 return 0;
731 }
733 old_ctx = ctx_set(SDB_PLUGIN_CCB(obj)->ccb_ctx);
734 if (callback(SDB_PLUGIN_CCB(obj)->ccb_user_data)) {
735 /* XXX */
736 }
737 ctx_set(old_ctx);
739 interval = SDB_PLUGIN_CCB(obj)->ccb_interval;
740 if (! interval)
741 interval = loop->default_interval;
742 if (! interval) {
743 sdb_log(SDB_LOG_WARNING, "plugin: No interval configured "
744 "for plugin '%s'; skipping any further "
745 "iterations.", obj->name);
746 sdb_object_deref(obj);
747 continue;
748 }
750 SDB_PLUGIN_CCB(obj)->ccb_next_update += interval;
752 if (! (now = sdb_gettime())) {
753 char errbuf[1024];
754 sdb_log(SDB_LOG_ERR, "plugin: Failed to determine current "
755 "time: %s", sdb_strerror(errno, errbuf, sizeof(errbuf)));
756 now = SDB_PLUGIN_CCB(obj)->ccb_next_update;
757 }
759 if (now > SDB_PLUGIN_CCB(obj)->ccb_next_update) {
760 sdb_log(SDB_LOG_WARNING, "plugin: Plugin '%s' took too "
761 "long; skipping iterations to keep up.",
762 obj->name);
763 SDB_PLUGIN_CCB(obj)->ccb_next_update = now;
764 }
766 if (sdb_llist_insert_sorted(collector_list, obj,
767 sdb_plugin_cmp_next_update)) {
768 sdb_log(SDB_LOG_ERR, "plugin: Failed to re-insert "
769 "plugin '%s' into collector list. Unable to further "
770 "use the plugin.",
771 obj->name);
772 sdb_object_deref(obj);
773 return -1;
774 }
776 /* pass control back to the list */
777 sdb_object_deref(obj);
778 }
779 return 0;
780 } /* sdb_plugin_read_loop */
782 char *
783 sdb_plugin_cname(char *hostname)
784 {
785 sdb_llist_iter_t *iter;
787 if (! hostname)
788 return NULL;
790 if (! cname_list)
791 return hostname;
793 iter = sdb_llist_get_iter(cname_list);
794 while (sdb_llist_iter_has_next(iter)) {
795 sdb_plugin_cname_cb callback;
796 char *cname;
798 sdb_object_t *obj = sdb_llist_iter_get_next(iter);
799 assert(obj);
801 callback = SDB_PLUGIN_CB(obj)->cb_callback;
802 cname = callback(hostname, SDB_PLUGIN_CB(obj)->cb_user_data);
803 if (cname) {
804 free(hostname);
805 hostname = cname;
806 }
807 /* else: don't change hostname */
808 }
809 sdb_llist_iter_destroy(iter);
810 return hostname;
811 } /* sdb_plugin_cname */
813 int
814 sdb_plugin_log(int prio, const char *msg)
815 {
816 sdb_llist_iter_t *iter;
817 int ret = -1;
819 if (! msg)
820 return 0;
822 if (! log_list)
823 return fprintf(stderr, "[%s] %s\n", SDB_LOG_PRIO_TO_STRING(prio), msg);
825 iter = sdb_llist_get_iter(log_list);
826 while (sdb_llist_iter_has_next(iter)) {
827 sdb_plugin_log_cb callback;
828 int tmp;
830 sdb_object_t *obj = sdb_llist_iter_get_next(iter);
831 assert(obj);
833 callback = SDB_PLUGIN_CB(obj)->cb_callback;
834 tmp = callback(prio, msg, SDB_PLUGIN_CB(obj)->cb_user_data);
835 if (tmp > ret)
836 ret = tmp;
837 }
838 sdb_llist_iter_destroy(iter);
839 return ret;
840 } /* sdb_plugin_log */
842 int
843 sdb_plugin_vlogf(int prio, const char *fmt, va_list ap)
844 {
845 sdb_strbuf_t *buf;
846 int ret;
848 if (! fmt)
849 return 0;
851 buf = sdb_strbuf_create(64);
852 if (! buf) {
853 ret = fprintf(stderr, "[%s] ", SDB_LOG_PRIO_TO_STRING(prio));
854 ret += vfprintf(stderr, fmt, ap);
855 return ret;
856 }
858 if (sdb_strbuf_vsprintf(buf, fmt, ap) < 0) {
859 sdb_strbuf_destroy(buf);
860 return -1;
861 }
863 ret = sdb_plugin_log(prio, sdb_strbuf_string(buf));
864 sdb_strbuf_destroy(buf);
865 return ret;
866 } /* sdb_plugin_vlogf */
868 int
869 sdb_plugin_logf(int prio, const char *fmt, ...)
870 {
871 va_list ap;
872 int ret;
874 if (! fmt)
875 return 0;
877 va_start(ap, fmt);
878 ret = sdb_plugin_vlogf(prio, fmt, ap);
879 va_end(ap);
880 return ret;
881 } /* sdb_plugin_logf */
883 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */