Code

plugin: Store real plugin name and filename in the 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 *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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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, ...)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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, ...)
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 : */