Code

plugin: Name the plugin context after the actual module name.
[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 #if HAVE_CONFIG_H
29 #       include "config.h"
30 #endif /* HAVE_CONFIG_H */
32 #include "sysdb.h"
33 #include "core/plugin.h"
34 #include "core/time.h"
35 #include "utils/error.h"
36 #include "utils/llist.h"
37 #include "utils/strbuf.h"
39 #include <assert.h>
41 #include <errno.h>
43 #include <stdarg.h>
44 #include <stdio.h>
45 #include <string.h>
46 #include <strings.h>
47 #include <unistd.h>
49 #include <ltdl.h>
51 #include <pthread.h>
53 /*
54  * private data types
55  */
57 struct sdb_plugin_info {
58         char *plugin_name;
59         char *filename;
61         /* public attributes */
62         char *name;
64         char *description;
65         char *copyright;
66         char *license;
68         int   version;
69         int   plugin_version;
70 };
71 #define SDB_PLUGIN_INFO_INIT { \
72         /* plugin_name */ NULL, /* filename */ NULL, \
73         /* name */ NULL, /* desc */ NULL, \
74         /* copyright */ NULL, /* license */ NULL, \
75         /* version */ -1, /* plugin_version */ -1 }
76 #define INFO_GET(i, attr) \
77         ((i)->attr ? (i)->attr : #attr" not set")
79 typedef struct {
80         sdb_object_t super;
81         sdb_plugin_ctx_t public;
83         sdb_plugin_info_t info;
85         /* The usage count differs from the object's ref count
86          * in that it provides higher level information about how
87          * the plugin is in use. */
88         size_t use_cnt;
89 } ctx_t;
90 #define CTX_INIT { SDB_OBJECT_INIT, \
91         SDB_PLUGIN_CTX_INIT, SDB_PLUGIN_INFO_INIT, 0 }
93 #define CTX(obj) ((ctx_t *)(obj))
95 typedef struct {
96         sdb_object_t super;
97         void *cb_callback;
98         sdb_object_t *cb_user_data;
99         ctx_t *cb_ctx;
100 } sdb_plugin_cb_t;
101 #define SDB_PLUGIN_CB_INIT { SDB_OBJECT_INIT, \
102         /* callback = */ NULL, /* user_data = */ NULL, \
103         SDB_PLUGIN_CTX_INIT }
105 typedef struct {
106         sdb_plugin_cb_t super;
107 #define ccb_callback super.cb_callback
108 #define ccb_user_data super.cb_user_data
109 #define ccb_ctx super.cb_ctx
110         sdb_time_t ccb_interval;
111         sdb_time_t ccb_next_update;
112 } sdb_plugin_collector_cb_t;
114 #define SDB_PLUGIN_CB(obj) ((sdb_plugin_cb_t *)(obj))
115 #define SDB_CONST_PLUGIN_CB(obj) ((const sdb_plugin_cb_t *)(obj))
116 #define SDB_PLUGIN_CCB(obj) ((sdb_plugin_collector_cb_t *)(obj))
117 #define SDB_CONST_PLUGIN_CCB(obj) ((const sdb_plugin_collector_cb_t *)(obj))
119 /*
120  * private variables
121  */
123 static sdb_plugin_ctx_t  plugin_default_ctx  = SDB_PLUGIN_CTX_INIT;
124 static sdb_plugin_info_t plugin_default_info = SDB_PLUGIN_INFO_INIT;
126 static pthread_key_t     plugin_ctx_key;
127 static _Bool             plugin_ctx_key_initialized = 0;
129 /* a list of the plugin contexts of all registered plugins */
130 static sdb_llist_t      *all_plugins = NULL;
132 static sdb_llist_t      *config_list = NULL;
133 static sdb_llist_t      *init_list = NULL;
134 static sdb_llist_t      *collector_list = NULL;
135 static sdb_llist_t      *cname_list = NULL;
136 static sdb_llist_t      *shutdown_list = NULL;
137 static sdb_llist_t      *log_list = NULL;
139 /*
140  * private helper functions
141  */
143 static void
144 plugin_info_clear(sdb_plugin_info_t *info)
146         sdb_plugin_info_t empty_info = SDB_PLUGIN_INFO_INIT;
147         if (! info)
148                 return;
150         if (info->plugin_name)
151                 free(info->plugin_name);
152         if (info->filename)
153                 free(info->filename);
155         if (info->name)
156                 free(info->name);
157         if (info->description)
158                 free(info->description);
159         if (info->copyright)
160                 free(info->copyright);
161         if (info->license)
162                 free(info->license);
164         *info = empty_info;
165 } /* plugin_info_clear */
167 static void
168 ctx_key_init(void)
170         if (plugin_ctx_key_initialized)
171                 return;
173         pthread_key_create(&plugin_ctx_key, /* destructor */ NULL);
174         plugin_ctx_key_initialized = 1;
175 } /* ctx_key_init */
177 static int
178 plugin_cmp_next_update(const sdb_object_t *a, const sdb_object_t *b)
180         const sdb_plugin_collector_cb_t *ccb1
181                 = (const sdb_plugin_collector_cb_t *)a;
182         const sdb_plugin_collector_cb_t *ccb2
183                 = (const sdb_plugin_collector_cb_t *)b;
185         assert(ccb1 && ccb2);
187         return (ccb1->ccb_next_update > ccb2->ccb_next_update)
188                 ? 1 : (ccb1->ccb_next_update < ccb2->ccb_next_update)
189                 ? -1 : 0;
190 } /* plugin_cmp_next_update */
192 static int
193 plugin_lookup_by_name(const sdb_object_t *obj, const void *id)
195         const sdb_plugin_cb_t *cb = SDB_CONST_PLUGIN_CB(obj);
196         const char *name = id;
198         assert(cb && id && cb->cb_ctx);
199         if (!strcasecmp(cb->cb_ctx->info.plugin_name, name))
200                 return 0;
201         return 1;
202 } /* plugin_lookup_by_name */
204 static void
205 plugin_unregister_by_name(const char *plugin_name)
207         size_t i;
209         struct {
210                 const char  *type;
211                 sdb_llist_t *list;
212         } all_lists[] = {
213                 { "config",    config_list },
214                 { "init",      init_list },
215                 { "collector", collector_list },
216                 { "cname",     cname_list },
217                 { "shutdown",  shutdown_list },
218                 { "log",       log_list },
219         };
221         for (i = 0; i < SDB_STATIC_ARRAY_LEN(all_lists); ++i) {
222                 const char  *type = all_lists[i].type;
223                 sdb_llist_t *list = all_lists[i].list;
225                 while (1) {
226                         sdb_object_t *obj = sdb_llist_remove(list,
227                                         plugin_lookup_by_name, plugin_name);
228                         sdb_plugin_cb_t *cb = SDB_PLUGIN_CB(obj);
230                         if (! obj)
231                                 break;
233                         sdb_log(SDB_LOG_INFO, "core: Unregistering "
234                                         "%s callback '%s' (module %s)", type, obj->name,
235                                         cb->cb_ctx->info.plugin_name);
236                         sdb_object_deref(obj);
237                 }
238         }
239 } /* plugin_unregister_by_name */
241 /*
242  * private types
243  */
245 static int
246 ctx_init(sdb_object_t *obj, va_list __attribute__((unused)) ap)
248         ctx_t *ctx = CTX(obj);
250         assert(ctx);
252         ctx->public = plugin_default_ctx;
253         ctx->info = plugin_default_info;
254         ctx->use_cnt = 1;
255         return 0;
256 } /* ctx_init */
258 static void
259 ctx_destroy(sdb_object_t *obj)
261         ctx_t *ctx = CTX(obj);
262         plugin_info_clear(&ctx->info);
263 } /* ctx_destroy */
265 static sdb_type_t ctx_type = {
266         sizeof(ctx_t),
268         ctx_init,
269         ctx_destroy
270 };
272 static ctx_t *
273 ctx_create(const char *name)
275         ctx_t *ctx;
277         ctx = CTX(sdb_object_create(name, ctx_type));
278         if (! ctx)
279                 return NULL;
281         if (! plugin_ctx_key_initialized)
282                 ctx_key_init();
283         pthread_setspecific(plugin_ctx_key, ctx);
284         return ctx;
285 } /* ctx_create */
287 static ctx_t *
288 ctx_get(void)
290         if (! plugin_ctx_key_initialized)
291                 ctx_key_init();
292         return pthread_getspecific(plugin_ctx_key);
293 } /* ctx_get */
295 static ctx_t *
296 ctx_set(ctx_t *new)
298         ctx_t *old;
300         if (! plugin_ctx_key_initialized)
301                 ctx_key_init();
303         old = pthread_getspecific(plugin_ctx_key);
304         pthread_setspecific(plugin_ctx_key, new);
305         return old;
306 } /* ctx_set */
308 static int
309 plugin_cb_init(sdb_object_t *obj, va_list ap)
311         sdb_llist_t **list = va_arg(ap, sdb_llist_t **);
312         const char   *type = va_arg(ap, const char *);
313         void     *callback = va_arg(ap, void *);
314         sdb_object_t   *ud = va_arg(ap, sdb_object_t *);
316         assert(list);
317         assert(type);
318         assert(obj);
320         if (sdb_llist_search_by_name(*list, obj->name)) {
321                 sdb_log(SDB_LOG_WARNING, "core: %s callback '%s' "
322                                 "has already been registered. Ignoring newly "
323                                 "registered version.", type, obj->name);
324                 return -1;
325         }
327         SDB_PLUGIN_CB(obj)->cb_callback = callback;
328         SDB_PLUGIN_CB(obj)->cb_ctx      = ctx_get();
329         sdb_object_ref(SDB_OBJ(SDB_PLUGIN_CB(obj)->cb_ctx));
331         sdb_object_ref(ud);
332         SDB_PLUGIN_CB(obj)->cb_user_data = ud;
333         return 0;
334 } /* plugin_cb_init */
336 static void
337 plugin_cb_destroy(sdb_object_t *obj)
339         assert(obj);
340         sdb_object_deref(SDB_PLUGIN_CB(obj)->cb_user_data);
341         sdb_object_deref(SDB_OBJ(SDB_PLUGIN_CB(obj)->cb_ctx));
342 } /* plugin_cb_destroy */
344 static sdb_type_t sdb_plugin_cb_type = {
345         sizeof(sdb_plugin_cb_t),
347         plugin_cb_init,
348         plugin_cb_destroy
349 };
351 static sdb_type_t sdb_plugin_collector_cb_type = {
352         sizeof(sdb_plugin_collector_cb_t),
354         plugin_cb_init,
355         plugin_cb_destroy
356 };
358 static int
359 plugin_add_callback(sdb_llist_t **list, const char *type,
360                 const char *name, void *callback, sdb_object_t *user_data)
362         sdb_object_t *obj;
364         if ((! name) || (! callback))
365                 return -1;
367         assert(list);
369         if (! *list)
370                 *list = sdb_llist_create();
371         if (! *list)
372                 return -1;
374         obj = sdb_object_create(name, sdb_plugin_cb_type,
375                         list, type, callback, user_data);
376         if (! obj)
377                 return -1;
379         if (sdb_llist_append(*list, obj)) {
380                 sdb_object_deref(obj);
381                 return -1;
382         }
384         /* pass control to the list */
385         sdb_object_deref(obj);
387         sdb_log(SDB_LOG_INFO, "core: Registered %s callback '%s'.",
388                         type, name);
389         return 0;
390 } /* plugin_add_callback */
392 /*
393  * public API
394  */
396 int
397 sdb_plugin_load(const char *name, const sdb_plugin_ctx_t *plugin_ctx)
399         char  base_name[name ? strlen(name) + 1 : 1];
400         const char *name_ptr;
401         char *tmp;
403         char filename[1024];
404         ctx_t *ctx;
406         lt_dlhandle lh;
408         int (*mod_init)(sdb_plugin_info_t *);
409         int status;
411         if ((! name) || (! *name))
412                 return -1;
414         base_name[0] = '\0';
415         name_ptr = name;
417         while ((tmp = strstr(name_ptr, "::"))) {
418                 strncat(base_name, name_ptr, (size_t)(tmp - name_ptr));
419                 strcat(base_name, "/");
420                 name_ptr = tmp + strlen("::");
421         }
422         strcat(base_name, name_ptr);
424         ctx = CTX(sdb_llist_search_by_name(all_plugins, base_name));
425         if (ctx) {
426                 /* plugin already loaded */
427                 ++ctx->use_cnt;
428                 return 0;
429         }
431         snprintf(filename, sizeof(filename), "%s/%s.so",
432                         PKGLIBDIR, base_name);
433         filename[sizeof(filename) - 1] = '\0';
435         if (access(filename, R_OK)) {
436                 char errbuf[1024];
437                 sdb_log(SDB_LOG_ERR, "core: Failed to load plugin '%s' (%s): %s",
438                                 name, filename, sdb_strerror(errno, errbuf, sizeof(errbuf)));
439                 return -1;
440         }
442         lt_dlinit();
443         lt_dlerror();
445         lh = lt_dlopen(filename);
446         if (! lh) {
447                 sdb_log(SDB_LOG_ERR, "core: Failed to load plugin '%s': %s"
448                                 "The most common cause for this problem are missing "
449                                 "dependencies.\n", name, lt_dlerror());
450                 return -1;
451         }
453         if (ctx_get())
454                 sdb_log(SDB_LOG_WARNING, "core: Discarding old plugin context");
456         ctx = ctx_create(name);
457         if (! ctx) {
458                 sdb_log(SDB_LOG_ERR, "core: Failed to initialize plugin context");
459                 return -1;
460         }
462         ctx->info.plugin_name = strdup(name);
463         ctx->info.filename = strdup(filename);
465         if (plugin_ctx)
466                 ctx->public = *plugin_ctx;
468         mod_init = (int (*)(sdb_plugin_info_t *))lt_dlsym(lh, "sdb_module_init");
469         if (! mod_init) {
470                 sdb_log(SDB_LOG_ERR, "core: Failed to load plugin '%s': "
471                                 "could not find symbol 'sdb_module_init'", name);
472                 sdb_object_deref(SDB_OBJ(ctx));
473                 return -1;
474         }
476         status = mod_init(&ctx->info);
477         if (status) {
478                 sdb_log(SDB_LOG_ERR, "core: Failed to initialize "
479                                 "module '%s'", name);
480                 plugin_unregister_by_name(ctx->info.plugin_name);
481                 sdb_object_deref(SDB_OBJ(ctx));
482                 return -1;
483         }
485         /* compare minor version */
486         if ((ctx->info.version < 0)
487                         || ((int)(ctx->info.version / 100) != (int)(SDB_VERSION / 100)))
488                 sdb_log(SDB_LOG_WARNING, "core: WARNING: version of "
489                                 "plugin '%s' (%i.%i.%i) does not match our version "
490                                 "(%i.%i.%i); this might cause problems",
491                                 name, SDB_VERSION_DECODE(ctx->info.version),
492                                 SDB_VERSION_DECODE(SDB_VERSION));
494         if (! all_plugins) {
495                 if (! (all_plugins = sdb_llist_create())) {
496                         sdb_log(SDB_LOG_ERR, "core: Failed to load plugin '%s': "
497                                         "internal error while creating linked list", name);
498                         plugin_unregister_by_name(ctx->info.plugin_name);
499                         sdb_object_deref(SDB_OBJ(ctx));
500                         return -1;
501                 }
502         }
504         sdb_llist_append(all_plugins, SDB_OBJ(ctx));
506         sdb_log(SDB_LOG_INFO, "core: Successfully loaded "
507                         "plugin '%s' v%i (%s)\n\t%s\n\tLicense: %s",
508                         INFO_GET(&ctx->info, name), ctx->info.plugin_version,
509                         INFO_GET(&ctx->info, description),
510                         INFO_GET(&ctx->info, copyright),
511                         INFO_GET(&ctx->info, license));
513         /* any registered callbacks took ownership of the context */
514         sdb_object_deref(SDB_OBJ(ctx));
516         /* reset */
517         ctx_set(NULL);
518         return 0;
519 } /* sdb_plugin_load */
521 int
522 sdb_plugin_set_info(sdb_plugin_info_t *info, int type, ...)
524         va_list ap;
526         if (! info)
527                 return -1;
529         va_start(ap, type);
531         switch (type) {
532                 case SDB_PLUGIN_INFO_NAME:
533                         {
534                                 char *name = va_arg(ap, char *);
535                                 if (name) {
536                                         if (info->name)
537                                                 free(info->name);
538                                         info->name = strdup(name);
539                                 }
540                         }
541                         break;
542                 case SDB_PLUGIN_INFO_DESC:
543                         {
544                                 char *desc = va_arg(ap, char *);
545                                 if (desc) {
546                                         if (info->description)
547                                                 free(info->description);
548                                         info->description = strdup(desc);
549                                 }
550                         }
551                         break;
552                 case SDB_PLUGIN_INFO_COPYRIGHT:
553                         {
554                                 char *copyright = va_arg(ap, char *);
555                                 if (copyright)
556                                         info->copyright = strdup(copyright);
557                         }
558                         break;
559                 case SDB_PLUGIN_INFO_LICENSE:
560                         {
561                                 char *license = va_arg(ap, char *);
562                                 if (license) {
563                                         if (info->license)
564                                                 free(info->license);
565                                         info->license = strdup(license);
566                                 }
567                         }
568                         break;
569                 case SDB_PLUGIN_INFO_VERSION:
570                         {
571                                 int version = va_arg(ap, int);
572                                 info->version = version;
573                         }
574                         break;
575                 case SDB_PLUGIN_INFO_PLUGIN_VERSION:
576                         {
577                                 int version = va_arg(ap, int);
578                                 info->plugin_version = version;
579                         }
580                         break;
581                 default:
582                         va_end(ap);
583                         return -1;
584         }
586         va_end(ap);
587         return 0;
588 } /* sdb_plugin_set_info */
590 int
591 sdb_plugin_register_config(const char *name, sdb_plugin_config_cb callback)
593         return plugin_add_callback(&config_list, "init", name,
594                         (void *)callback, NULL);
595 } /* sdb_plugin_register_config */
597 int
598 sdb_plugin_register_init(const char *name, sdb_plugin_init_cb callback,
599                 sdb_object_t *user_data)
601         return plugin_add_callback(&init_list, "init", name,
602                         (void *)callback, user_data);
603 } /* sdb_plugin_register_init */
605 int
606 sdb_plugin_register_shutdown(const char *name, sdb_plugin_shutdown_cb callback,
607                 sdb_object_t *user_data)
609         return plugin_add_callback(&shutdown_list, "shutdown", name,
610                         (void *)callback, user_data);
611 } /* sdb_plugin_register_shutdown */
613 int
614 sdb_plugin_register_log(const char *name, sdb_plugin_log_cb callback,
615                 sdb_object_t *user_data)
617         return plugin_add_callback(&log_list, "log", name, (void *)callback,
618                         user_data);
619 } /* sdb_plugin_register_log */
621 int
622 sdb_plugin_register_cname(const char *name, sdb_plugin_cname_cb callback,
623                 sdb_object_t *user_data)
625         return plugin_add_callback(&cname_list, "cname", name, (void *)callback,
626                         user_data);
627 } /* sdb_plugin_register_cname */
629 int
630 sdb_plugin_register_collector(const char *name, sdb_plugin_collector_cb callback,
631                 const sdb_time_t *interval, sdb_object_t *user_data)
633         sdb_object_t *obj;
635         if ((! name) || (! callback))
636                 return -1;
638         if (! collector_list)
639                 collector_list = sdb_llist_create();
640         if (! collector_list)
641                 return -1;
643         obj = sdb_object_create(name, sdb_plugin_collector_cb_type,
644                         &collector_list, "collector", callback, user_data);
645         if (! obj)
646                 return -1;
648         if (interval)
649                 SDB_PLUGIN_CCB(obj)->ccb_interval = *interval;
650         else {
651                 sdb_time_t tmp = sdb_plugin_get_ctx().interval;
653                 if (tmp > 0)
654                         SDB_PLUGIN_CCB(obj)->ccb_interval = tmp;
655                 else
656                         SDB_PLUGIN_CCB(obj)->ccb_interval = 0;
657         }
659         if (! (SDB_PLUGIN_CCB(obj)->ccb_next_update = sdb_gettime())) {
660                 char errbuf[1024];
661                 sdb_log(SDB_LOG_ERR, "core: Failed to determine current "
662                                 "time: %s", sdb_strerror(errno, errbuf, sizeof(errbuf)));
663                 sdb_object_deref(obj);
664                 return -1;
665         }
667         if (sdb_llist_insert_sorted(collector_list, obj,
668                                 plugin_cmp_next_update)) {
669                 sdb_object_deref(obj);
670                 return -1;
671         }
673         /* pass control to the list */
674         sdb_object_deref(obj);
676         sdb_log(SDB_LOG_INFO, "core: Registered collector callback '%s' "
677                         "(interval = %.3fs).", name,
678                         SDB_TIME_TO_DOUBLE(SDB_PLUGIN_CCB(obj)->ccb_interval));
679         return 0;
680 } /* sdb_plugin_register_collector */
682 sdb_plugin_ctx_t
683 sdb_plugin_get_ctx(void)
685         ctx_t *c;
687         c = ctx_get();
688         if (! c) {
689                 sdb_plugin_log(SDB_LOG_ERR, "core: Invalid read access to plugin "
690                                 "context outside a plugin");
691                 return plugin_default_ctx;
692         }
693         return c->public;
694 } /* sdb_plugin_get_ctx */
696 int
697 sdb_plugin_set_ctx(sdb_plugin_ctx_t ctx, sdb_plugin_ctx_t *old)
699         ctx_t *c;
701         c = ctx_get();
702         if (! c) {
703                 sdb_plugin_log(SDB_LOG_ERR, "core: Invalid write access to plugin "
704                                 "context outside a plugin");
705                 return -1;
706         }
708         if (old)
709                 *old = c->public;
710         c->public = ctx;
711         return 0;
712 } /* sdb_plugin_set_ctx */
714 int
715 sdb_plugin_configure(const char *name, oconfig_item_t *ci)
717         sdb_plugin_cb_t *plugin;
718         sdb_plugin_config_cb callback;
720         ctx_t *old_ctx;
722         int status;
724         if ((! name) || (! ci))
725                 return -1;
727         plugin = SDB_PLUGIN_CB(sdb_llist_search_by_name(config_list, name));
728         if (! plugin) {
729                 ctx_t *ctx = CTX(sdb_llist_search_by_name(all_plugins, name));
730                 if (! ctx)
731                         sdb_log(SDB_LOG_ERR, "core: Plugin '%s' not loaded.", name);
732                 else
733                         sdb_log(SDB_LOG_ERR, "core: Plugin '%s' did not register "
734                                         "a config callback.", name);
735                 errno = ENOENT;
736                 return -1;
737         }
739         old_ctx = ctx_set(plugin->cb_ctx);
740         callback = (sdb_plugin_config_cb)plugin->cb_callback;
741         status = callback(ci);
742         ctx_set(old_ctx);
743         return status;
744 } /* sdb_plugin_configure */
746 int
747 sdb_plugin_init_all(void)
749         sdb_llist_iter_t *iter;
750         int ret = 0;
752         iter = sdb_llist_get_iter(init_list);
753         while (sdb_llist_iter_has_next(iter)) {
754                 sdb_plugin_cb_t *cb;
755                 sdb_plugin_init_cb callback;
756                 ctx_t *old_ctx;
758                 sdb_object_t *obj = sdb_llist_iter_get_next(iter);
759                 assert(obj);
760                 cb = SDB_PLUGIN_CB(obj);
762                 callback = (sdb_plugin_init_cb)cb->cb_callback;
764                 old_ctx = ctx_set(cb->cb_ctx);
765                 if (callback(cb->cb_user_data)) {
766                         sdb_log(SDB_LOG_ERR, "core: Failed to initialize plugin "
767                                         "'%s'. Unregistering all callbacks.", obj->name);
768                         plugin_unregister_by_name(cb->cb_ctx->info.plugin_name);
769                         ++ret;
770                 }
771                 ctx_set(old_ctx);
772         }
773         sdb_llist_iter_destroy(iter);
774         return ret;
775 } /* sdb_plugin_init_all */
777 int
778 sdb_plugin_collector_loop(sdb_plugin_loop_t *loop)
780         if (! collector_list) {
781                 sdb_log(SDB_LOG_WARNING, "core: No collectors registered. "
782                                 "Quiting main loop.");
783                 return -1;
784         }
786         if (! loop)
787                 return -1;
789         while (loop->do_loop) {
790                 sdb_plugin_collector_cb callback;
791                 ctx_t *old_ctx;
793                 sdb_time_t interval, now;
795                 sdb_object_t *obj = sdb_llist_shift(collector_list);
796                 if (! obj)
797                         return -1;
799                 callback = (sdb_plugin_collector_cb)SDB_PLUGIN_CCB(obj)->ccb_callback;
801                 if (! (now = sdb_gettime())) {
802                         char errbuf[1024];
803                         sdb_log(SDB_LOG_ERR, "core: Failed to determine current "
804                                         "time in collector main loop: %s",
805                                         sdb_strerror(errno, errbuf, sizeof(errbuf)));
806                         now = SDB_PLUGIN_CCB(obj)->ccb_next_update;
807                 }
809                 if (now < SDB_PLUGIN_CCB(obj)->ccb_next_update) {
810                         interval = SDB_PLUGIN_CCB(obj)->ccb_next_update - now;
812                         errno = 0;
813                         while (loop->do_loop && sdb_sleep(interval, &interval)) {
814                                 if (errno != EINTR) {
815                                         char errbuf[1024];
816                                         sdb_log(SDB_LOG_ERR, "core: Failed to sleep "
817                                                         "in collector main loop: %s",
818                                                         sdb_strerror(errno, errbuf, sizeof(errbuf)));
819                                         return -1;
820                                 }
821                                 errno = 0;
822                         }
824                         if (! loop->do_loop)
825                                 return 0;
826                 }
828                 old_ctx = ctx_set(SDB_PLUGIN_CCB(obj)->ccb_ctx);
829                 if (callback(SDB_PLUGIN_CCB(obj)->ccb_user_data)) {
830                         /* XXX */
831                 }
832                 ctx_set(old_ctx);
834                 interval = SDB_PLUGIN_CCB(obj)->ccb_interval;
835                 if (! interval)
836                         interval = loop->default_interval;
837                 if (! interval) {
838                         sdb_log(SDB_LOG_WARNING, "core: No interval configured "
839                                         "for plugin '%s'; skipping any further "
840                                         "iterations.", obj->name);
841                         sdb_object_deref(obj);
842                         continue;
843                 }
845                 SDB_PLUGIN_CCB(obj)->ccb_next_update += interval;
847                 if (! (now = sdb_gettime())) {
848                         char errbuf[1024];
849                         sdb_log(SDB_LOG_ERR, "core: Failed to determine current "
850                                         "time in collector main loop: %s",
851                                         sdb_strerror(errno, errbuf, sizeof(errbuf)));
852                         now = SDB_PLUGIN_CCB(obj)->ccb_next_update;
853                 }
855                 if (now > SDB_PLUGIN_CCB(obj)->ccb_next_update) {
856                         sdb_log(SDB_LOG_WARNING, "core: Plugin '%s' took too "
857                                         "long; skipping iterations to keep up.",
858                                         obj->name);
859                         SDB_PLUGIN_CCB(obj)->ccb_next_update = now;
860                 }
862                 if (sdb_llist_insert_sorted(collector_list, obj,
863                                         plugin_cmp_next_update)) {
864                         sdb_log(SDB_LOG_ERR, "core: Failed to re-insert "
865                                         "plugin '%s' into collector list. Unable to further "
866                                         "use the plugin.",
867                                         obj->name);
868                         sdb_object_deref(obj);
869                         return -1;
870                 }
872                 /* pass control back to the list */
873                 sdb_object_deref(obj);
874         }
875         return 0;
876 } /* sdb_plugin_read_loop */
878 char *
879 sdb_plugin_cname(char *hostname)
881         sdb_llist_iter_t *iter;
883         if (! hostname)
884                 return NULL;
886         if (! cname_list)
887                 return hostname;
889         iter = sdb_llist_get_iter(cname_list);
890         while (sdb_llist_iter_has_next(iter)) {
891                 sdb_plugin_cname_cb callback;
892                 char *cname;
894                 sdb_object_t *obj = sdb_llist_iter_get_next(iter);
895                 assert(obj);
897                 callback = (sdb_plugin_cname_cb)SDB_PLUGIN_CB(obj)->cb_callback;
898                 cname = callback(hostname, SDB_PLUGIN_CB(obj)->cb_user_data);
899                 if (cname) {
900                         free(hostname);
901                         hostname = cname;
902                 }
903                 /* else: don't change hostname */
904         }
905         sdb_llist_iter_destroy(iter);
906         return hostname;
907 } /* sdb_plugin_cname */
909 int
910 sdb_plugin_log(int prio, const char *msg)
912         sdb_llist_iter_t *iter;
913         int ret = -1;
915         if (! msg)
916                 return 0;
918         if (! log_list)
919                 return fprintf(stderr, "[%s] %s\n", SDB_LOG_PRIO_TO_STRING(prio), msg);
921         iter = sdb_llist_get_iter(log_list);
922         while (sdb_llist_iter_has_next(iter)) {
923                 sdb_plugin_log_cb callback;
924                 int tmp;
926                 sdb_object_t *obj = sdb_llist_iter_get_next(iter);
927                 assert(obj);
929                 callback = (sdb_plugin_log_cb)SDB_PLUGIN_CB(obj)->cb_callback;
930                 tmp = callback(prio, msg, SDB_PLUGIN_CB(obj)->cb_user_data);
931                 if (tmp > ret)
932                         ret = tmp;
933         }
934         sdb_llist_iter_destroy(iter);
935         return ret;
936 } /* sdb_plugin_log */
938 int
939 sdb_plugin_vlogf(int prio, const char *fmt, va_list ap)
941         sdb_strbuf_t *buf;
942         int ret;
944         if (! fmt)
945                 return 0;
947         buf = sdb_strbuf_create(64);
948         if (! buf) {
949                 ret = fprintf(stderr, "[%s] ", SDB_LOG_PRIO_TO_STRING(prio));
950                 ret += vfprintf(stderr, fmt, ap);
951                 return ret;
952         }
954         if (sdb_strbuf_vsprintf(buf, fmt, ap) < 0) {
955                 sdb_strbuf_destroy(buf);
956                 return -1;
957         }
959         ret = sdb_plugin_log(prio, sdb_strbuf_string(buf));
960         sdb_strbuf_destroy(buf);
961         return ret;
962 } /* sdb_plugin_vlogf */
964 int
965 sdb_plugin_logf(int prio, const char *fmt, ...)
967         va_list ap;
968         int ret;
970         if (! fmt)
971                 return 0;
973         va_start(ap, fmt);
974         ret = sdb_plugin_vlogf(prio, fmt, ap);
975         va_end(ap);
976         return ret;
977 } /* sdb_plugin_logf */
979 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */