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;
72 } ctx_t;
73 #define CTX_INIT { SDB_OBJECT_INIT, \
74 SDB_PLUGIN_CTX_INIT }
76 #define CTX(obj) ((ctx_t *)(obj))
78 typedef struct {
79 sdb_object_t super;
80 void *cb_callback;
81 sdb_object_t *cb_user_data;
82 ctx_t *cb_ctx;
83 } sdb_plugin_cb_t;
84 #define SDB_PLUGIN_CB_INIT { SDB_OBJECT_INIT, \
85 /* callback = */ NULL, /* user_data = */ NULL, \
86 SDB_PLUGIN_CTX_INIT }
88 typedef struct {
89 sdb_plugin_cb_t super;
90 #define ccb_callback super.cb_callback
91 #define ccb_user_data super.cb_user_data
92 #define ccb_ctx super.cb_ctx
93 sdb_time_t ccb_interval;
94 sdb_time_t ccb_next_update;
95 } sdb_plugin_collector_cb_t;
97 #define SDB_PLUGIN_CB(obj) ((sdb_plugin_cb_t *)(obj))
98 #define SDB_PLUGIN_CCB(obj) ((sdb_plugin_collector_cb_t *)(obj))
100 /*
101 * private variables
102 */
104 static sdb_plugin_ctx_t plugin_default_ctx = SDB_PLUGIN_CTX_INIT;
106 static pthread_key_t plugin_ctx_key;
107 static _Bool plugin_ctx_key_initialized = 0;
109 static sdb_llist_t *config_list = NULL;
110 static sdb_llist_t *init_list = NULL;
111 static sdb_llist_t *collector_list = NULL;
112 static sdb_llist_t *cname_list = NULL;
113 static sdb_llist_t *shutdown_list = NULL;
114 static sdb_llist_t *log_list = NULL;
116 /*
117 * private helper functions
118 */
120 static void
121 sdb_plugin_info_clear(sdb_plugin_info_t *info)
122 {
123 sdb_plugin_info_t empty_info = SDB_PLUGIN_INFO_INIT;
124 if (! info)
125 return;
127 if (info->name)
128 free(info->name);
129 if (info->description)
130 free(info->description);
131 if (info->copyright)
132 free(info->copyright);
133 if (info->license)
134 free(info->license);
136 *info = empty_info;
137 } /* sdb_plugin_info_clear */
139 static void
140 ctx_key_init(void)
141 {
142 if (plugin_ctx_key_initialized)
143 return;
145 pthread_key_create(&plugin_ctx_key, /* destructor */ NULL);
146 plugin_ctx_key_initialized = 1;
147 } /* ctx_key_init */
149 static int
150 sdb_plugin_cmp_next_update(const sdb_object_t *a, const sdb_object_t *b)
151 {
152 const sdb_plugin_collector_cb_t *ccb1
153 = (const sdb_plugin_collector_cb_t *)a;
154 const sdb_plugin_collector_cb_t *ccb2
155 = (const sdb_plugin_collector_cb_t *)b;
157 assert(ccb1 && ccb2);
159 return (ccb1->ccb_next_update > ccb2->ccb_next_update)
160 ? 1 : (ccb1->ccb_next_update < ccb2->ccb_next_update)
161 ? -1 : 0;
162 } /* sdb_plugin_cmp_next_update */
164 /*
165 * private types
166 */
168 static int
169 ctx_init(sdb_object_t *obj, va_list __attribute__((unused)) ap)
170 {
171 ctx_t *ctx = CTX(obj);
173 assert(ctx);
175 ctx->public = plugin_default_ctx;
176 return 0;
177 } /* ctx_init */
179 static sdb_type_t ctx_type = {
180 sizeof(ctx_t),
182 ctx_init,
183 NULL
184 };
186 static ctx_t *
187 ctx_create(void)
188 {
189 ctx_t *ctx;
191 ctx = CTX(sdb_object_create("plugin-context", ctx_type));
192 if (! ctx)
193 return NULL;
195 if (! plugin_ctx_key_initialized)
196 ctx_key_init();
197 pthread_setspecific(plugin_ctx_key, ctx);
198 return ctx;
199 } /* ctx_create */
201 static ctx_t *
202 ctx_get(void)
203 {
204 if (! plugin_ctx_key_initialized)
205 ctx_key_init();
206 return pthread_getspecific(plugin_ctx_key);
207 } /* ctx_get */
209 static ctx_t *
210 ctx_set(ctx_t *new)
211 {
212 ctx_t *old;
214 if (! plugin_ctx_key_initialized)
215 ctx_key_init();
217 old = pthread_getspecific(plugin_ctx_key);
218 pthread_setspecific(plugin_ctx_key, new);
219 return old;
220 } /* ctx_set */
222 static int
223 sdb_plugin_cb_init(sdb_object_t *obj, va_list ap)
224 {
225 sdb_llist_t **list = va_arg(ap, sdb_llist_t **);
226 const char *type = va_arg(ap, const char *);
227 void *callback = va_arg(ap, void *);
228 sdb_object_t *ud = va_arg(ap, sdb_object_t *);
230 assert(list);
231 assert(type);
232 assert(obj);
234 if (sdb_llist_search_by_name(*list, obj->name)) {
235 sdb_log(SDB_LOG_WARNING, "plugin: %s callback '%s' "
236 "has already been registered. Ignoring newly "
237 "registered version.", type, obj->name);
238 return -1;
239 }
241 SDB_PLUGIN_CB(obj)->cb_callback = callback;
242 SDB_PLUGIN_CB(obj)->cb_ctx = ctx_get();
243 sdb_object_ref(SDB_OBJ(SDB_PLUGIN_CB(obj)->cb_ctx));
245 sdb_object_ref(ud);
246 SDB_PLUGIN_CB(obj)->cb_user_data = ud;
247 return 0;
248 } /* sdb_plugin_cb_init */
250 static void
251 sdb_plugin_cb_destroy(sdb_object_t *obj)
252 {
253 assert(obj);
254 sdb_object_deref(SDB_PLUGIN_CB(obj)->cb_user_data);
255 sdb_object_deref(SDB_OBJ(SDB_PLUGIN_CB(obj)->cb_ctx));
256 } /* sdb_plugin_cb_destroy */
258 static sdb_type_t sdb_plugin_cb_type = {
259 sizeof(sdb_plugin_cb_t),
261 sdb_plugin_cb_init,
262 sdb_plugin_cb_destroy
263 };
265 static sdb_type_t sdb_plugin_collector_cb_type = {
266 sizeof(sdb_plugin_collector_cb_t),
268 sdb_plugin_cb_init,
269 sdb_plugin_cb_destroy
270 };
272 static int
273 sdb_plugin_add_callback(sdb_llist_t **list, const char *type,
274 const char *name, void *callback, sdb_object_t *user_data)
275 {
276 sdb_object_t *obj;
278 if ((! name) || (! callback))
279 return -1;
281 assert(list);
283 if (! *list)
284 *list = sdb_llist_create();
285 if (! *list)
286 return -1;
288 obj = sdb_object_create(name, sdb_plugin_cb_type,
289 list, type, callback, user_data);
290 if (! obj)
291 return -1;
293 if (sdb_llist_append(*list, obj)) {
294 sdb_object_deref(obj);
295 return -1;
296 }
298 /* pass control to the list */
299 sdb_object_deref(obj);
301 sdb_log(SDB_LOG_INFO, "plugin: Registered %s callback '%s'.",
302 type, name);
303 return 0;
304 } /* sdb_plugin_add_callback */
306 /*
307 * public API
308 */
310 int
311 sdb_plugin_load(const char *name, const sdb_plugin_ctx_t *plugin_ctx)
312 {
313 char real_name[strlen(name) > 0 ? strlen(name) : 1];
314 const char *name_ptr;
315 char *tmp;
317 char filename[1024];
318 ctx_t *ctx;
320 lt_dlhandle lh;
322 int (*mod_init)(sdb_plugin_info_t *);
323 sdb_plugin_info_t info = SDB_PLUGIN_INFO_INIT;
325 int status;
327 if ((! name) || (! *name))
328 return -1;
330 real_name[0] = '\0';
331 name_ptr = name;
333 while ((tmp = strstr(name_ptr, "::"))) {
334 strncat(real_name, name_ptr, (size_t)(tmp - name_ptr));
335 strcat(real_name, "/");
336 name_ptr = tmp + strlen("::");
337 }
338 strcat(real_name, name_ptr);
340 snprintf(filename, sizeof(filename), "%s/%s.so",
341 PKGLIBDIR, real_name);
342 filename[sizeof(filename) - 1] = '\0';
344 if (access(filename, R_OK)) {
345 char errbuf[1024];
346 sdb_log(SDB_LOG_ERR, "plugin: Failed to load plugin '%s' (%s): %s",
347 name, filename, sdb_strerror(errno, errbuf, sizeof(errbuf)));
348 return -1;
349 }
351 lt_dlinit();
352 lt_dlerror();
354 lh = lt_dlopen(filename);
355 if (! lh) {
356 sdb_log(SDB_LOG_ERR, "plugin: Failed to load plugin '%s': %s"
357 "The most common cause for this problem are missing "
358 "dependencies.\n", name, lt_dlerror());
359 return -1;
360 }
362 if (ctx_get())
363 sdb_log(SDB_LOG_WARNING, "plugin: Discarding old plugin context");
365 ctx = ctx_create();
366 if (! ctx) {
367 sdb_log(SDB_LOG_ERR, "plugin: Failed to initialize plugin context");
368 return -1;
369 }
371 if (plugin_ctx)
372 ctx->public = *plugin_ctx;
374 mod_init = (int (*)(sdb_plugin_info_t *))lt_dlsym(lh, "sdb_module_init");
375 if (! mod_init) {
376 sdb_log(SDB_LOG_ERR, "plugin: Failed to load plugin '%s': "
377 "could not find symbol 'sdb_module_init'", name);
378 sdb_object_deref(SDB_OBJ(ctx));
379 return -1;
380 }
382 status = mod_init(&info);
383 if (status) {
384 sdb_log(SDB_LOG_ERR, "plugin: Failed to initialize "
385 "plugin '%s'", name);
386 sdb_plugin_info_clear(&info);
387 sdb_object_deref(SDB_OBJ(ctx));
388 return -1;
389 }
391 /* compare minor version */
392 if ((info.version < 0)
393 || ((int)(info.version / 100) != (int)(SDB_VERSION / 100)))
394 sdb_log(SDB_LOG_WARNING, "plugin: WARNING: version of "
395 "plugin '%s' (%i.%i.%i) does not match our version "
396 "(%i.%i.%i); this might cause problems",
397 name, SDB_VERSION_DECODE(info.version),
398 SDB_VERSION_DECODE(SDB_VERSION));
400 sdb_log(SDB_LOG_INFO, "plugin: Successfully loaded "
401 "plugin '%s' v%i (%s)\n\t%s\n\tLicense: %s",
402 INFO_GET(&info, name), info.plugin_version,
403 INFO_GET(&info, description),
404 INFO_GET(&info, copyright),
405 INFO_GET(&info, license));
407 sdb_plugin_info_clear(&info);
408 /* any registered callbacks took ownership of the context */
409 sdb_object_deref(SDB_OBJ(ctx));
411 /* reset */
412 ctx_set(NULL);
413 return 0;
414 } /* sdb_plugin_load */
416 int
417 sdb_plugin_set_info(sdb_plugin_info_t *info, int type, ...)
418 {
419 va_list ap;
421 if (! info)
422 return -1;
424 va_start(ap, type);
426 switch (type) {
427 case SDB_PLUGIN_INFO_NAME:
428 {
429 char *name = va_arg(ap, char *);
430 if (name) {
431 if (info->name)
432 free(info->name);
433 info->name = strdup(name);
434 }
435 }
436 break;
437 case SDB_PLUGIN_INFO_DESC:
438 {
439 char *desc = va_arg(ap, char *);
440 if (desc) {
441 if (info->description)
442 free(info->description);
443 info->description = strdup(desc);
444 }
445 }
446 break;
447 case SDB_PLUGIN_INFO_COPYRIGHT:
448 {
449 char *copyright = va_arg(ap, char *);
450 if (copyright)
451 info->copyright = strdup(copyright);
452 }
453 break;
454 case SDB_PLUGIN_INFO_LICENSE:
455 {
456 char *license = va_arg(ap, char *);
457 if (license) {
458 if (info->license)
459 free(info->license);
460 info->license = strdup(license);
461 }
462 }
463 break;
464 case SDB_PLUGIN_INFO_VERSION:
465 {
466 int version = va_arg(ap, int);
467 info->version = version;
468 }
469 break;
470 case SDB_PLUGIN_INFO_PLUGIN_VERSION:
471 {
472 int version = va_arg(ap, int);
473 info->plugin_version = version;
474 }
475 break;
476 default:
477 va_end(ap);
478 return -1;
479 }
481 va_end(ap);
482 return 0;
483 } /* sdb_plugin_set_info */
485 int
486 sdb_plugin_register_config(const char *name, sdb_plugin_config_cb callback)
487 {
488 return sdb_plugin_add_callback(&config_list, "init", name,
489 callback, NULL);
490 } /* sdb_plugin_register_config */
492 int
493 sdb_plugin_register_init(const char *name, sdb_plugin_init_cb callback,
494 sdb_object_t *user_data)
495 {
496 return sdb_plugin_add_callback(&init_list, "init", name,
497 callback, user_data);
498 } /* sdb_plugin_register_init */
500 int
501 sdb_plugin_register_shutdown(const char *name, sdb_plugin_shutdown_cb callback,
502 sdb_object_t *user_data)
503 {
504 return sdb_plugin_add_callback(&shutdown_list, "shutdown", name,
505 callback, user_data);
506 } /* sdb_plugin_register_shutdown */
508 int
509 sdb_plugin_register_log(const char *name, sdb_plugin_log_cb callback,
510 sdb_object_t *user_data)
511 {
512 return sdb_plugin_add_callback(&log_list, "log", name, callback,
513 user_data);
514 } /* sdb_plugin_register_log */
516 int
517 sdb_plugin_register_cname(const char *name, sdb_plugin_cname_cb callback,
518 sdb_object_t *user_data)
519 {
520 return sdb_plugin_add_callback(&cname_list, "cname", name, callback,
521 user_data);
522 } /* sdb_plugin_register_cname */
524 int
525 sdb_plugin_register_collector(const char *name, sdb_plugin_collector_cb callback,
526 const sdb_time_t *interval, sdb_object_t *user_data)
527 {
528 sdb_object_t *obj;
530 if ((! name) || (! callback))
531 return -1;
533 if (! collector_list)
534 collector_list = sdb_llist_create();
535 if (! collector_list)
536 return -1;
538 obj = sdb_object_create(name, sdb_plugin_collector_cb_type,
539 &collector_list, "collector", callback, user_data);
540 if (! obj)
541 return -1;
543 if (interval)
544 SDB_PLUGIN_CCB(obj)->ccb_interval = *interval;
545 else {
546 sdb_time_t tmp = sdb_plugin_get_ctx().interval;
548 if (tmp > 0)
549 SDB_PLUGIN_CCB(obj)->ccb_interval = tmp;
550 else
551 SDB_PLUGIN_CCB(obj)->ccb_interval = 0;
552 }
554 if (! (SDB_PLUGIN_CCB(obj)->ccb_next_update = sdb_gettime())) {
555 char errbuf[1024];
556 sdb_log(SDB_LOG_ERR, "plugin: Failed to determine current "
557 "time: %s", sdb_strerror(errno, errbuf, sizeof(errbuf)));
558 sdb_object_deref(obj);
559 return -1;
560 }
562 if (sdb_llist_insert_sorted(collector_list, obj,
563 sdb_plugin_cmp_next_update)) {
564 sdb_object_deref(obj);
565 return -1;
566 }
568 /* pass control to the list */
569 sdb_object_deref(obj);
571 sdb_log(SDB_LOG_INFO, "plugin: Registered collector callback '%s' "
572 "(interval = %.3fs).", name,
573 SDB_TIME_TO_DOUBLE(SDB_PLUGIN_CCB(obj)->ccb_interval));
574 return 0;
575 } /* sdb_plugin_register_collector */
577 sdb_plugin_ctx_t
578 sdb_plugin_get_ctx(void)
579 {
580 ctx_t *c;
582 c = ctx_get();
583 if (! c) {
584 sdb_plugin_log(SDB_LOG_ERR, "plugin: Invalid read access to plugin "
585 "context outside a plugin");
586 return plugin_default_ctx;
587 }
588 return c->public;
589 } /* sdb_plugin_get_ctx */
591 int
592 sdb_plugin_set_ctx(sdb_plugin_ctx_t ctx, sdb_plugin_ctx_t *old)
593 {
594 ctx_t *c;
596 c = ctx_get();
597 if (! c) {
598 sdb_plugin_log(SDB_LOG_ERR, "plugin: Invalid write access to plugin "
599 "context outside a plugin");
600 return -1;
601 }
603 if (old)
604 *old = c->public;
605 c->public = ctx;
606 return 0;
607 } /* sdb_plugin_set_ctx */
609 int
610 sdb_plugin_configure(const char *name, oconfig_item_t *ci)
611 {
612 sdb_plugin_cb_t *plugin;
613 sdb_plugin_config_cb callback;
615 ctx_t *old_ctx;
617 int status;
619 if ((! name) || (! ci))
620 return -1;
622 plugin = SDB_PLUGIN_CB(sdb_llist_search_by_name(config_list, name));
623 if (! plugin) {
624 /* XXX: check if any such plugin has been loaded */
625 sdb_log(SDB_LOG_ERR, "plugin: Plugin '%s' did not register "
626 "a config callback.", name);
627 errno = ENOENT;
628 return -1;
629 }
631 old_ctx = ctx_set(plugin->cb_ctx);
632 callback = plugin->cb_callback;
633 status = callback(ci);
634 ctx_set(old_ctx);
635 return status;
636 } /* sdb_plugin_configure */
638 int
639 sdb_plugin_init_all(void)
640 {
641 sdb_llist_iter_t *iter;
643 iter = sdb_llist_get_iter(init_list);
644 while (sdb_llist_iter_has_next(iter)) {
645 sdb_plugin_init_cb callback;
646 ctx_t *old_ctx;
648 sdb_object_t *obj = sdb_llist_iter_get_next(iter);
649 assert(obj);
651 callback = SDB_PLUGIN_CB(obj)->cb_callback;
653 old_ctx = ctx_set(SDB_PLUGIN_CB(obj)->cb_ctx);
654 if (callback(SDB_PLUGIN_CB(obj)->cb_user_data)) {
655 /* XXX: unload plugin */
656 }
657 ctx_set(old_ctx);
658 }
659 sdb_llist_iter_destroy(iter);
660 return 0;
661 } /* sdb_plugin_init_all */
663 int
664 sdb_plugin_collector_loop(sdb_plugin_loop_t *loop)
665 {
666 if (! collector_list) {
667 sdb_log(SDB_LOG_WARNING, "plugin: No collectors registered. "
668 "Quiting main loop.");
669 return -1;
670 }
672 if (! loop)
673 return -1;
675 while (loop->do_loop) {
676 sdb_plugin_collector_cb callback;
677 ctx_t *old_ctx;
679 sdb_time_t interval, now;
681 sdb_object_t *obj = sdb_llist_shift(collector_list);
682 if (! obj)
683 return -1;
685 callback = SDB_PLUGIN_CCB(obj)->ccb_callback;
687 if (! (now = sdb_gettime())) {
688 char errbuf[1024];
689 sdb_log(SDB_LOG_ERR, "plugin: Failed to determine current "
690 "time: %s", sdb_strerror(errno, errbuf, sizeof(errbuf)));
691 now = SDB_PLUGIN_CCB(obj)->ccb_next_update;
692 }
694 if (now < SDB_PLUGIN_CCB(obj)->ccb_next_update) {
695 interval = SDB_PLUGIN_CCB(obj)->ccb_next_update - now;
697 errno = 0;
698 while (loop->do_loop && sdb_sleep(interval, &interval)) {
699 if (errno != EINTR) {
700 char errbuf[1024];
701 sdb_log(SDB_LOG_ERR, "plugin: Failed to sleep: %s",
702 sdb_strerror(errno, errbuf, sizeof(errbuf)));
703 return -1;
704 }
705 errno = 0;
706 }
708 if (! loop->do_loop)
709 return 0;
710 }
712 old_ctx = ctx_set(SDB_PLUGIN_CCB(obj)->ccb_ctx);
713 if (callback(SDB_PLUGIN_CCB(obj)->ccb_user_data)) {
714 /* XXX */
715 }
716 ctx_set(old_ctx);
718 interval = SDB_PLUGIN_CCB(obj)->ccb_interval;
719 if (! interval)
720 interval = loop->default_interval;
721 if (! interval) {
722 sdb_log(SDB_LOG_WARNING, "plugin: No interval configured "
723 "for plugin '%s'; skipping any further "
724 "iterations.", obj->name);
725 sdb_object_deref(obj);
726 continue;
727 }
729 SDB_PLUGIN_CCB(obj)->ccb_next_update += interval;
731 if (! (now = sdb_gettime())) {
732 char errbuf[1024];
733 sdb_log(SDB_LOG_ERR, "plugin: Failed to determine current "
734 "time: %s", sdb_strerror(errno, errbuf, sizeof(errbuf)));
735 now = SDB_PLUGIN_CCB(obj)->ccb_next_update;
736 }
738 if (now > SDB_PLUGIN_CCB(obj)->ccb_next_update) {
739 sdb_log(SDB_LOG_WARNING, "plugin: Plugin '%s' took too "
740 "long; skipping iterations to keep up.",
741 obj->name);
742 SDB_PLUGIN_CCB(obj)->ccb_next_update = now;
743 }
745 if (sdb_llist_insert_sorted(collector_list, obj,
746 sdb_plugin_cmp_next_update)) {
747 sdb_log(SDB_LOG_ERR, "plugin: Failed to re-insert "
748 "plugin '%s' into collector list. Unable to further "
749 "use the plugin.",
750 obj->name);
751 sdb_object_deref(obj);
752 return -1;
753 }
755 /* pass control back to the list */
756 sdb_object_deref(obj);
757 }
758 return 0;
759 } /* sdb_plugin_read_loop */
761 char *
762 sdb_plugin_cname(char *hostname)
763 {
764 sdb_llist_iter_t *iter;
766 if (! hostname)
767 return NULL;
769 if (! cname_list)
770 return hostname;
772 iter = sdb_llist_get_iter(cname_list);
773 while (sdb_llist_iter_has_next(iter)) {
774 sdb_plugin_cname_cb callback;
775 char *cname;
777 sdb_object_t *obj = sdb_llist_iter_get_next(iter);
778 assert(obj);
780 callback = SDB_PLUGIN_CB(obj)->cb_callback;
781 cname = callback(hostname, SDB_PLUGIN_CB(obj)->cb_user_data);
782 if (cname) {
783 free(hostname);
784 hostname = cname;
785 }
786 /* else: don't change hostname */
787 }
788 sdb_llist_iter_destroy(iter);
789 return hostname;
790 } /* sdb_plugin_cname */
792 int
793 sdb_plugin_log(int prio, const char *msg)
794 {
795 sdb_llist_iter_t *iter;
796 int ret = -1;
798 if (! msg)
799 return 0;
801 if (! log_list)
802 return fprintf(stderr, "[%s] %s\n", SDB_LOG_PRIO_TO_STRING(prio), msg);
804 iter = sdb_llist_get_iter(log_list);
805 while (sdb_llist_iter_has_next(iter)) {
806 sdb_plugin_log_cb callback;
807 int tmp;
809 sdb_object_t *obj = sdb_llist_iter_get_next(iter);
810 assert(obj);
812 callback = SDB_PLUGIN_CB(obj)->cb_callback;
813 tmp = callback(prio, msg, SDB_PLUGIN_CB(obj)->cb_user_data);
814 if (tmp > ret)
815 ret = tmp;
816 }
817 sdb_llist_iter_destroy(iter);
818 return ret;
819 } /* sdb_plugin_log */
821 int
822 sdb_plugin_vlogf(int prio, const char *fmt, va_list ap)
823 {
824 sdb_strbuf_t *buf;
825 int ret;
827 if (! fmt)
828 return 0;
830 buf = sdb_strbuf_create(64);
831 if (! buf) {
832 ret = fprintf(stderr, "[%s] ", SDB_LOG_PRIO_TO_STRING(prio));
833 ret += vfprintf(stderr, fmt, ap);
834 return ret;
835 }
837 if (sdb_strbuf_vsprintf(buf, fmt, ap) < 0) {
838 sdb_strbuf_destroy(buf);
839 return -1;
840 }
842 ret = sdb_plugin_log(prio, sdb_strbuf_string(buf));
843 sdb_strbuf_destroy(buf);
844 return ret;
845 } /* sdb_plugin_vlogf */
847 int
848 sdb_plugin_logf(int prio, const char *fmt, ...)
849 {
850 va_list ap;
851 int ret;
853 if (! fmt)
854 return 0;
856 va_start(ap, fmt);
857 ret = sdb_plugin_vlogf(prio, fmt, ap);
858 va_end(ap);
859 return ret;
860 } /* sdb_plugin_logf */
862 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */