Code

plugin: Manage all context information in the core.
[sysdb.git] / src / core / plugin.c
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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, ...)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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, ...)
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 : */