235b8c7721ba97d08dc1b165c6ac0812ed7c6292
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 /* helper to access info attributes */
54 #define INFO_GET(i, attr) \
55 ((i)->attr ? (i)->attr : #attr" not set")
57 /*
58 * private data types
59 */
61 typedef struct {
62 sdb_object_t super;
63 sdb_plugin_ctx_t public;
65 sdb_plugin_info_t info;
66 lt_dlhandle handle;
68 /* The usage count differs from the object's ref count
69 * in that it provides higher level information about how
70 * the plugin is in use. */
71 size_t use_cnt;
72 } ctx_t;
73 #define CTX_INIT { SDB_OBJECT_INIT, \
74 SDB_PLUGIN_CTX_INIT, SDB_PLUGIN_INFO_INIT, NULL, 0 }
76 #define CTX(obj) ((ctx_t *)(obj))
78 typedef struct {
79 sdb_object_t super;
80 void *cb_callback;
81 sdb_object_t *cb_user_data;
82 ctx_t *cb_ctx;
83 } callback_t;
84 #define CB_INIT { SDB_OBJECT_INIT, \
85 /* callback = */ NULL, /* user_data = */ NULL, \
86 SDB_PLUGIN_CTX_INIT }
87 #define CB(obj) ((callback_t *)(obj))
88 #define CONST_CB(obj) ((const callback_t *)(obj))
90 typedef struct {
91 callback_t super;
92 #define ccb_callback super.cb_callback
93 #define ccb_user_data super.cb_user_data
94 #define ccb_ctx super.cb_ctx
95 sdb_time_t ccb_interval;
96 sdb_time_t ccb_next_update;
97 } collector_t;
98 #define CCB(obj) ((collector_t *)(obj))
99 #define CONST_CCB(obj) ((const collector_t *)(obj))
101 typedef struct {
102 callback_t super; /* cb_callback will always be NULL */
103 #define w_user_data super.cb_user_data
104 #define w_ctx super.cb_ctx
105 sdb_store_writer_t impl;
106 } writer_t;
107 #define WRITER(obj) ((writer_t *)(obj))
109 typedef struct {
110 callback_t super; /* cb_callback will always be NULL */
111 #define r_user_data super.cb_user_data
112 #define r_ctx super.cb_ctx
113 sdb_store_reader_t impl;
114 } reader_t;
115 #define READER(obj) ((reader_t *)(obj))
117 /*
118 * private variables
119 */
121 static sdb_plugin_ctx_t plugin_default_ctx = SDB_PLUGIN_CTX_INIT;
122 static sdb_plugin_info_t plugin_default_info = SDB_PLUGIN_INFO_INIT;
124 static pthread_key_t plugin_ctx_key;
125 static bool plugin_ctx_key_initialized = 0;
127 /* a list of the plugin contexts of all registered plugins */
128 static sdb_llist_t *all_plugins = NULL;
130 static sdb_llist_t *config_list = NULL;
131 static sdb_llist_t *init_list = NULL;
132 static sdb_llist_t *collector_list = NULL;
133 static sdb_llist_t *cname_list = NULL;
134 static sdb_llist_t *shutdown_list = NULL;
135 static sdb_llist_t *log_list = NULL;
136 static sdb_llist_t *ts_fetcher_list = NULL;
137 static sdb_llist_t *writer_list = NULL;
138 static sdb_llist_t *reader_list = NULL;
140 static struct {
141 const char *type;
142 sdb_llist_t **list;
143 } all_lists[] = {
144 { "config", &config_list },
145 { "init", &init_list },
146 { "collector", &collector_list },
147 { "cname", &cname_list },
148 { "shutdown", &shutdown_list },
149 { "log", &log_list },
150 { "timeseries fetcher", &ts_fetcher_list },
151 { "store writer", &writer_list },
152 { "store reader", &reader_list },
153 };
155 /*
156 * private helper functions
157 */
159 static void
160 plugin_info_clear(sdb_plugin_info_t *info)
161 {
162 sdb_plugin_info_t empty_info = SDB_PLUGIN_INFO_INIT;
163 if (! info)
164 return;
166 if (info->plugin_name)
167 free(info->plugin_name);
168 if (info->filename)
169 free(info->filename);
171 if (info->description)
172 free(info->description);
173 if (info->copyright)
174 free(info->copyright);
175 if (info->license)
176 free(info->license);
178 *info = empty_info;
179 } /* plugin_info_clear */
181 static void
182 ctx_key_init(void)
183 {
184 if (plugin_ctx_key_initialized)
185 return;
187 pthread_key_create(&plugin_ctx_key, /* destructor */ NULL);
188 plugin_ctx_key_initialized = 1;
189 } /* ctx_key_init */
191 static int
192 plugin_cmp_next_update(const sdb_object_t *a, const sdb_object_t *b)
193 {
194 const collector_t *ccb1 = (const collector_t *)a;
195 const collector_t *ccb2 = (const collector_t *)b;
197 assert(ccb1 && ccb2);
199 return (ccb1->ccb_next_update > ccb2->ccb_next_update)
200 ? 1 : (ccb1->ccb_next_update < ccb2->ccb_next_update)
201 ? -1 : 0;
202 } /* plugin_cmp_next_update */
204 static int
205 plugin_lookup_by_name(const sdb_object_t *obj, const void *id)
206 {
207 const callback_t *cb = CONST_CB(obj);
208 const char *name = id;
210 assert(cb && id);
212 /* when a plugin was registered from outside a plugin (e.g. the core),
213 * we don't have a plugin context */
214 if (! cb->cb_ctx)
215 return 1;
217 if (!strcasecmp(cb->cb_ctx->info.plugin_name, name))
218 return 0;
219 return 1;
220 } /* plugin_lookup_by_name */
222 /* since this function is called from sdb_plugin_reconfigure_finish()
223 * when iterating through all_plugins, we may not do any additional
224 * modifications to all_plugins except for the optional removal */
225 static void
226 plugin_unregister_by_name(const char *plugin_name)
227 {
228 sdb_object_t *obj;
229 size_t i;
231 for (i = 0; i < SDB_STATIC_ARRAY_LEN(all_lists); ++i) {
232 const char *type = all_lists[i].type;
233 sdb_llist_t *list = *all_lists[i].list;
235 while (1) {
236 callback_t *cb;
238 cb = CB(sdb_llist_remove(list,
239 plugin_lookup_by_name, plugin_name));
240 if (! cb)
241 break;
243 assert(cb->cb_ctx);
245 sdb_log(SDB_LOG_INFO, "core: Unregistering "
246 "%s callback '%s' (module %s)", type, cb->super.name,
247 cb->cb_ctx->info.plugin_name);
248 sdb_object_deref(SDB_OBJ(cb));
249 }
250 }
252 obj = sdb_llist_search_by_name(all_plugins, plugin_name);
253 /* when called from sdb_plugin_reconfigure_finish, the object has already
254 * been removed from the list */
255 if (obj && (obj->ref_cnt <= 1)) {
256 sdb_llist_remove_by_name(all_plugins, plugin_name);
257 sdb_object_deref(obj);
258 }
259 /* else: other callbacks still reference it */
260 } /* plugin_unregister_by_name */
262 /*
263 * private types
264 */
266 static int
267 ctx_init(sdb_object_t *obj, va_list __attribute__((unused)) ap)
268 {
269 ctx_t *ctx = CTX(obj);
271 assert(ctx);
273 ctx->public = plugin_default_ctx;
274 ctx->info = plugin_default_info;
275 ctx->handle = NULL;
276 ctx->use_cnt = 1;
277 return 0;
278 } /* ctx_init */
280 static void
281 ctx_destroy(sdb_object_t *obj)
282 {
283 ctx_t *ctx = CTX(obj);
285 if (ctx->handle) {
286 const char *err;
288 sdb_log(SDB_LOG_INFO, "core: Unloading module %s",
289 ctx->info.plugin_name);
291 lt_dlerror();
292 lt_dlclose(ctx->handle);
293 if ((err = lt_dlerror()))
294 sdb_log(SDB_LOG_WARNING, "core: Failed to unload module %s: %s",
295 ctx->info.plugin_name, err);
296 }
298 plugin_info_clear(&ctx->info);
299 } /* ctx_destroy */
301 static sdb_type_t ctx_type = {
302 sizeof(ctx_t),
304 ctx_init,
305 ctx_destroy
306 };
308 static ctx_t *
309 ctx_get(void)
310 {
311 if (! plugin_ctx_key_initialized)
312 ctx_key_init();
313 return pthread_getspecific(plugin_ctx_key);
314 } /* ctx_get */
316 static ctx_t *
317 ctx_set(ctx_t *new)
318 {
319 ctx_t *old;
321 if (! plugin_ctx_key_initialized)
322 ctx_key_init();
324 old = pthread_getspecific(plugin_ctx_key);
325 if (old)
326 sdb_object_deref(SDB_OBJ(old));
327 if (new)
328 sdb_object_ref(SDB_OBJ(new));
329 pthread_setspecific(plugin_ctx_key, new);
330 return old;
331 } /* ctx_set */
333 static ctx_t *
334 ctx_create(const char *name)
335 {
336 ctx_t *ctx;
338 ctx = CTX(sdb_object_create(name, ctx_type));
339 if (! ctx)
340 return NULL;
342 if (! plugin_ctx_key_initialized)
343 ctx_key_init();
344 ctx_set(ctx);
345 return ctx;
346 } /* ctx_create */
348 static int
349 plugin_cb_init(sdb_object_t *obj, va_list ap)
350 {
351 sdb_llist_t **list = va_arg(ap, sdb_llist_t **);
352 const char *type = va_arg(ap, const char *);
353 void *callback = va_arg(ap, void *);
354 sdb_object_t *ud = va_arg(ap, sdb_object_t *);
356 assert(list);
357 assert(type);
358 assert(obj);
360 if (sdb_llist_search_by_name(*list, obj->name)) {
361 sdb_log(SDB_LOG_WARNING, "core: %s callback '%s' "
362 "has already been registered. Ignoring newly "
363 "registered version.", type, obj->name);
364 return -1;
365 }
367 /* cb_ctx may be NULL if the plugin was not registered by a plugin */
369 CB(obj)->cb_callback = callback;
370 CB(obj)->cb_ctx = ctx_get();
371 sdb_object_ref(SDB_OBJ(CB(obj)->cb_ctx));
373 sdb_object_ref(ud);
374 CB(obj)->cb_user_data = ud;
375 return 0;
376 } /* plugin_cb_init */
378 static void
379 plugin_cb_destroy(sdb_object_t *obj)
380 {
381 assert(obj);
382 sdb_object_deref(CB(obj)->cb_user_data);
383 sdb_object_deref(SDB_OBJ(CB(obj)->cb_ctx));
384 } /* plugin_cb_destroy */
386 static sdb_type_t callback_type = {
387 sizeof(callback_t),
389 plugin_cb_init,
390 plugin_cb_destroy
391 };
393 static sdb_type_t collector_type = {
394 sizeof(collector_t),
396 plugin_cb_init,
397 plugin_cb_destroy
398 };
400 static int
401 plugin_writer_init(sdb_object_t *obj, va_list ap)
402 {
403 sdb_store_writer_t *impl = va_arg(ap, sdb_store_writer_t *);
404 sdb_object_t *ud = va_arg(ap, sdb_object_t *);
406 assert(impl);
408 if ((! impl->store_host) || (! impl->store_service)
409 || (! impl->store_metric) || (! impl->store_attribute)
410 || (! impl->store_service_attr) || (! impl->store_metric_attr)) {
411 sdb_log(SDB_LOG_ERR, "core: store writer callback '%s' "
412 "does not fully implement the writer interface.",
413 obj->name);
414 return -1;
415 }
416 if (sdb_llist_search_by_name(writer_list, obj->name)) {
417 sdb_log(SDB_LOG_WARNING, "core: store writer callback '%s' "
418 "has already been registered. Ignoring newly "
419 "registered version.", obj->name);
420 return -1;
421 }
423 /* ctx may be NULL if the callback was not registered by a plugin */
425 WRITER(obj)->impl = *impl;
426 WRITER(obj)->w_ctx = ctx_get();
427 sdb_object_ref(SDB_OBJ(WRITER(obj)->w_ctx));
429 sdb_object_ref(ud);
430 WRITER(obj)->w_user_data = ud;
431 return 0;
432 } /* plugin_writer_init */
434 static void
435 plugin_writer_destroy(sdb_object_t *obj)
436 {
437 assert(obj);
438 sdb_object_deref(WRITER(obj)->w_user_data);
439 sdb_object_deref(SDB_OBJ(WRITER(obj)->w_ctx));
440 } /* plugin_writer_destroy */
442 static sdb_type_t writer_type = {
443 sizeof(writer_t),
445 plugin_writer_init,
446 plugin_writer_destroy
447 };
449 static int
450 plugin_reader_init(sdb_object_t *obj, va_list ap)
451 {
452 sdb_store_reader_t *impl = va_arg(ap, sdb_store_reader_t *);
453 sdb_object_t *ud = va_arg(ap, sdb_object_t *);
455 assert(impl);
457 if ((! impl->prepare_query) || (! impl->execute_query)) {
458 sdb_log(SDB_LOG_ERR, "core: store reader callback '%s' "
459 "does not fully implement the reader interface.",
460 obj->name);
461 return -1;
462 }
463 if (sdb_llist_search_by_name(reader_list, obj->name)) {
464 sdb_log(SDB_LOG_WARNING, "core: store reader callback '%s' "
465 "has already been registered. Ignoring newly "
466 "registered version.", obj->name);
467 return -1;
468 }
470 /* ctx may be NULL if the callback was not registered by a plugin */
472 READER(obj)->impl = *impl;
473 READER(obj)->r_ctx = ctx_get();
474 sdb_object_ref(SDB_OBJ(READER(obj)->r_ctx));
476 sdb_object_ref(ud);
477 READER(obj)->r_user_data = ud;
478 return 0;
479 } /* plugin_reader_init */
481 static void
482 plugin_reader_destroy(sdb_object_t *obj)
483 {
484 assert(obj);
485 sdb_object_deref(READER(obj)->r_user_data);
486 sdb_object_deref(SDB_OBJ(READER(obj)->r_ctx));
487 } /* plugin_reader_destroy */
489 static sdb_type_t reader_type = {
490 sizeof(reader_t),
492 plugin_reader_init,
493 plugin_reader_destroy
494 };
496 static int
497 module_init(const char *name, lt_dlhandle lh, sdb_plugin_info_t *info)
498 {
499 int (*mod_init)(sdb_plugin_info_t *);
500 int status;
502 mod_init = (int (*)(sdb_plugin_info_t *))lt_dlsym(lh, "sdb_module_init");
503 if (! mod_init) {
504 sdb_log(SDB_LOG_ERR, "core: Failed to load plugin '%s': "
505 "could not find symbol 'sdb_module_init'", name);
506 return -1;
507 }
509 status = mod_init(info);
510 if (status) {
511 sdb_log(SDB_LOG_ERR, "core: Failed to initialize "
512 "module '%s'", name);
513 plugin_unregister_by_name(name);
514 return -1;
515 }
516 return 0;
517 } /* module_init */
519 static int
520 module_load(const char *basedir, const char *name,
521 const sdb_plugin_ctx_t *plugin_ctx)
522 {
523 char base_name[name ? strlen(name) + 1 : 1];
524 const char *name_ptr;
525 char *tmp;
527 char filename[1024];
528 lt_dlhandle lh;
530 ctx_t *ctx;
532 int status;
534 assert(name);
536 base_name[0] = '\0';
537 name_ptr = name;
539 while ((tmp = strstr(name_ptr, "::"))) {
540 strncat(base_name, name_ptr, (size_t)(tmp - name_ptr));
541 strcat(base_name, "/");
542 name_ptr = tmp + strlen("::");
543 }
544 strcat(base_name, name_ptr);
546 if (! basedir)
547 basedir = PKGLIBDIR;
549 snprintf(filename, sizeof(filename), "%s/%s.so", basedir, base_name);
550 filename[sizeof(filename) - 1] = '\0';
552 if (access(filename, R_OK)) {
553 char errbuf[1024];
554 sdb_log(SDB_LOG_ERR, "core: Failed to load plugin '%s' (%s): %s",
555 name, filename, sdb_strerror(errno, errbuf, sizeof(errbuf)));
556 return -1;
557 }
559 lt_dlinit();
560 lt_dlerror();
562 lh = lt_dlopen(filename);
563 if (! lh) {
564 sdb_log(SDB_LOG_ERR, "core: Failed to load plugin '%s': %s"
565 "The most common cause for this problem are missing "
566 "dependencies.\n", name, lt_dlerror());
567 return -1;
568 }
570 if (ctx_get())
571 sdb_log(SDB_LOG_WARNING, "core: Discarding old plugin context");
573 ctx = ctx_create(name);
574 if (! ctx) {
575 sdb_log(SDB_LOG_ERR, "core: Failed to initialize plugin context");
576 return -1;
577 }
579 ctx->info.plugin_name = strdup(name);
580 ctx->info.filename = strdup(filename);
581 ctx->handle = lh;
583 if (plugin_ctx)
584 ctx->public = *plugin_ctx;
586 if ((status = module_init(name, lh, &ctx->info))) {
587 sdb_object_deref(SDB_OBJ(ctx));
588 return status;
589 }
591 /* compare minor version */
592 if ((ctx->info.version < 0)
593 || ((int)(ctx->info.version / 100) != (int)(SDB_VERSION / 100)))
594 sdb_log(SDB_LOG_WARNING, "core: WARNING: version of "
595 "plugin '%s' (%i.%i.%i) does not match our version "
596 "(%i.%i.%i); this might cause problems",
597 name, SDB_VERSION_DECODE(ctx->info.version),
598 SDB_VERSION_DECODE(SDB_VERSION));
600 sdb_llist_append(all_plugins, SDB_OBJ(ctx));
602 sdb_log(SDB_LOG_INFO, "core: Successfully loaded "
603 "plugin %s v%i (%s)", ctx->info.plugin_name,
604 ctx->info.plugin_version,
605 INFO_GET(&ctx->info, description));
606 sdb_log(SDB_LOG_INFO, "core: Plugin %s: %s, License: %s",
607 ctx->info.plugin_name,
608 INFO_GET(&ctx->info, copyright),
609 INFO_GET(&ctx->info, license));
611 /* any registered callbacks took ownership of the context */
612 sdb_object_deref(SDB_OBJ(ctx));
614 /* reset */
615 ctx_set(NULL);
616 return 0;
617 } /* module_load */
619 static char *
620 plugin_get_name(const char *name, char *buf, size_t bufsize)
621 {
622 ctx_t *ctx = ctx_get();
624 if (ctx)
625 snprintf(buf, bufsize, "%s::%s", ctx->info.plugin_name, name);
626 else
627 snprintf(buf, bufsize, "core::%s", name);
628 return buf;
629 } /* plugin_get_name */
631 static int
632 plugin_add_callback(sdb_llist_t **list, const char *type,
633 const char *name, void *callback, sdb_object_t *user_data)
634 {
635 sdb_object_t *obj;
637 if ((! name) || (! callback))
638 return -1;
640 assert(list);
642 if (! *list)
643 *list = sdb_llist_create();
644 if (! *list)
645 return -1;
647 obj = sdb_object_create(name, callback_type,
648 list, type, callback, user_data);
649 if (! obj)
650 return -1;
652 if (sdb_llist_append(*list, obj)) {
653 sdb_object_deref(obj);
654 return -1;
655 }
657 /* pass control to the list */
658 sdb_object_deref(obj);
660 sdb_log(SDB_LOG_INFO, "core: Registered %s callback '%s'.",
661 type, name);
662 return 0;
663 } /* plugin_add_callback */
665 /*
666 * public API
667 */
669 int
670 sdb_plugin_load(const char *basedir, const char *name,
671 const sdb_plugin_ctx_t *plugin_ctx)
672 {
673 ctx_t *ctx;
675 int status;
677 if ((! name) || (! *name))
678 return -1;
680 if (! all_plugins) {
681 if (! (all_plugins = sdb_llist_create())) {
682 sdb_log(SDB_LOG_ERR, "core: Failed to load plugin '%s': "
683 "internal error while creating linked list", name);
684 return -1;
685 }
686 }
688 ctx = CTX(sdb_llist_search_by_name(all_plugins, name));
689 if (ctx) {
690 /* plugin already loaded */
691 if (! ctx->use_cnt) {
692 /* reloading plugin */
693 ctx_t *old_ctx = ctx_set(ctx);
695 status = module_init(ctx->info.plugin_name, ctx->handle, NULL);
696 if (status)
697 return status;
699 sdb_log(SDB_LOG_INFO, "core: Successfully reloaded plugin "
700 "'%s' (%s)", ctx->info.plugin_name,
701 INFO_GET(&ctx->info, description));
702 ctx_set(old_ctx);
703 }
704 ++ctx->use_cnt;
705 return 0;
706 }
708 return module_load(basedir, name, plugin_ctx);
709 } /* sdb_plugin_load */
711 int
712 sdb_plugin_set_info(sdb_plugin_info_t *info, int type, ...)
713 {
714 va_list ap;
716 if (! info)
717 return -1;
719 va_start(ap, type);
721 switch (type) {
722 case SDB_PLUGIN_INFO_DESC:
723 {
724 char *desc = va_arg(ap, char *);
725 if (desc) {
726 if (info->description)
727 free(info->description);
728 info->description = strdup(desc);
729 }
730 }
731 break;
732 case SDB_PLUGIN_INFO_COPYRIGHT:
733 {
734 char *copyright = va_arg(ap, char *);
735 if (copyright)
736 info->copyright = strdup(copyright);
737 }
738 break;
739 case SDB_PLUGIN_INFO_LICENSE:
740 {
741 char *license = va_arg(ap, char *);
742 if (license) {
743 if (info->license)
744 free(info->license);
745 info->license = strdup(license);
746 }
747 }
748 break;
749 case SDB_PLUGIN_INFO_VERSION:
750 {
751 int version = va_arg(ap, int);
752 info->version = version;
753 }
754 break;
755 case SDB_PLUGIN_INFO_PLUGIN_VERSION:
756 {
757 int version = va_arg(ap, int);
758 info->plugin_version = version;
759 }
760 break;
761 default:
762 va_end(ap);
763 return -1;
764 }
766 va_end(ap);
767 return 0;
768 } /* sdb_plugin_set_info */
770 int
771 sdb_plugin_register_config(sdb_plugin_config_cb callback)
772 {
773 ctx_t *ctx = ctx_get();
775 if (! ctx) {
776 sdb_log(SDB_LOG_ERR, "core: Invalid attempt to register a "
777 "config callback from outside a plugin");
778 return -1;
779 }
780 return plugin_add_callback(&config_list, "config", ctx->info.plugin_name,
781 (void *)callback, NULL);
782 } /* sdb_plugin_register_config */
784 int
785 sdb_plugin_register_init(const char *name, sdb_plugin_init_cb callback,
786 sdb_object_t *user_data)
787 {
788 char cb_name[1024];
789 return plugin_add_callback(&init_list, "init",
790 plugin_get_name(name, cb_name, sizeof(cb_name)),
791 (void *)callback, user_data);
792 } /* sdb_plugin_register_init */
794 int
795 sdb_plugin_register_shutdown(const char *name, sdb_plugin_shutdown_cb callback,
796 sdb_object_t *user_data)
797 {
798 char cb_name[1024];
799 return plugin_add_callback(&shutdown_list, "shutdown",
800 plugin_get_name(name, cb_name, sizeof(cb_name)),
801 (void *)callback, user_data);
802 } /* sdb_plugin_register_shutdown */
804 int
805 sdb_plugin_register_log(const char *name, sdb_plugin_log_cb callback,
806 sdb_object_t *user_data)
807 {
808 char cb_name[1024];
809 return plugin_add_callback(&log_list, "log",
810 plugin_get_name(name, cb_name, sizeof(cb_name)),
811 callback, user_data);
812 } /* sdb_plugin_register_log */
814 int
815 sdb_plugin_register_cname(const char *name, sdb_plugin_cname_cb callback,
816 sdb_object_t *user_data)
817 {
818 char cb_name[1024];
819 return plugin_add_callback(&cname_list, "cname",
820 plugin_get_name(name, cb_name, sizeof(cb_name)),
821 callback, user_data);
822 } /* sdb_plugin_register_cname */
824 int
825 sdb_plugin_register_collector(const char *name, sdb_plugin_collector_cb callback,
826 const sdb_time_t *interval, sdb_object_t *user_data)
827 {
828 char cb_name[1024];
829 sdb_object_t *obj;
831 if ((! name) || (! callback))
832 return -1;
834 if (! collector_list)
835 collector_list = sdb_llist_create();
836 if (! collector_list)
837 return -1;
839 plugin_get_name(name, cb_name, sizeof(cb_name));
841 obj = sdb_object_create(cb_name, collector_type,
842 &collector_list, "collector", callback, user_data);
843 if (! obj)
844 return -1;
846 if (interval)
847 CCB(obj)->ccb_interval = *interval;
848 else {
849 ctx_t *ctx = ctx_get();
851 if (! ctx) {
852 sdb_log(SDB_LOG_ERR, "core: Cannot determine interval "
853 "for collector %s; none specified and no plugin "
854 "context found", cb_name);
855 return -1;
856 }
858 CCB(obj)->ccb_interval = ctx->public.interval;
859 }
861 if (! (CCB(obj)->ccb_next_update = sdb_gettime())) {
862 char errbuf[1024];
863 sdb_log(SDB_LOG_ERR, "core: Failed to determine current "
864 "time: %s", sdb_strerror(errno, errbuf, sizeof(errbuf)));
865 sdb_object_deref(obj);
866 return -1;
867 }
869 if (sdb_llist_insert_sorted(collector_list, obj,
870 plugin_cmp_next_update)) {
871 sdb_object_deref(obj);
872 return -1;
873 }
875 /* pass control to the list */
876 sdb_object_deref(obj);
878 sdb_log(SDB_LOG_INFO, "core: Registered collector callback '%s' "
879 "(interval = %.3fs).", cb_name,
880 SDB_TIME_TO_DOUBLE(CCB(obj)->ccb_interval));
881 return 0;
882 } /* sdb_plugin_register_collector */
884 int
885 sdb_plugin_register_ts_fetcher(const char *name,
886 sdb_plugin_fetch_ts_cb callback, sdb_object_t *user_data)
887 {
888 return plugin_add_callback(&ts_fetcher_list, "time-series fetcher",
889 name, callback, user_data);
890 } /* sdb_plugin_register_ts_fetcher */
892 int
893 sdb_plugin_register_writer(const char *name,
894 sdb_store_writer_t *writer, sdb_object_t *user_data)
895 {
896 char cb_name[1024];
897 sdb_object_t *obj;
899 if ((! name) || (! writer))
900 return -1;
902 if (! writer_list)
903 writer_list = sdb_llist_create();
904 if (! writer_list)
905 return -1;
907 plugin_get_name(name, cb_name, sizeof(cb_name));
909 obj = sdb_object_create(cb_name, writer_type,
910 writer, user_data);
911 if (! obj)
912 return -1;
914 if (sdb_llist_append(writer_list, obj)) {
915 sdb_object_deref(obj);
916 return -1;
917 }
919 /* pass control to the list */
920 sdb_object_deref(obj);
922 sdb_log(SDB_LOG_INFO, "core: Registered store writer callback '%s'.",
923 cb_name);
924 return 0;
925 } /* sdb_store_register_writer */
927 int
928 sdb_plugin_register_reader(const char *name,
929 sdb_store_reader_t *reader, sdb_object_t *user_data)
930 {
931 char cb_name[1024];
932 sdb_object_t *obj;
934 if ((! name) || (! reader))
935 return -1;
937 if (! reader_list)
938 reader_list = sdb_llist_create();
939 if (! reader_list)
940 return -1;
942 plugin_get_name(name, cb_name, sizeof(cb_name));
944 obj = sdb_object_create(cb_name, reader_type,
945 reader, user_data);
946 if (! obj)
947 return -1;
949 if (sdb_llist_append(reader_list, obj)) {
950 sdb_object_deref(obj);
951 return -1;
952 }
954 /* pass control to the list */
955 sdb_object_deref(obj);
957 sdb_log(SDB_LOG_INFO, "core: Registered store reader callback '%s'.",
958 cb_name);
959 return 0;
960 } /* sdb_plugin_register_reader */
962 void
963 sdb_plugin_unregister_all(void)
964 {
965 size_t i;
967 for (i = 0; i < SDB_STATIC_ARRAY_LEN(all_lists); ++i) {
968 const char *type = all_lists[i].type;
969 sdb_llist_t *list = *all_lists[i].list;
971 size_t len = sdb_llist_len(list);
973 if (! len)
974 continue;
976 sdb_llist_clear(list);
977 sdb_log(SDB_LOG_INFO, "core: Unregistered %zu %s callback%s",
978 len, type, len == 1 ? "" : "s");
979 }
980 } /* sdb_plugin_unregister_all */
982 sdb_plugin_ctx_t
983 sdb_plugin_get_ctx(void)
984 {
985 ctx_t *c;
987 c = ctx_get();
988 if (! c) {
989 sdb_plugin_log(SDB_LOG_ERR, "core: Invalid read access to plugin "
990 "context outside a plugin");
991 return plugin_default_ctx;
992 }
993 return c->public;
994 } /* sdb_plugin_get_ctx */
996 int
997 sdb_plugin_set_ctx(sdb_plugin_ctx_t ctx, sdb_plugin_ctx_t *old)
998 {
999 ctx_t *c;
1001 c = ctx_get();
1002 if (! c) {
1003 sdb_plugin_log(SDB_LOG_ERR, "core: Invalid write access to plugin "
1004 "context outside a plugin");
1005 return -1;
1006 }
1008 if (old)
1009 *old = c->public;
1010 c->public = ctx;
1011 return 0;
1012 } /* sdb_plugin_set_ctx */
1014 const sdb_plugin_info_t *
1015 sdb_plugin_current(void)
1016 {
1017 ctx_t *ctx = ctx_get();
1019 if (! ctx)
1020 return NULL;
1021 return &ctx->info;
1022 } /* sdb_plugin_current */
1024 int
1025 sdb_plugin_configure(const char *name, oconfig_item_t *ci)
1026 {
1027 callback_t *plugin;
1028 sdb_plugin_config_cb callback;
1030 ctx_t *old_ctx;
1032 int status;
1034 if ((! name) || (! ci))
1035 return -1;
1037 plugin = CB(sdb_llist_search_by_name(config_list, name));
1038 if (! plugin) {
1039 ctx_t *ctx = CTX(sdb_llist_search_by_name(all_plugins, name));
1040 if (! ctx)
1041 sdb_log(SDB_LOG_ERR, "core: Cannot configure unknown "
1042 "plugin '%s'. Missing 'LoadPlugin \"%s\"'?",
1043 name, name);
1044 else
1045 sdb_log(SDB_LOG_ERR, "core: Plugin '%s' did not register "
1046 "a config callback.", name);
1047 errno = ENOENT;
1048 return -1;
1049 }
1051 old_ctx = ctx_set(plugin->cb_ctx);
1052 callback = (sdb_plugin_config_cb)plugin->cb_callback;
1053 status = callback(ci);
1054 ctx_set(old_ctx);
1055 return status;
1056 } /* sdb_plugin_configure */
1058 int
1059 sdb_plugin_reconfigure_init(void)
1060 {
1061 sdb_llist_iter_t *iter;
1063 iter = sdb_llist_get_iter(config_list);
1064 if (config_list && (! iter))
1065 return -1;
1067 /* deconfigure all plugins */
1068 while (sdb_llist_iter_has_next(iter)) {
1069 callback_t *plugin;
1070 sdb_plugin_config_cb callback;
1071 ctx_t *old_ctx;
1073 plugin = CB(sdb_llist_iter_get_next(iter));
1074 old_ctx = ctx_set(plugin->cb_ctx);
1075 callback = (sdb_plugin_config_cb)plugin->cb_callback;
1076 callback(NULL);
1077 ctx_set(old_ctx);
1078 }
1079 sdb_llist_iter_destroy(iter);
1081 iter = sdb_llist_get_iter(all_plugins);
1082 if (all_plugins && (! iter))
1083 return -1;
1085 /* record all plugins as being unused */
1086 while (sdb_llist_iter_has_next(iter))
1087 CTX(sdb_llist_iter_get_next(iter))->use_cnt = 0;
1088 sdb_llist_iter_destroy(iter);
1090 sdb_plugin_unregister_all();
1091 return 0;
1092 } /* sdb_plugin_reconfigure_init */
1094 int
1095 sdb_plugin_reconfigure_finish(void)
1096 {
1097 sdb_llist_iter_t *iter;
1099 iter = sdb_llist_get_iter(all_plugins);
1100 if (all_plugins && (! iter))
1101 return -1;
1103 while (sdb_llist_iter_has_next(iter)) {
1104 ctx_t *ctx = CTX(sdb_llist_iter_get_next(iter));
1105 if (ctx->use_cnt)
1106 continue;
1108 sdb_log(SDB_LOG_INFO, "core: Module %s no longer in use",
1109 ctx->info.plugin_name);
1110 sdb_llist_iter_remove_current(iter);
1111 plugin_unregister_by_name(ctx->info.plugin_name);
1112 sdb_object_deref(SDB_OBJ(ctx));
1113 }
1114 sdb_llist_iter_destroy(iter);
1115 return 0;
1116 } /* sdb_plugin_reconfigure_finish */
1118 int
1119 sdb_plugin_init_all(void)
1120 {
1121 sdb_llist_iter_t *iter;
1122 int ret = 0;
1124 iter = sdb_llist_get_iter(init_list);
1125 while (sdb_llist_iter_has_next(iter)) {
1126 callback_t *cb;
1127 sdb_plugin_init_cb callback;
1128 ctx_t *old_ctx;
1130 sdb_object_t *obj = sdb_llist_iter_get_next(iter);
1131 assert(obj);
1132 cb = CB(obj);
1134 callback = (sdb_plugin_init_cb)cb->cb_callback;
1136 old_ctx = ctx_set(cb->cb_ctx);
1137 if (callback(cb->cb_user_data)) {
1138 sdb_log(SDB_LOG_ERR, "core: Failed to initialize plugin "
1139 "'%s'. Unregistering all callbacks.", obj->name);
1140 ctx_set(old_ctx);
1141 plugin_unregister_by_name(cb->cb_ctx->info.plugin_name);
1142 ++ret;
1143 }
1144 else
1145 ctx_set(old_ctx);
1146 }
1147 sdb_llist_iter_destroy(iter);
1148 return ret;
1149 } /* sdb_plugin_init_all */
1151 int
1152 sdb_plugin_shutdown_all(void)
1153 {
1154 sdb_llist_iter_t *iter;
1155 int ret = 0;
1157 iter = sdb_llist_get_iter(shutdown_list);
1158 while (sdb_llist_iter_has_next(iter)) {
1159 callback_t *cb;
1160 sdb_plugin_shutdown_cb callback;
1161 ctx_t *old_ctx;
1163 sdb_object_t *obj = sdb_llist_iter_get_next(iter);
1164 assert(obj);
1165 cb = CB(obj);
1167 callback = (sdb_plugin_shutdown_cb)cb->cb_callback;
1169 old_ctx = ctx_set(cb->cb_ctx);
1170 if (callback(cb->cb_user_data)) {
1171 sdb_log(SDB_LOG_ERR, "core: Failed to shutdown plugin '%s'.",
1172 obj->name);
1173 ++ret;
1174 }
1175 ctx_set(old_ctx);
1176 }
1177 sdb_llist_iter_destroy(iter);
1178 return ret;
1179 } /* sdb_plugin_shutdown_all */
1181 int
1182 sdb_plugin_collector_loop(sdb_plugin_loop_t *loop)
1183 {
1184 if (! collector_list) {
1185 sdb_log(SDB_LOG_WARNING, "core: No collectors registered. "
1186 "Quiting main loop.");
1187 return -1;
1188 }
1190 if (! loop)
1191 return -1;
1193 while (loop->do_loop) {
1194 sdb_plugin_collector_cb callback;
1195 ctx_t *old_ctx;
1197 sdb_time_t interval, now;
1199 sdb_object_t *obj = sdb_llist_shift(collector_list);
1200 if (! obj)
1201 return -1;
1203 callback = (sdb_plugin_collector_cb)CCB(obj)->ccb_callback;
1205 if (! (now = sdb_gettime())) {
1206 char errbuf[1024];
1207 sdb_log(SDB_LOG_ERR, "core: Failed to determine current "
1208 "time in collector main loop: %s",
1209 sdb_strerror(errno, errbuf, sizeof(errbuf)));
1210 now = CCB(obj)->ccb_next_update;
1211 }
1213 if (now < CCB(obj)->ccb_next_update) {
1214 interval = CCB(obj)->ccb_next_update - now;
1216 errno = 0;
1217 while (loop->do_loop && sdb_sleep(interval, &interval)) {
1218 if (errno != EINTR) {
1219 char errbuf[1024];
1220 sdb_log(SDB_LOG_ERR, "core: Failed to sleep "
1221 "in collector main loop: %s",
1222 sdb_strerror(errno, errbuf, sizeof(errbuf)));
1223 sdb_llist_insert_sorted(collector_list, obj,
1224 plugin_cmp_next_update);
1225 sdb_object_deref(obj);
1226 return -1;
1227 }
1228 errno = 0;
1229 }
1231 if (! loop->do_loop) {
1232 /* put back; don't worry about errors */
1233 sdb_llist_insert_sorted(collector_list, obj,
1234 plugin_cmp_next_update);
1235 sdb_object_deref(obj);
1236 return 0;
1237 }
1238 }
1240 old_ctx = ctx_set(CCB(obj)->ccb_ctx);
1241 if (callback(CCB(obj)->ccb_user_data)) {
1242 /* XXX */
1243 }
1244 ctx_set(old_ctx);
1246 interval = CCB(obj)->ccb_interval;
1247 if (! interval)
1248 interval = loop->default_interval;
1249 if (! interval) {
1250 sdb_log(SDB_LOG_WARNING, "core: No interval configured "
1251 "for plugin '%s'; skipping any further "
1252 "iterations.", obj->name);
1253 sdb_object_deref(obj);
1254 continue;
1255 }
1257 CCB(obj)->ccb_next_update += interval;
1259 if (! (now = sdb_gettime())) {
1260 char errbuf[1024];
1261 sdb_log(SDB_LOG_ERR, "core: Failed to determine current "
1262 "time in collector main loop: %s",
1263 sdb_strerror(errno, errbuf, sizeof(errbuf)));
1264 now = CCB(obj)->ccb_next_update;
1265 }
1267 if (now > CCB(obj)->ccb_next_update) {
1268 sdb_log(SDB_LOG_WARNING, "core: Plugin '%s' took too "
1269 "long; skipping iterations to keep up.",
1270 obj->name);
1271 CCB(obj)->ccb_next_update = now;
1272 }
1274 if (sdb_llist_insert_sorted(collector_list, obj,
1275 plugin_cmp_next_update)) {
1276 sdb_log(SDB_LOG_ERR, "core: Failed to re-insert "
1277 "plugin '%s' into collector list. Unable to further "
1278 "use the plugin.",
1279 obj->name);
1280 sdb_object_deref(obj);
1281 return -1;
1282 }
1284 /* pass control back to the list */
1285 sdb_object_deref(obj);
1286 }
1287 return 0;
1288 } /* sdb_plugin_read_loop */
1290 char *
1291 sdb_plugin_cname(char *hostname)
1292 {
1293 sdb_llist_iter_t *iter;
1295 if (! hostname)
1296 return NULL;
1298 if (! cname_list)
1299 return hostname;
1301 iter = sdb_llist_get_iter(cname_list);
1302 while (sdb_llist_iter_has_next(iter)) {
1303 sdb_plugin_cname_cb callback;
1304 char *cname;
1306 sdb_object_t *obj = sdb_llist_iter_get_next(iter);
1307 assert(obj);
1309 callback = (sdb_plugin_cname_cb)CB(obj)->cb_callback;
1310 cname = callback(hostname, CB(obj)->cb_user_data);
1311 if (cname) {
1312 free(hostname);
1313 hostname = cname;
1314 }
1315 /* else: don't change hostname */
1316 }
1317 sdb_llist_iter_destroy(iter);
1318 return hostname;
1319 } /* sdb_plugin_cname */
1321 int
1322 sdb_plugin_log(int prio, const char *msg)
1323 {
1324 sdb_llist_iter_t *iter;
1325 int ret = -1;
1327 bool logged = 0;
1329 if (! msg)
1330 return 0;
1332 iter = sdb_llist_get_iter(log_list);
1333 while (sdb_llist_iter_has_next(iter)) {
1334 sdb_plugin_log_cb callback;
1335 int tmp;
1337 sdb_object_t *obj = sdb_llist_iter_get_next(iter);
1338 assert(obj);
1340 callback = (sdb_plugin_log_cb)CB(obj)->cb_callback;
1341 tmp = callback(prio, msg, CB(obj)->cb_user_data);
1342 if (tmp > ret)
1343 ret = tmp;
1345 if (CB(obj)->cb_ctx)
1346 logged = 1;
1347 /* else: this is an internally registered callback */
1348 }
1349 sdb_llist_iter_destroy(iter);
1351 if (! logged)
1352 return fprintf(stderr, "[%s] %s\n", SDB_LOG_PRIO_TO_STRING(prio), msg);
1353 return ret;
1354 } /* sdb_plugin_log */
1356 int
1357 sdb_plugin_vlogf(int prio, const char *fmt, va_list ap)
1358 {
1359 sdb_strbuf_t *buf;
1360 int ret;
1362 if (! fmt)
1363 return 0;
1365 buf = sdb_strbuf_create(64);
1366 if (! buf) {
1367 ret = fprintf(stderr, "[%s] ", SDB_LOG_PRIO_TO_STRING(prio));
1368 ret += vfprintf(stderr, fmt, ap);
1369 return ret;
1370 }
1372 if (sdb_strbuf_vsprintf(buf, fmt, ap) < 0) {
1373 sdb_strbuf_destroy(buf);
1374 return -1;
1375 }
1377 ret = sdb_plugin_log(prio, sdb_strbuf_string(buf));
1378 sdb_strbuf_destroy(buf);
1379 return ret;
1380 } /* sdb_plugin_vlogf */
1382 int
1383 sdb_plugin_logf(int prio, const char *fmt, ...)
1384 {
1385 va_list ap;
1386 int ret;
1388 if (! fmt)
1389 return 0;
1391 va_start(ap, fmt);
1392 ret = sdb_plugin_vlogf(prio, fmt, ap);
1393 va_end(ap);
1394 return ret;
1395 } /* sdb_plugin_logf */
1397 sdb_timeseries_t *
1398 sdb_plugin_fetch_timeseries(const char *type, const char *id,
1399 sdb_timeseries_opts_t *opts)
1400 {
1401 callback_t *plugin;
1402 sdb_plugin_fetch_ts_cb callback;
1403 sdb_timeseries_t *ts;
1405 ctx_t *old_ctx;
1407 if ((! type) || (! id) || (! opts))
1408 return NULL;
1410 plugin = CB(sdb_llist_search_by_name(ts_fetcher_list, type));
1411 if (! plugin) {
1412 sdb_log(SDB_LOG_ERR, "core: Cannot fetch time-series of type %s: "
1413 "no such plugin loaded", type);
1414 errno = ENOENT;
1415 return NULL;
1416 }
1418 old_ctx = ctx_set(plugin->cb_ctx);
1419 callback = (sdb_plugin_fetch_ts_cb)plugin->cb_callback;
1420 ts = callback(id, opts, plugin->cb_user_data);
1421 ctx_set(old_ctx);
1422 return ts;
1423 } /* sdb_plugin_fetch_timeseries */
1425 int
1426 sdb_plugin_query(sdb_ast_node_t *ast, sdb_strbuf_t *buf, sdb_strbuf_t *errbuf)
1427 {
1428 size_t n = sdb_llist_len(reader_list);
1429 reader_t *reader;
1430 sdb_object_t *q;
1431 int status = 0;
1433 if (! ast)
1434 return 0;
1436 if ((ast->type != SDB_AST_TYPE_FETCH)
1437 && (ast->type != SDB_AST_TYPE_LIST)
1438 && (ast->type != SDB_AST_TYPE_LOOKUP)
1439 && (ast->type != SDB_AST_TYPE_TIMESERIES)) {
1440 sdb_log(SDB_LOG_ERR, "core: Cannot execute query of type %s",
1441 SDB_AST_TYPE_TO_STRING(ast));
1442 sdb_strbuf_sprintf(errbuf, "Cannot execute query of type %s",
1443 SDB_AST_TYPE_TO_STRING(ast));
1444 return -1;
1445 }
1447 if (n != 1) {
1448 char *msg = (n > 0)
1449 ? "Cannot execute query: multiple readers not supported"
1450 : "Cannot execute query: no readers registered";
1451 sdb_strbuf_sprintf(errbuf, "%s", msg);
1452 sdb_log(SDB_LOG_ERR, "core: %s", msg);
1453 return -1;
1454 }
1456 reader = READER(sdb_llist_get(reader_list, 0));
1457 assert(reader);
1459 q = reader->impl.prepare_query(ast, errbuf, reader->r_user_data);
1460 if (q)
1461 status = reader->impl.execute_query(q, buf, errbuf, reader->r_user_data);
1462 else
1463 status = -1;
1465 sdb_object_deref(SDB_OBJ(q));
1466 sdb_object_deref(SDB_OBJ(reader));
1467 return status;
1468 } /* sdb_plugin_query */
1470 int
1471 sdb_plugin_store_host(const char *name, sdb_time_t last_update)
1472 {
1473 char *cname;
1475 sdb_llist_iter_t *iter;
1476 int status = 0;
1478 if (! name)
1479 return -1;
1481 if (! sdb_llist_len(writer_list)) {
1482 sdb_log(SDB_LOG_ERR, "core: Cannot store host: "
1483 "no writers registered");
1484 return -1;
1485 }
1487 cname = sdb_plugin_cname(strdup(name));
1488 if (! cname) {
1489 sdb_log(SDB_LOG_ERR, "core: strdup failed");
1490 return -1;
1491 }
1493 iter = sdb_llist_get_iter(writer_list);
1494 while (sdb_llist_iter_has_next(iter)) {
1495 writer_t *writer = WRITER(sdb_llist_iter_get_next(iter));
1496 int s;
1497 assert(writer);
1498 s = writer->impl.store_host(cname, last_update, writer->w_user_data);
1499 if (((s > 0) && (status >= 0)) || (s < 0))
1500 status = s;
1501 }
1502 sdb_llist_iter_destroy(iter);
1503 free(cname);
1504 return status;
1505 } /* sdb_plugin_store_host */
1507 int
1508 sdb_plugin_store_service(const char *hostname, const char *name,
1509 sdb_time_t last_update)
1510 {
1511 char *cname;
1513 sdb_llist_iter_t *iter;
1514 int status = 0;
1516 if ((! hostname) || (! name))
1517 return -1;
1519 if (! sdb_llist_len(writer_list)) {
1520 sdb_log(SDB_LOG_ERR, "core: Cannot store service: "
1521 "no writers registered");
1522 return -1;
1523 }
1525 cname = sdb_plugin_cname(strdup(hostname));
1526 if (! cname) {
1527 sdb_log(SDB_LOG_ERR, "core: strdup failed");
1528 return -1;
1529 }
1531 iter = sdb_llist_get_iter(writer_list);
1532 while (sdb_llist_iter_has_next(iter)) {
1533 writer_t *writer = WRITER(sdb_llist_iter_get_next(iter));
1534 int s;
1535 assert(writer);
1536 s = writer->impl.store_service(cname, name, last_update,
1537 writer->w_user_data);
1538 if (((s > 0) && (status >= 0)) || (s < 0))
1539 status = s;
1540 }
1541 sdb_llist_iter_destroy(iter);
1542 free(cname);
1543 return status;
1544 } /* sdb_plugin_store_service */
1546 int
1547 sdb_plugin_store_metric(const char *hostname, const char *name,
1548 sdb_metric_store_t *store, sdb_time_t last_update)
1549 {
1550 char *cname;
1552 sdb_llist_iter_t *iter;
1553 int status = 0;
1555 if ((! hostname) || (! name))
1556 return -1;
1558 if (! sdb_llist_len(writer_list)) {
1559 sdb_log(SDB_LOG_ERR, "core: Cannot store metric: "
1560 "no writers registered");
1561 return -1;
1562 }
1564 cname = sdb_plugin_cname(strdup(hostname));
1565 if (! cname) {
1566 sdb_log(SDB_LOG_ERR, "core: strdup failed");
1567 return -1;
1568 }
1570 if (store && ((! store->type) || (! store->id)))
1571 store = NULL;
1573 iter = sdb_llist_get_iter(writer_list);
1574 while (sdb_llist_iter_has_next(iter)) {
1575 writer_t *writer = WRITER(sdb_llist_iter_get_next(iter));
1576 int s;
1577 assert(writer);
1578 s = writer->impl.store_metric(cname, name, store, last_update,
1579 writer->w_user_data);
1580 if (((s > 0) && (status >= 0)) || (s < 0))
1581 status = s;
1582 }
1583 sdb_llist_iter_destroy(iter);
1584 free(cname);
1585 return status;
1586 } /* sdb_plugin_store_metric */
1588 int
1589 sdb_plugin_store_attribute(const char *hostname, const char *key,
1590 const sdb_data_t *value, sdb_time_t last_update)
1591 {
1592 char *cname;
1594 sdb_llist_iter_t *iter;
1595 int status = 0;
1597 if ((! hostname) || (! key) || (! value))
1598 return -1;
1600 if (! sdb_llist_len(writer_list)) {
1601 sdb_log(SDB_LOG_ERR, "core: Cannot store attribute: "
1602 "no writers registered");
1603 return -1;
1604 }
1606 cname = sdb_plugin_cname(strdup(hostname));
1607 if (! cname) {
1608 sdb_log(SDB_LOG_ERR, "core: strdup failed");
1609 return -1;
1610 }
1612 iter = sdb_llist_get_iter(writer_list);
1613 while (sdb_llist_iter_has_next(iter)) {
1614 writer_t *writer = WRITER(sdb_llist_iter_get_next(iter));
1615 int s;
1616 assert(writer);
1617 s = writer->impl.store_attribute(cname, key, value, last_update,
1618 writer->w_user_data);
1619 if (((s > 0) && (status >= 0)) || (s < 0))
1620 status = s;
1621 }
1622 sdb_llist_iter_destroy(iter);
1623 free(cname);
1624 return status;
1625 } /* sdb_plugin_store_attribute */
1627 int
1628 sdb_plugin_store_service_attribute(const char *hostname, const char *service,
1629 const char *key, const sdb_data_t *value, sdb_time_t last_update)
1630 {
1631 char *cname;
1633 sdb_llist_iter_t *iter;
1634 int status = 0;
1636 if ((! hostname) || (! service) || (! key) || (! value))
1637 return -1;
1639 if (! sdb_llist_len(writer_list)) {
1640 sdb_log(SDB_LOG_ERR, "core: Cannot store service attribute: "
1641 "no writers registered");
1642 return -1;
1643 }
1645 cname = sdb_plugin_cname(strdup(hostname));
1646 if (! cname) {
1647 sdb_log(SDB_LOG_ERR, "core: strdup failed");
1648 return -1;
1649 }
1651 iter = sdb_llist_get_iter(writer_list);
1652 while (sdb_llist_iter_has_next(iter)) {
1653 writer_t *writer = WRITER(sdb_llist_iter_get_next(iter));
1654 int s;
1655 assert(writer);
1656 s = writer->impl.store_service_attr(cname, service,
1657 key, value, last_update, writer->w_user_data);
1658 if (((s > 0) && (status >= 0)) || (s < 0))
1659 status = s;
1660 }
1661 sdb_llist_iter_destroy(iter);
1662 free(cname);
1663 return status;
1664 } /* sdb_plugin_store_service_attribute */
1666 int
1667 sdb_plugin_store_metric_attribute(const char *hostname, const char *metric,
1668 const char *key, const sdb_data_t *value, sdb_time_t last_update)
1669 {
1670 char *cname;
1672 sdb_llist_iter_t *iter;
1673 int status = 0;
1675 if ((! hostname) || (! metric) || (! key) || (! value))
1676 return -1;
1678 if (! sdb_llist_len(writer_list)) {
1679 sdb_log(SDB_LOG_ERR, "core: Cannot store metric attribute: "
1680 "no writers registered");
1681 return -1;
1682 }
1684 cname = sdb_plugin_cname(strdup(hostname));
1685 if (! cname) {
1686 sdb_log(SDB_LOG_ERR, "core: strdup failed");
1687 return -1;
1688 }
1690 iter = sdb_llist_get_iter(writer_list);
1691 while (sdb_llist_iter_has_next(iter)) {
1692 writer_t *writer = WRITER(sdb_llist_iter_get_next(iter));
1693 int s;
1694 assert(writer);
1695 s = writer->impl.store_metric_attr(cname, metric,
1696 key, value, last_update, writer->w_user_data);
1697 if (((s > 0) && (status >= 0)) || (s < 0))
1698 status = s;
1699 }
1700 sdb_llist_iter_destroy(iter);
1701 free(cname);
1702 return status;
1703 } /* sdb_plugin_store_metric_attribute */
1705 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */