Code

plugin: Store plugin info attributes in the plugin context.
[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;
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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, ...)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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, ...)
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 : */