Code

plugin: Made plugin context a dynamic object.
[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         void *cb_callback;
72         sdb_object_t *cb_user_data;
73         sdb_plugin_ctx_t cb_ctx;
74 } sdb_plugin_cb_t;
75 #define SDB_PLUGIN_CB_INIT { SDB_OBJECT_INIT, \
76         /* callback = */ NULL, /* user_data = */ NULL, \
77         SDB_PLUGIN_CTX_INIT }
79 typedef struct {
80         sdb_plugin_cb_t super;
81 #define ccb_callback super.cb_callback
82 #define ccb_user_data super.cb_user_data
83 #define ccb_ctx super.cb_ctx
84         sdb_time_t ccb_interval;
85         sdb_time_t ccb_next_update;
86 } sdb_plugin_collector_cb_t;
88 #define SDB_PLUGIN_CB(obj) ((sdb_plugin_cb_t *)(obj))
89 #define SDB_PLUGIN_CCB(obj) ((sdb_plugin_collector_cb_t *)(obj))
91 typedef struct {
92         sdb_object_t super;
93         sdb_plugin_ctx_t public;
94 } ctx_t;
95 #define CTX_INIT { SDB_OBJECT_INIT, \
96         SDB_PLUGIN_CTX_INIT }
98 #define CTX(obj) ((ctx_t *)(obj))
100 /*
101  * private variables
102  */
104 static sdb_plugin_ctx_t  plugin_default_ctx = SDB_PLUGIN_CTX_INIT;
106 static pthread_key_t     plugin_ctx_key;
107 static _Bool             plugin_ctx_key_initialized = 0;
109 static sdb_llist_t      *config_list = NULL;
110 static sdb_llist_t      *init_list = NULL;
111 static sdb_llist_t      *collector_list = NULL;
112 static sdb_llist_t      *cname_list = NULL;
113 static sdb_llist_t      *shutdown_list = NULL;
114 static sdb_llist_t      *log_list = NULL;
116 /*
117  * private helper functions
118  */
120 static void
121 sdb_plugin_info_clear(sdb_plugin_info_t *info)
123         sdb_plugin_info_t empty_info = SDB_PLUGIN_INFO_INIT;
124         if (! info)
125                 return;
127         if (info->name)
128                 free(info->name);
129         if (info->description)
130                 free(info->description);
131         if (info->copyright)
132                 free(info->copyright);
133         if (info->license)
134                 free(info->license);
136         *info = empty_info;
137 } /* sdb_plugin_info_clear */
139 static void
140 ctx_destructor(void *c)
142         sdb_object_deref(SDB_OBJ(c));
143 } /* ctx_destructor */
145 static void
146 ctx_key_init(void)
148         if (plugin_ctx_key_initialized)
149                 return;
151         pthread_key_create(&plugin_ctx_key, ctx_destructor);
152         plugin_ctx_key_initialized = 1;
153 } /* ctx_key_init */
155 static int
156 sdb_plugin_cmp_next_update(const sdb_object_t *a, const sdb_object_t *b)
158         const sdb_plugin_collector_cb_t *ccb1
159                 = (const sdb_plugin_collector_cb_t *)a;
160         const sdb_plugin_collector_cb_t *ccb2
161                 = (const sdb_plugin_collector_cb_t *)b;
163         assert(ccb1 && ccb2);
165         return (ccb1->ccb_next_update > ccb2->ccb_next_update)
166                 ? 1 : (ccb1->ccb_next_update < ccb2->ccb_next_update)
167                 ? -1 : 0;
168 } /* sdb_plugin_cmp_next_update */
170 /*
171  * private types
172  */
174 static int
175 ctx_init(sdb_object_t *obj, va_list __attribute__((unused)) ap)
177         ctx_t *ctx = CTX(obj);
179         assert(ctx);
181         ctx->public = plugin_default_ctx;
182         return 0;
183 } /* ctx_init */
185 static sdb_type_t ctx_type = {
186         sizeof(ctx_t),
188         ctx_init,
189         NULL
190 };
192 static ctx_t *
193 ctx_create(void)
195         ctx_t *ctx;
197         ctx = CTX(sdb_object_create("plugin-context", ctx_type));
198         if (! ctx)
199                 return NULL;
201         if (! plugin_ctx_key_initialized)
202                 ctx_key_init();
203         pthread_setspecific(plugin_ctx_key, ctx);
204         return ctx;
205 } /* ctx_create */
207 static int
208 sdb_plugin_cb_init(sdb_object_t *obj, va_list ap)
210         sdb_llist_t **list = va_arg(ap, sdb_llist_t **);
211         const char   *type = va_arg(ap, const char *);
212         void     *callback = va_arg(ap, void *);
213         sdb_object_t   *ud = va_arg(ap, sdb_object_t *);
215         assert(list);
216         assert(type);
217         assert(obj);
219         if (sdb_llist_search_by_name(*list, obj->name)) {
220                 sdb_log(SDB_LOG_WARNING, "plugin: %s callback '%s' "
221                                 "has already been registered. Ignoring newly "
222                                 "registered version.", type, obj->name);
223                 return -1;
224         }
226         SDB_PLUGIN_CB(obj)->cb_callback = callback;
227         SDB_PLUGIN_CB(obj)->cb_ctx      = sdb_plugin_get_ctx();
229         sdb_object_ref(ud);
230         SDB_PLUGIN_CB(obj)->cb_user_data = ud;
231         return 0;
232 } /* sdb_plugin_cb_init */
234 static void
235 sdb_plugin_cb_destroy(sdb_object_t *obj)
237         assert(obj);
238         sdb_object_deref(SDB_PLUGIN_CB(obj)->cb_user_data);
239 } /* sdb_plugin_cb_destroy */
241 static sdb_type_t sdb_plugin_cb_type = {
242         sizeof(sdb_plugin_cb_t),
244         sdb_plugin_cb_init,
245         sdb_plugin_cb_destroy
246 };
248 static sdb_type_t sdb_plugin_collector_cb_type = {
249         sizeof(sdb_plugin_collector_cb_t),
251         sdb_plugin_cb_init,
252         sdb_plugin_cb_destroy
253 };
255 static int
256 sdb_plugin_add_callback(sdb_llist_t **list, const char *type,
257                 const char *name, void *callback, sdb_object_t *user_data)
259         sdb_object_t *obj;
261         if ((! name) || (! callback))
262                 return -1;
264         assert(list);
266         if (! *list)
267                 *list = sdb_llist_create();
268         if (! *list)
269                 return -1;
271         obj = sdb_object_create(name, sdb_plugin_cb_type,
272                         list, type, callback, user_data);
273         if (! obj)
274                 return -1;
276         if (sdb_llist_append(*list, obj)) {
277                 sdb_object_deref(obj);
278                 return -1;
279         }
281         /* pass control to the list */
282         sdb_object_deref(obj);
284         sdb_log(SDB_LOG_INFO, "plugin: Registered %s callback '%s'.",
285                         type, name);
286         return 0;
287 } /* sdb_plugin_add_callback */
289 /*
290  * public API
291  */
293 int
294 sdb_plugin_load(const char *name)
296         char  real_name[strlen(name) > 0 ? strlen(name) : 1];
297         const char *name_ptr;
298         char *tmp;
300         char filename[1024];
302         lt_dlhandle lh;
304         int (*mod_init)(sdb_plugin_info_t *);
305         sdb_plugin_info_t info = SDB_PLUGIN_INFO_INIT;
307         int status;
309         if ((! name) || (! *name))
310                 return -1;
312         real_name[0] = '\0';
313         name_ptr = name;
315         while ((tmp = strstr(name_ptr, "::"))) {
316                 strncat(real_name, name_ptr, (size_t)(tmp - name_ptr));
317                 strcat(real_name, "/");
318                 name_ptr = tmp + strlen("::");
319         }
320         strcat(real_name, name_ptr);
322         snprintf(filename, sizeof(filename), "%s/%s.so",
323                         PKGLIBDIR, real_name);
324         filename[sizeof(filename) - 1] = '\0';
326         if (access(filename, R_OK)) {
327                 char errbuf[1024];
328                 sdb_log(SDB_LOG_ERR, "plugin: Failed to load plugin '%s' (%s): %s",
329                                 name, filename, sdb_strerror(errno, errbuf, sizeof(errbuf)));
330                 return -1;
331         }
333         lt_dlinit();
334         lt_dlerror();
336         lh = lt_dlopen(filename);
337         if (! lh) {
338                 sdb_log(SDB_LOG_ERR, "plugin: Failed to load plugin '%s': %s"
339                                 "The most common cause for this problem are missing "
340                                 "dependencies.\n", name, lt_dlerror());
341                 return -1;
342         }
344         mod_init = (int (*)(sdb_plugin_info_t *))lt_dlsym(lh, "sdb_module_init");
345         if (! mod_init) {
346                 sdb_log(SDB_LOG_ERR, "plugin: Failed to load plugin '%s': "
347                                 "could not find symbol 'sdb_module_init'", name);
348                 return -1;
349         }
351         status = mod_init(&info);
352         if (status) {
353                 sdb_log(SDB_LOG_ERR, "plugin: Failed to initialize "
354                                 "plugin '%s'", name);
355                 sdb_plugin_info_clear(&info);
356                 return -1;
357         }
359         /* compare minor version */
360         if ((info.version < 0)
361                         || ((int)(info.version / 100) != (int)(SDB_VERSION / 100)))
362                 sdb_log(SDB_LOG_WARNING, "plugin: WARNING: version of "
363                                 "plugin '%s' (%i.%i.%i) does not match our version "
364                                 "(%i.%i.%i); this might cause problems",
365                                 name, SDB_VERSION_DECODE(info.version),
366                                 SDB_VERSION_DECODE(SDB_VERSION));
368         sdb_log(SDB_LOG_INFO, "plugin: Successfully loaded "
369                         "plugin '%s' v%i (%s)\n\t%s\n\tLicense: %s",
370                         INFO_GET(&info, name), info.plugin_version,
371                         INFO_GET(&info, description),
372                         INFO_GET(&info, copyright),
373                         INFO_GET(&info, license));
374         sdb_plugin_info_clear(&info);
375         return 0;
376 } /* sdb_plugin_load */
378 int
379 sdb_plugin_set_info(sdb_plugin_info_t *info, int type, ...)
381         va_list ap;
383         if (! info)
384                 return -1;
386         va_start(ap, type);
388         switch (type) {
389                 case SDB_PLUGIN_INFO_NAME:
390                         {
391                                 char *name = va_arg(ap, char *);
392                                 if (name) {
393                                         if (info->name)
394                                                 free(info->name);
395                                         info->name = strdup(name);
396                                 }
397                         }
398                         break;
399                 case SDB_PLUGIN_INFO_DESC:
400                         {
401                                 char *desc = va_arg(ap, char *);
402                                 if (desc) {
403                                         if (info->description)
404                                                 free(info->description);
405                                         info->description = strdup(desc);
406                                 }
407                         }
408                         break;
409                 case SDB_PLUGIN_INFO_COPYRIGHT:
410                         {
411                                 char *copyright = va_arg(ap, char *);
412                                 if (copyright)
413                                         info->copyright = strdup(copyright);
414                         }
415                         break;
416                 case SDB_PLUGIN_INFO_LICENSE:
417                         {
418                                 char *license = va_arg(ap, char *);
419                                 if (license) {
420                                         if (info->license)
421                                                 free(info->license);
422                                         info->license = strdup(license);
423                                 }
424                         }
425                         break;
426                 case SDB_PLUGIN_INFO_VERSION:
427                         {
428                                 int version = va_arg(ap, int);
429                                 info->version = version;
430                         }
431                         break;
432                 case SDB_PLUGIN_INFO_PLUGIN_VERSION:
433                         {
434                                 int version = va_arg(ap, int);
435                                 info->plugin_version = version;
436                         }
437                         break;
438                 default:
439                         va_end(ap);
440                         return -1;
441         }
443         va_end(ap);
444         return 0;
445 } /* sdb_plugin_set_info */
447 int
448 sdb_plugin_register_config(const char *name, sdb_plugin_config_cb callback)
450         return sdb_plugin_add_callback(&config_list, "init", name,
451                         callback, NULL);
452 } /* sdb_plugin_register_config */
454 int
455 sdb_plugin_register_init(const char *name, sdb_plugin_init_cb callback,
456                 sdb_object_t *user_data)
458         return sdb_plugin_add_callback(&init_list, "init", name,
459                         callback, user_data);
460 } /* sdb_plugin_register_init */
462 int
463 sdb_plugin_register_shutdown(const char *name, sdb_plugin_shutdown_cb callback,
464                 sdb_object_t *user_data)
466         return sdb_plugin_add_callback(&shutdown_list, "shutdown", name,
467                         callback, user_data);
468 } /* sdb_plugin_register_shutdown */
470 int
471 sdb_plugin_register_log(const char *name, sdb_plugin_log_cb callback,
472                 sdb_object_t *user_data)
474         return sdb_plugin_add_callback(&log_list, "log", name, callback,
475                         user_data);
476 } /* sdb_plugin_register_log */
478 int
479 sdb_plugin_register_cname(const char *name, sdb_plugin_cname_cb callback,
480                 sdb_object_t *user_data)
482         return sdb_plugin_add_callback(&cname_list, "cname", name, callback,
483                         user_data);
484 } /* sdb_plugin_register_cname */
486 int
487 sdb_plugin_register_collector(const char *name, sdb_plugin_collector_cb callback,
488                 const sdb_time_t *interval, sdb_object_t *user_data)
490         sdb_object_t *obj;
492         if ((! name) || (! callback))
493                 return -1;
495         if (! collector_list)
496                 collector_list = sdb_llist_create();
497         if (! collector_list)
498                 return -1;
500         obj = sdb_object_create(name, sdb_plugin_collector_cb_type,
501                         &collector_list, "collector", callback, user_data);
502         if (! obj)
503                 return -1;
505         if (interval)
506                 SDB_PLUGIN_CCB(obj)->ccb_interval = *interval;
507         else {
508                 sdb_time_t tmp = sdb_plugin_get_ctx().interval;
510                 if (tmp > 0)
511                         SDB_PLUGIN_CCB(obj)->ccb_interval = tmp;
512                 else
513                         SDB_PLUGIN_CCB(obj)->ccb_interval = 0;
514         }
516         if (! (SDB_PLUGIN_CCB(obj)->ccb_next_update = sdb_gettime())) {
517                 char errbuf[1024];
518                 sdb_log(SDB_LOG_ERR, "plugin: Failed to determine current "
519                                 "time: %s", sdb_strerror(errno, errbuf, sizeof(errbuf)));
520                 sdb_object_deref(obj);
521                 return -1;
522         }
524         if (sdb_llist_insert_sorted(collector_list, obj,
525                                 sdb_plugin_cmp_next_update)) {
526                 sdb_object_deref(obj);
527                 return -1;
528         }
530         /* pass control to the list */
531         sdb_object_deref(obj);
533         sdb_log(SDB_LOG_INFO, "plugin: Registered collector callback '%s' "
534                         "(interval = %.3fs).", name,
535                         SDB_TIME_TO_DOUBLE(SDB_PLUGIN_CCB(obj)->ccb_interval));
536         return 0;
537 } /* sdb_plugin_register_collector */
539 sdb_plugin_ctx_t
540 sdb_plugin_get_ctx(void)
542         ctx_t *ctx;
544         if (! plugin_ctx_key_initialized)
545                 ctx_key_init();
546         ctx = pthread_getspecific(plugin_ctx_key);
548         if (! ctx)
549                 ctx = ctx_create();
550         if (! ctx)
551                 return plugin_default_ctx;
552         return ctx->public;
553 } /* sdb_plugin_get_ctx */
555 sdb_plugin_ctx_t
556 sdb_plugin_set_ctx(sdb_plugin_ctx_t ctx)
558         ctx_t *tmp;
559         sdb_plugin_ctx_t old;
561         if (! plugin_ctx_key_initialized)
562                 ctx_key_init();
563         tmp = pthread_getspecific(plugin_ctx_key);
565         if (! tmp)
566                 tmp = ctx_create();
567         if (! tmp)
568                 return plugin_default_ctx;
570         old = tmp->public;
571         tmp->public = ctx;
572         return old;
573 } /* sdb_plugin_set_ctx */
575 int
576 sdb_plugin_configure(const char *name, oconfig_item_t *ci)
578         sdb_plugin_cb_t *plugin;
579         sdb_plugin_config_cb callback;
581         sdb_plugin_ctx_t old_ctx;
583         int status;
585         if ((! name) || (! ci))
586                 return -1;
588         plugin = SDB_PLUGIN_CB(sdb_llist_search_by_name(config_list, name));
589         if (! plugin) {
590                 /* XXX: check if any such plugin has been loaded */
591                 sdb_log(SDB_LOG_ERR, "plugin: Plugin '%s' did not register "
592                                 "a config callback.", name);
593                 errno = ENOENT;
594                 return -1;
595         }
597         old_ctx = sdb_plugin_set_ctx(plugin->cb_ctx);
598         callback = plugin->cb_callback;
599         status = callback(ci);
600         sdb_plugin_set_ctx(old_ctx);
601         return status;
602 } /* sdb_plugin_configure */
604 int
605 sdb_plugin_init_all(void)
607         sdb_llist_iter_t *iter;
609         iter = sdb_llist_get_iter(init_list);
610         while (sdb_llist_iter_has_next(iter)) {
611                 sdb_plugin_init_cb callback;
612                 sdb_plugin_ctx_t old_ctx;
614                 sdb_object_t *obj = sdb_llist_iter_get_next(iter);
615                 assert(obj);
617                 callback = SDB_PLUGIN_CB(obj)->cb_callback;
619                 old_ctx = sdb_plugin_set_ctx(SDB_PLUGIN_CB(obj)->cb_ctx);
620                 if (callback(SDB_PLUGIN_CB(obj)->cb_user_data)) {
621                         /* XXX: unload plugin */
622                 }
623                 sdb_plugin_set_ctx(old_ctx);
624         }
625         sdb_llist_iter_destroy(iter);
626         return 0;
627 } /* sdb_plugin_init_all */
629 int
630 sdb_plugin_collector_loop(sdb_plugin_loop_t *loop)
632         if (! collector_list) {
633                 sdb_log(SDB_LOG_WARNING, "plugin: No collectors registered. "
634                                 "Quiting main loop.");
635                 return -1;
636         }
638         if (! loop)
639                 return -1;
641         while (loop->do_loop) {
642                 sdb_plugin_collector_cb callback;
643                 sdb_plugin_ctx_t old_ctx;
645                 sdb_time_t interval, now;
647                 sdb_object_t *obj = sdb_llist_shift(collector_list);
648                 if (! obj)
649                         return -1;
651                 callback = SDB_PLUGIN_CCB(obj)->ccb_callback;
653                 if (! (now = sdb_gettime())) {
654                         char errbuf[1024];
655                         sdb_log(SDB_LOG_ERR, "plugin: Failed to determine current "
656                                         "time: %s", sdb_strerror(errno, errbuf, sizeof(errbuf)));
657                         now = SDB_PLUGIN_CCB(obj)->ccb_next_update;
658                 }
660                 if (now < SDB_PLUGIN_CCB(obj)->ccb_next_update) {
661                         interval = SDB_PLUGIN_CCB(obj)->ccb_next_update - now;
663                         errno = 0;
664                         while (loop->do_loop && sdb_sleep(interval, &interval)) {
665                                 if (errno != EINTR) {
666                                         char errbuf[1024];
667                                         sdb_log(SDB_LOG_ERR, "plugin: Failed to sleep: %s",
668                                                         sdb_strerror(errno, errbuf, sizeof(errbuf)));
669                                         return -1;
670                                 }
671                                 errno = 0;
672                         }
674                         if (! loop->do_loop)
675                                 return 0;
676                 }
678                 old_ctx = sdb_plugin_set_ctx(SDB_PLUGIN_CCB(obj)->ccb_ctx);
679                 if (callback(SDB_PLUGIN_CCB(obj)->ccb_user_data)) {
680                         /* XXX */
681                 }
682                 sdb_plugin_set_ctx(old_ctx);
684                 interval = SDB_PLUGIN_CCB(obj)->ccb_interval;
685                 if (! interval)
686                         interval = loop->default_interval;
687                 if (! interval) {
688                         sdb_log(SDB_LOG_WARNING, "plugin: No interval configured "
689                                         "for plugin '%s'; skipping any further "
690                                         "iterations.", obj->name);
691                         sdb_object_deref(obj);
692                         continue;
693                 }
695                 SDB_PLUGIN_CCB(obj)->ccb_next_update += interval;
697                 if (! (now = sdb_gettime())) {
698                         char errbuf[1024];
699                         sdb_log(SDB_LOG_ERR, "plugin: Failed to determine current "
700                                         "time: %s", sdb_strerror(errno, errbuf, sizeof(errbuf)));
701                         now = SDB_PLUGIN_CCB(obj)->ccb_next_update;
702                 }
704                 if (now > SDB_PLUGIN_CCB(obj)->ccb_next_update) {
705                         sdb_log(SDB_LOG_WARNING, "plugin: Plugin '%s' took too "
706                                         "long; skipping iterations to keep up.",
707                                         obj->name);
708                         SDB_PLUGIN_CCB(obj)->ccb_next_update = now;
709                 }
711                 if (sdb_llist_insert_sorted(collector_list, obj,
712                                         sdb_plugin_cmp_next_update)) {
713                         sdb_log(SDB_LOG_ERR, "plugin: Failed to re-insert "
714                                         "plugin '%s' into collector list. Unable to further "
715                                         "use the plugin.",
716                                         obj->name);
717                         sdb_object_deref(obj);
718                         return -1;
719                 }
721                 /* pass control back to the list */
722                 sdb_object_deref(obj);
723         }
724         return 0;
725 } /* sdb_plugin_read_loop */
727 char *
728 sdb_plugin_cname(char *hostname)
730         sdb_llist_iter_t *iter;
732         if (! hostname)
733                 return NULL;
735         if (! cname_list)
736                 return hostname;
738         iter = sdb_llist_get_iter(cname_list);
739         while (sdb_llist_iter_has_next(iter)) {
740                 sdb_plugin_cname_cb callback;
741                 char *cname;
743                 sdb_object_t *obj = sdb_llist_iter_get_next(iter);
744                 assert(obj);
746                 callback = SDB_PLUGIN_CB(obj)->cb_callback;
747                 cname = callback(hostname, SDB_PLUGIN_CB(obj)->cb_user_data);
748                 if (cname) {
749                         free(hostname);
750                         hostname = cname;
751                 }
752                 /* else: don't change hostname */
753         }
754         sdb_llist_iter_destroy(iter);
755         return hostname;
756 } /* sdb_plugin_cname */
758 int
759 sdb_plugin_log(int prio, const char *msg)
761         sdb_llist_iter_t *iter;
762         int ret = -1;
764         if (! msg)
765                 return 0;
767         if (! log_list)
768                 return fprintf(stderr, "[%s] %s\n", SDB_LOG_PRIO_TO_STRING(prio), msg);
770         iter = sdb_llist_get_iter(log_list);
771         while (sdb_llist_iter_has_next(iter)) {
772                 sdb_plugin_log_cb callback;
773                 int tmp;
775                 sdb_object_t *obj = sdb_llist_iter_get_next(iter);
776                 assert(obj);
778                 callback = SDB_PLUGIN_CB(obj)->cb_callback;
779                 tmp = callback(prio, msg, SDB_PLUGIN_CB(obj)->cb_user_data);
780                 if (tmp > ret)
781                         ret = tmp;
782         }
783         sdb_llist_iter_destroy(iter);
784         return ret;
785 } /* sdb_plugin_log */
787 int
788 sdb_plugin_vlogf(int prio, const char *fmt, va_list ap)
790         sdb_strbuf_t *buf;
791         int ret;
793         if (! fmt)
794                 return 0;
796         buf = sdb_strbuf_create(64);
797         if (! buf) {
798                 ret = fprintf(stderr, "[%s] ", SDB_LOG_PRIO_TO_STRING(prio));
799                 ret += vfprintf(stderr, fmt, ap);
800                 return ret;
801         }
803         if (sdb_strbuf_vsprintf(buf, fmt, ap) < 0) {
804                 sdb_strbuf_destroy(buf);
805                 return -1;
806         }
808         ret = sdb_plugin_log(prio, sdb_strbuf_string(buf));
809         sdb_strbuf_destroy(buf);
810         return ret;
811 } /* sdb_plugin_vlogf */
813 int
814 sdb_plugin_logf(int prio, const char *fmt, ...)
816         va_list ap;
817         int ret;
819         if (! fmt)
820                 return 0;
822         va_start(ap, fmt);
823         ret = sdb_plugin_vlogf(prio, fmt, ap);
824         va_end(ap);
825         return ret;
826 } /* sdb_plugin_logf */
828 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */