Code

plugin: Dynamically allocate plugin info attributes.
[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 /*
92  * private variables
93  */
95 static sdb_plugin_ctx_t  plugin_default_ctx = SDB_PLUGIN_CTX_INIT;
97 static pthread_key_t    plugin_ctx_key;
98 static _Bool            plugin_ctx_key_initialized = 0;
100 static sdb_llist_t      *config_list = NULL;
101 static sdb_llist_t      *init_list = NULL;
102 static sdb_llist_t      *collector_list = NULL;
103 static sdb_llist_t      *cname_list = NULL;
104 static sdb_llist_t      *shutdown_list = NULL;
105 static sdb_llist_t      *log_list = NULL;
107 /*
108  * private helper functions
109  */
111 static void
112 sdb_plugin_info_clear(sdb_plugin_info_t *info)
114         sdb_plugin_info_t empty_info = SDB_PLUGIN_INFO_INIT;
115         if (! info)
116                 return;
118         if (info->name)
119                 free(info->name);
120         if (info->description)
121                 free(info->description);
122         if (info->copyright)
123                 free(info->copyright);
124         if (info->license)
125                 free(info->license);
127         *info = empty_info;
128 } /* sdb_plugin_info_clear */
130 static void
131 sdb_plugin_ctx_destructor(void *ctx)
133         if (! ctx)
134                 return;
135         free(ctx);
136 } /* sdb_plugin_ctx_destructor */
138 static void
139 sdb_plugin_ctx_init(void)
141         if (plugin_ctx_key_initialized)
142                 return;
144         pthread_key_create(&plugin_ctx_key, sdb_plugin_ctx_destructor);
145         plugin_ctx_key_initialized = 1;
146 } /* sdb_plugin_ctx_init */
148 static sdb_plugin_ctx_t *
149 sdb_plugin_ctx_create(void)
151         sdb_plugin_ctx_t *ctx;
153         ctx = malloc(sizeof(*ctx));
154         if (! ctx)
155                 return NULL;
157         *ctx = plugin_default_ctx;
159         if (! plugin_ctx_key_initialized)
160                 sdb_plugin_ctx_init();
161         pthread_setspecific(plugin_ctx_key, ctx);
162         return ctx;
163 } /* sdb_plugin_ctx_create */
165 static int
166 sdb_plugin_cmp_next_update(const sdb_object_t *a, const sdb_object_t *b)
168         const sdb_plugin_collector_cb_t *ccb1
169                 = (const sdb_plugin_collector_cb_t *)a;
170         const sdb_plugin_collector_cb_t *ccb2
171                 = (const sdb_plugin_collector_cb_t *)b;
173         assert(ccb1 && ccb2);
175         return (ccb1->ccb_next_update > ccb2->ccb_next_update)
176                 ? 1 : (ccb1->ccb_next_update < ccb2->ccb_next_update)
177                 ? -1 : 0;
178 } /* sdb_plugin_cmp_next_update */
180 /*
181  * private types
182  */
184 static int
185 sdb_plugin_cb_init(sdb_object_t *obj, va_list ap)
187         sdb_llist_t **list = va_arg(ap, sdb_llist_t **);
188         const char   *type = va_arg(ap, const char *);
189         void     *callback = va_arg(ap, void *);
190         sdb_object_t   *ud = va_arg(ap, sdb_object_t *);
192         assert(list);
193         assert(type);
194         assert(obj);
196         if (sdb_llist_search_by_name(*list, obj->name)) {
197                 sdb_log(SDB_LOG_WARNING, "plugin: %s callback '%s' "
198                                 "has already been registered. Ignoring newly "
199                                 "registered version.", type, obj->name);
200                 return -1;
201         }
203         SDB_PLUGIN_CB(obj)->cb_callback = callback;
204         SDB_PLUGIN_CB(obj)->cb_ctx      = sdb_plugin_get_ctx();
206         sdb_object_ref(ud);
207         SDB_PLUGIN_CB(obj)->cb_user_data = ud;
208         return 0;
209 } /* sdb_plugin_cb_init */
211 static void
212 sdb_plugin_cb_destroy(sdb_object_t *obj)
214         assert(obj);
215         sdb_object_deref(SDB_PLUGIN_CB(obj)->cb_user_data);
216 } /* sdb_plugin_cb_destroy */
218 static sdb_type_t sdb_plugin_cb_type = {
219         sizeof(sdb_plugin_cb_t),
221         sdb_plugin_cb_init,
222         sdb_plugin_cb_destroy
223 };
225 static sdb_type_t sdb_plugin_collector_cb_type = {
226         sizeof(sdb_plugin_collector_cb_t),
228         sdb_plugin_cb_init,
229         sdb_plugin_cb_destroy
230 };
232 static int
233 sdb_plugin_add_callback(sdb_llist_t **list, const char *type,
234                 const char *name, void *callback, sdb_object_t *user_data)
236         sdb_object_t *obj;
238         if ((! name) || (! callback))
239                 return -1;
241         assert(list);
243         if (! *list)
244                 *list = sdb_llist_create();
245         if (! *list)
246                 return -1;
248         obj = sdb_object_create(name, sdb_plugin_cb_type,
249                         list, type, callback, user_data);
250         if (! obj)
251                 return -1;
253         if (sdb_llist_append(*list, obj)) {
254                 sdb_object_deref(obj);
255                 return -1;
256         }
258         /* pass control to the list */
259         sdb_object_deref(obj);
261         sdb_log(SDB_LOG_INFO, "plugin: Registered %s callback '%s'.",
262                         type, name);
263         return 0;
264 } /* sdb_plugin_add_callback */
266 /*
267  * public API
268  */
270 int
271 sdb_plugin_load(const char *name)
273         char  real_name[strlen(name) > 0 ? strlen(name) : 1];
274         const char *name_ptr;
275         char *tmp;
277         char filename[1024];
279         lt_dlhandle lh;
281         int (*mod_init)(sdb_plugin_info_t *);
282         sdb_plugin_info_t info = SDB_PLUGIN_INFO_INIT;
284         int status;
286         if ((! name) || (! *name))
287                 return -1;
289         real_name[0] = '\0';
290         name_ptr = name;
292         while ((tmp = strstr(name_ptr, "::"))) {
293                 strncat(real_name, name_ptr, (size_t)(tmp - name_ptr));
294                 strcat(real_name, "/");
295                 name_ptr = tmp + strlen("::");
296         }
297         strcat(real_name, name_ptr);
299         snprintf(filename, sizeof(filename), "%s/%s.so",
300                         PKGLIBDIR, real_name);
301         filename[sizeof(filename) - 1] = '\0';
303         if (access(filename, R_OK)) {
304                 char errbuf[1024];
305                 sdb_log(SDB_LOG_ERR, "plugin: Failed to load plugin '%s' (%s): %s",
306                                 name, filename, sdb_strerror(errno, errbuf, sizeof(errbuf)));
307                 return -1;
308         }
310         lt_dlinit();
311         lt_dlerror();
313         lh = lt_dlopen(filename);
314         if (! lh) {
315                 sdb_log(SDB_LOG_ERR, "plugin: Failed to load plugin '%s': %s"
316                                 "The most common cause for this problem are missing "
317                                 "dependencies.\n", name, lt_dlerror());
318                 return -1;
319         }
321         mod_init = (int (*)(sdb_plugin_info_t *))lt_dlsym(lh, "sdb_module_init");
322         if (! mod_init) {
323                 sdb_log(SDB_LOG_ERR, "plugin: Failed to load plugin '%s': "
324                                 "could not find symbol 'sdb_module_init'", name);
325                 return -1;
326         }
328         status = mod_init(&info);
329         if (status) {
330                 sdb_log(SDB_LOG_ERR, "plugin: Failed to initialize "
331                                 "plugin '%s'", name);
332                 sdb_plugin_info_clear(&info);
333                 return -1;
334         }
336         /* compare minor version */
337         if ((info.version < 0)
338                         || ((int)(info.version / 100) != (int)(SDB_VERSION / 100)))
339                 sdb_log(SDB_LOG_WARNING, "plugin: WARNING: version of "
340                                 "plugin '%s' (%i.%i.%i) does not match our version "
341                                 "(%i.%i.%i); this might cause problems",
342                                 name, SDB_VERSION_DECODE(info.version),
343                                 SDB_VERSION_DECODE(SDB_VERSION));
345         sdb_log(SDB_LOG_INFO, "plugin: Successfully loaded "
346                         "plugin '%s' v%i (%s)\n\t%s\n\tLicense: %s",
347                         INFO_GET(&info, name), info.plugin_version,
348                         INFO_GET(&info, description),
349                         INFO_GET(&info, copyright),
350                         INFO_GET(&info, license));
351         sdb_plugin_info_clear(&info);
352         return 0;
353 } /* sdb_plugin_load */
355 int
356 sdb_plugin_set_info(sdb_plugin_info_t *info, int type, ...)
358         va_list ap;
360         if (! info)
361                 return -1;
363         va_start(ap, type);
365         switch (type) {
366                 case SDB_PLUGIN_INFO_NAME:
367                         {
368                                 char *name = va_arg(ap, char *);
369                                 if (name) {
370                                         if (info->name)
371                                                 free(info->name);
372                                         info->name = strdup(name);
373                                 }
374                         }
375                         break;
376                 case SDB_PLUGIN_INFO_DESC:
377                         {
378                                 char *desc = va_arg(ap, char *);
379                                 if (desc) {
380                                         if (info->description)
381                                                 free(info->description);
382                                         info->description = strdup(desc);
383                                 }
384                         }
385                         break;
386                 case SDB_PLUGIN_INFO_COPYRIGHT:
387                         {
388                                 char *copyright = va_arg(ap, char *);
389                                 if (copyright)
390                                         info->copyright = strdup(copyright);
391                         }
392                         break;
393                 case SDB_PLUGIN_INFO_LICENSE:
394                         {
395                                 char *license = va_arg(ap, char *);
396                                 if (license) {
397                                         if (info->license)
398                                                 free(info->license);
399                                         info->license = strdup(license);
400                                 }
401                         }
402                         break;
403                 case SDB_PLUGIN_INFO_VERSION:
404                         {
405                                 int version = va_arg(ap, int);
406                                 info->version = version;
407                         }
408                         break;
409                 case SDB_PLUGIN_INFO_PLUGIN_VERSION:
410                         {
411                                 int version = va_arg(ap, int);
412                                 info->plugin_version = version;
413                         }
414                         break;
415                 default:
416                         va_end(ap);
417                         return -1;
418         }
420         va_end(ap);
421         return 0;
422 } /* sdb_plugin_set_info */
424 int
425 sdb_plugin_register_config(const char *name, sdb_plugin_config_cb callback)
427         return sdb_plugin_add_callback(&config_list, "init", name,
428                         callback, NULL);
429 } /* sdb_plugin_register_config */
431 int
432 sdb_plugin_register_init(const char *name, sdb_plugin_init_cb callback,
433                 sdb_object_t *user_data)
435         return sdb_plugin_add_callback(&init_list, "init", name,
436                         callback, user_data);
437 } /* sdb_plugin_register_init */
439 int
440 sdb_plugin_register_shutdown(const char *name, sdb_plugin_shutdown_cb callback,
441                 sdb_object_t *user_data)
443         return sdb_plugin_add_callback(&shutdown_list, "shutdown", name,
444                         callback, user_data);
445 } /* sdb_plugin_register_shutdown */
447 int
448 sdb_plugin_register_log(const char *name, sdb_plugin_log_cb callback,
449                 sdb_object_t *user_data)
451         return sdb_plugin_add_callback(&log_list, "log", name, callback,
452                         user_data);
453 } /* sdb_plugin_register_log */
455 int
456 sdb_plugin_register_cname(const char *name, sdb_plugin_cname_cb callback,
457                 sdb_object_t *user_data)
459         return sdb_plugin_add_callback(&cname_list, "cname", name, callback,
460                         user_data);
461 } /* sdb_plugin_register_cname */
463 int
464 sdb_plugin_register_collector(const char *name, sdb_plugin_collector_cb callback,
465                 const sdb_time_t *interval, sdb_object_t *user_data)
467         sdb_object_t *obj;
469         if ((! name) || (! callback))
470                 return -1;
472         if (! collector_list)
473                 collector_list = sdb_llist_create();
474         if (! collector_list)
475                 return -1;
477         obj = sdb_object_create(name, sdb_plugin_collector_cb_type,
478                         &collector_list, "collector", callback, user_data);
479         if (! obj)
480                 return -1;
482         if (interval)
483                 SDB_PLUGIN_CCB(obj)->ccb_interval = *interval;
484         else {
485                 sdb_time_t tmp = sdb_plugin_get_ctx().interval;
487                 if (tmp > 0)
488                         SDB_PLUGIN_CCB(obj)->ccb_interval = tmp;
489                 else
490                         SDB_PLUGIN_CCB(obj)->ccb_interval = 0;
491         }
493         if (! (SDB_PLUGIN_CCB(obj)->ccb_next_update = sdb_gettime())) {
494                 char errbuf[1024];
495                 sdb_log(SDB_LOG_ERR, "plugin: Failed to determine current "
496                                 "time: %s", sdb_strerror(errno, errbuf, sizeof(errbuf)));
497                 sdb_object_deref(obj);
498                 return -1;
499         }
501         if (sdb_llist_insert_sorted(collector_list, obj,
502                                 sdb_plugin_cmp_next_update)) {
503                 sdb_object_deref(obj);
504                 return -1;
505         }
507         /* pass control to the list */
508         sdb_object_deref(obj);
510         sdb_log(SDB_LOG_INFO, "plugin: Registered collector callback '%s' "
511                         "(interval = %.3fs).", name,
512                         SDB_TIME_TO_DOUBLE(SDB_PLUGIN_CCB(obj)->ccb_interval));
513         return 0;
514 } /* sdb_plugin_register_collector */
516 sdb_plugin_ctx_t
517 sdb_plugin_get_ctx(void)
519         sdb_plugin_ctx_t *ctx;
521         if (! plugin_ctx_key_initialized)
522                 sdb_plugin_ctx_init();
523         ctx = pthread_getspecific(plugin_ctx_key);
525         if (! ctx)
526                 ctx = sdb_plugin_ctx_create();
527         if (! ctx)
528                 return plugin_default_ctx;
529         return *ctx;
530 } /* sdb_plugin_get_ctx */
532 sdb_plugin_ctx_t
533 sdb_plugin_set_ctx(sdb_plugin_ctx_t ctx)
535         sdb_plugin_ctx_t *tmp;
536         sdb_plugin_ctx_t old;
538         if (! plugin_ctx_key_initialized)
539                 sdb_plugin_ctx_init();
540         tmp = pthread_getspecific(plugin_ctx_key);
542         if (! tmp)
543                 tmp = sdb_plugin_ctx_create();
544         if (! tmp)
545                 return plugin_default_ctx;
547         old = *tmp;
548         *tmp = ctx;
549         return old;
550 } /* sdb_plugin_set_ctx */
552 int
553 sdb_plugin_configure(const char *name, oconfig_item_t *ci)
555         sdb_plugin_cb_t *plugin;
556         sdb_plugin_config_cb callback;
558         sdb_plugin_ctx_t old_ctx;
560         int status;
562         if ((! name) || (! ci))
563                 return -1;
565         plugin = SDB_PLUGIN_CB(sdb_llist_search_by_name(config_list, name));
566         if (! plugin) {
567                 /* XXX: check if any such plugin has been loaded */
568                 sdb_log(SDB_LOG_ERR, "plugin: Plugin '%s' did not register "
569                                 "a config callback.", name);
570                 errno = ENOENT;
571                 return -1;
572         }
574         old_ctx = sdb_plugin_set_ctx(plugin->cb_ctx);
575         callback = plugin->cb_callback;
576         status = callback(ci);
577         sdb_plugin_set_ctx(old_ctx);
578         return status;
579 } /* sdb_plugin_configure */
581 int
582 sdb_plugin_init_all(void)
584         sdb_llist_iter_t *iter;
586         iter = sdb_llist_get_iter(init_list);
587         while (sdb_llist_iter_has_next(iter)) {
588                 sdb_plugin_init_cb callback;
589                 sdb_plugin_ctx_t old_ctx;
591                 sdb_object_t *obj = sdb_llist_iter_get_next(iter);
592                 assert(obj);
594                 callback = SDB_PLUGIN_CB(obj)->cb_callback;
596                 old_ctx = sdb_plugin_set_ctx(SDB_PLUGIN_CB(obj)->cb_ctx);
597                 if (callback(SDB_PLUGIN_CB(obj)->cb_user_data)) {
598                         /* XXX: unload plugin */
599                 }
600                 sdb_plugin_set_ctx(old_ctx);
601         }
602         sdb_llist_iter_destroy(iter);
603         return 0;
604 } /* sdb_plugin_init_all */
606 int
607 sdb_plugin_collector_loop(sdb_plugin_loop_t *loop)
609         if (! collector_list) {
610                 sdb_log(SDB_LOG_WARNING, "plugin: No collectors registered. "
611                                 "Quiting main loop.");
612                 return -1;
613         }
615         if (! loop)
616                 return -1;
618         while (loop->do_loop) {
619                 sdb_plugin_collector_cb callback;
620                 sdb_plugin_ctx_t old_ctx;
622                 sdb_time_t interval, now;
624                 sdb_object_t *obj = sdb_llist_shift(collector_list);
625                 if (! obj)
626                         return -1;
628                 callback = SDB_PLUGIN_CCB(obj)->ccb_callback;
630                 if (! (now = sdb_gettime())) {
631                         char errbuf[1024];
632                         sdb_log(SDB_LOG_ERR, "plugin: Failed to determine current "
633                                         "time: %s", sdb_strerror(errno, errbuf, sizeof(errbuf)));
634                         now = SDB_PLUGIN_CCB(obj)->ccb_next_update;
635                 }
637                 if (now < SDB_PLUGIN_CCB(obj)->ccb_next_update) {
638                         interval = SDB_PLUGIN_CCB(obj)->ccb_next_update - now;
640                         errno = 0;
641                         while (loop->do_loop && sdb_sleep(interval, &interval)) {
642                                 if (errno != EINTR) {
643                                         char errbuf[1024];
644                                         sdb_log(SDB_LOG_ERR, "plugin: Failed to sleep: %s",
645                                                         sdb_strerror(errno, errbuf, sizeof(errbuf)));
646                                         return -1;
647                                 }
648                                 errno = 0;
649                         }
651                         if (! loop->do_loop)
652                                 return 0;
653                 }
655                 old_ctx = sdb_plugin_set_ctx(SDB_PLUGIN_CCB(obj)->ccb_ctx);
656                 if (callback(SDB_PLUGIN_CCB(obj)->ccb_user_data)) {
657                         /* XXX */
658                 }
659                 sdb_plugin_set_ctx(old_ctx);
661                 interval = SDB_PLUGIN_CCB(obj)->ccb_interval;
662                 if (! interval)
663                         interval = loop->default_interval;
664                 if (! interval) {
665                         sdb_log(SDB_LOG_WARNING, "plugin: No interval configured "
666                                         "for plugin '%s'; skipping any further "
667                                         "iterations.", obj->name);
668                         sdb_object_deref(obj);
669                         continue;
670                 }
672                 SDB_PLUGIN_CCB(obj)->ccb_next_update += interval;
674                 if (! (now = sdb_gettime())) {
675                         char errbuf[1024];
676                         sdb_log(SDB_LOG_ERR, "plugin: Failed to determine current "
677                                         "time: %s", sdb_strerror(errno, errbuf, sizeof(errbuf)));
678                         now = SDB_PLUGIN_CCB(obj)->ccb_next_update;
679                 }
681                 if (now > SDB_PLUGIN_CCB(obj)->ccb_next_update) {
682                         sdb_log(SDB_LOG_WARNING, "plugin: Plugin '%s' took too "
683                                         "long; skipping iterations to keep up.",
684                                         obj->name);
685                         SDB_PLUGIN_CCB(obj)->ccb_next_update = now;
686                 }
688                 if (sdb_llist_insert_sorted(collector_list, obj,
689                                         sdb_plugin_cmp_next_update)) {
690                         sdb_log(SDB_LOG_ERR, "plugin: Failed to re-insert "
691                                         "plugin '%s' into collector list. Unable to further "
692                                         "use the plugin.",
693                                         obj->name);
694                         sdb_object_deref(obj);
695                         return -1;
696                 }
698                 /* pass control back to the list */
699                 sdb_object_deref(obj);
700         }
701         return 0;
702 } /* sdb_plugin_read_loop */
704 char *
705 sdb_plugin_cname(char *hostname)
707         sdb_llist_iter_t *iter;
709         if (! hostname)
710                 return NULL;
712         if (! cname_list)
713                 return hostname;
715         iter = sdb_llist_get_iter(cname_list);
716         while (sdb_llist_iter_has_next(iter)) {
717                 sdb_plugin_cname_cb callback;
718                 char *cname;
720                 sdb_object_t *obj = sdb_llist_iter_get_next(iter);
721                 assert(obj);
723                 callback = SDB_PLUGIN_CB(obj)->cb_callback;
724                 cname = callback(hostname, SDB_PLUGIN_CB(obj)->cb_user_data);
725                 if (cname) {
726                         free(hostname);
727                         hostname = cname;
728                 }
729                 /* else: don't change hostname */
730         }
731         sdb_llist_iter_destroy(iter);
732         return hostname;
733 } /* sdb_plugin_cname */
735 int
736 sdb_plugin_log(int prio, const char *msg)
738         sdb_llist_iter_t *iter;
739         int ret = -1;
741         if (! msg)
742                 return 0;
744         if (! log_list)
745                 return fprintf(stderr, "[%s] %s\n", SDB_LOG_PRIO_TO_STRING(prio), msg);
747         iter = sdb_llist_get_iter(log_list);
748         while (sdb_llist_iter_has_next(iter)) {
749                 sdb_plugin_log_cb callback;
750                 int tmp;
752                 sdb_object_t *obj = sdb_llist_iter_get_next(iter);
753                 assert(obj);
755                 callback = SDB_PLUGIN_CB(obj)->cb_callback;
756                 tmp = callback(prio, msg, SDB_PLUGIN_CB(obj)->cb_user_data);
757                 if (tmp > ret)
758                         ret = tmp;
759         }
760         sdb_llist_iter_destroy(iter);
761         return ret;
762 } /* sdb_plugin_log */
764 int
765 sdb_plugin_vlogf(int prio, const char *fmt, va_list ap)
767         sdb_strbuf_t *buf;
768         int ret;
770         if (! fmt)
771                 return 0;
773         buf = sdb_strbuf_create(64);
774         if (! buf) {
775                 ret = fprintf(stderr, "[%s] ", SDB_LOG_PRIO_TO_STRING(prio));
776                 ret += vfprintf(stderr, fmt, ap);
777                 return ret;
778         }
780         if (sdb_strbuf_vsprintf(buf, fmt, ap) < 0) {
781                 sdb_strbuf_destroy(buf);
782                 return -1;
783         }
785         ret = sdb_plugin_log(prio, sdb_strbuf_string(buf));
786         sdb_strbuf_destroy(buf);
787         return ret;
788 } /* sdb_plugin_vlogf */
790 int
791 sdb_plugin_logf(int prio, const char *fmt, ...)
793         va_list ap;
794         int ret;
796         if (! fmt)
797                 return 0;
799         va_start(ap, fmt);
800         ret = sdb_plugin_vlogf(prio, fmt, ap);
801         va_end(ap);
802         return ret;
803 } /* sdb_plugin_logf */
805 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */