Fix compile time issues
[collectd.git] / src / daemon / configfile.c
1 /**
2  * collectd - src/configfile.c
3  * Copyright (C) 2005-2011  Florian octo Forster
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  *
23  * Authors:
24  *   Florian octo Forster <octo at collectd.org>
25  *   Sebastian tokkee Harl <sh at tokkee.org>
26  **/
27
28 #include "collectd.h"
29
30 #include "liboconfig/oconfig.h"
31
32 #include "configfile.h"
33 #include "filter_chain.h"
34 #include "plugin.h"
35 #include "types_list.h"
36 #include "utils/common/common.h"
37
38 #if HAVE_WORDEXP_H
39 #include <wordexp.h>
40 #endif /* HAVE_WORDEXP_H */
41
42 #if HAVE_FNMATCH_H
43 #include <fnmatch.h>
44 #endif /* HAVE_FNMATCH_H */
45
46 #if HAVE_LIBGEN_H
47 #include <libgen.h>
48 #endif /* HAVE_LIBGEN_H */
49
50 #define ESCAPE_NULL(str) ((str) == NULL ? "(null)" : (str))
51
52 /*
53  * Private types
54  */
55 typedef struct cf_callback {
56   const char *type;
57   int (*callback)(const char *, const char *);
58   const char **keys;
59   int keys_num;
60   plugin_ctx_t ctx;
61   struct cf_callback *next;
62 } cf_callback_t;
63
64 typedef struct cf_complex_callback_s {
65   char *type;
66   int (*callback)(oconfig_item_t *);
67   plugin_ctx_t ctx;
68   struct cf_complex_callback_s *next;
69 } cf_complex_callback_t;
70
71 typedef struct cf_value_map_s {
72   const char *key;
73   int (*func)(oconfig_item_t *);
74 } cf_value_map_t;
75
76 typedef struct cf_global_option_s {
77   const char *key;
78   char *value;
79   bool from_cli; /* value set from CLI */
80   const char *def;
81 } cf_global_option_t;
82
83 /*
84  * Prototypes of callback functions
85  */
86 static int dispatch_value_typesdb(oconfig_item_t *ci);
87 static int dispatch_value_plugindir(oconfig_item_t *ci);
88 static int dispatch_loadplugin(oconfig_item_t *ci);
89 static int dispatch_block_plugin(oconfig_item_t *ci);
90
91 /*
92  * Private variables
93  */
94 static cf_callback_t *first_callback;
95 static cf_complex_callback_t *complex_callback_head;
96
97 static cf_value_map_t cf_value_map[] = {{"TypesDB", dispatch_value_typesdb},
98                                         {"PluginDir", dispatch_value_plugindir},
99                                         {"LoadPlugin", dispatch_loadplugin},
100                                         {"Plugin", dispatch_block_plugin}};
101 static int cf_value_map_num = STATIC_ARRAY_SIZE(cf_value_map);
102
103 static cf_global_option_t cf_global_options[] = {
104     {"BaseDir", NULL, 0, PKGLOCALSTATEDIR},
105     {"PIDFile", NULL, 0, PIDFILE},
106     {"Hostname", NULL, 0, NULL},
107     {"FQDNLookup", NULL, 0, "true"},
108     {"Interval", NULL, 0, NULL},
109     {"ReadThreads", NULL, 0, "5"},
110     {"WriteThreads", NULL, 0, "5"},
111     {"WriteQueueLimitHigh", NULL, 0, NULL},
112     {"WriteQueueLimitLow", NULL, 0, NULL},
113     {"Timeout", NULL, 0, "2"},
114     {"AutoLoadPlugin", NULL, 0, "false"},
115     {"CollectInternalStats", NULL, 0, "false"},
116     {"PreCacheChain", NULL, 0, "PreCache"},
117     {"PostCacheChain", NULL, 0, "PostCache"},
118     {"MaxReadInterval", NULL, 0, "86400"}};
119 static int cf_global_options_num = STATIC_ARRAY_SIZE(cf_global_options);
120
121 static int cf_default_typesdb = 1;
122
123 /*
124  * Functions to handle register/unregister, search, and other plugin related
125  * stuff
126  */
127 static cf_callback_t *cf_search(const char *type) {
128   cf_callback_t *cf_cb;
129
130   if (type == NULL)
131     return NULL;
132
133   for (cf_cb = first_callback; cf_cb != NULL; cf_cb = cf_cb->next)
134     if (strcasecmp(cf_cb->type, type) == 0)
135       break;
136
137   return cf_cb;
138 }
139
140 static int cf_dispatch(const char *type, const char *orig_key,
141                        const char *orig_value) {
142   cf_callback_t *cf_cb;
143   plugin_ctx_t old_ctx;
144   char *key;
145   char *value;
146   int ret;
147   int i = 0;
148
149   if (orig_key == NULL)
150     return EINVAL;
151
152   DEBUG("type = %s, key = %s, value = %s", ESCAPE_NULL(type), orig_key,
153         ESCAPE_NULL(orig_value));
154
155   if ((cf_cb = cf_search(type)) == NULL) {
156     WARNING("Found a configuration for the `%s' plugin, but "
157             "the plugin isn't loaded or didn't register "
158             "a configuration callback.",
159             type);
160     return -1;
161   }
162
163   if ((key = strdup(orig_key)) == NULL)
164     return 1;
165   if ((value = strdup(orig_value)) == NULL) {
166     free(key);
167     return 2;
168   }
169
170   ret = -1;
171
172   old_ctx = plugin_set_ctx(cf_cb->ctx);
173
174   for (i = 0; i < cf_cb->keys_num; i++) {
175     if ((cf_cb->keys[i] != NULL) && (strcasecmp(cf_cb->keys[i], key) == 0)) {
176       ret = (*cf_cb->callback)(key, value);
177       break;
178     }
179   }
180
181   plugin_set_ctx(old_ctx);
182
183   if (i >= cf_cb->keys_num)
184     WARNING("Plugin `%s' did not register for value `%s'.", type, key);
185
186   free(key);
187   free(value);
188
189   return ret;
190 } /* int cf_dispatch */
191
192 static int dispatch_global_option(const oconfig_item_t *ci) {
193   if (ci->values_num != 1) {
194     ERROR("configfile: Global option `%s' needs exactly one argument.",
195           ci->key);
196     return -1;
197   }
198
199   if (ci->values[0].type == OCONFIG_TYPE_STRING)
200     return global_option_set(ci->key, ci->values[0].value.string, 0);
201   else if (ci->values[0].type == OCONFIG_TYPE_NUMBER) {
202     char tmp[128];
203     ssnprintf(tmp, sizeof(tmp), "%lf", ci->values[0].value.number);
204     return global_option_set(ci->key, tmp, 0);
205   } else if (ci->values[0].type == OCONFIG_TYPE_BOOLEAN) {
206     if (ci->values[0].value.boolean)
207       return global_option_set(ci->key, "true", 0);
208     else
209       return global_option_set(ci->key, "false", 0);
210   }
211
212   ERROR("configfile: Global option `%s' argument has unknown type.", ci->key);
213
214   return -1;
215 } /* int dispatch_global_option */
216
217 static int dispatch_value_typesdb(oconfig_item_t *ci) {
218   assert(strcasecmp(ci->key, "TypesDB") == 0);
219
220   cf_default_typesdb = 0;
221
222   if (ci->values_num < 1) {
223     ERROR("configfile: `TypesDB' needs at least one argument.");
224     return -1;
225   }
226
227   for (int i = 0; i < ci->values_num; ++i) {
228     if (OCONFIG_TYPE_STRING != ci->values[i].type) {
229       WARNING("configfile: TypesDB: Skipping %i. argument which "
230               "is not a string.",
231               i + 1);
232       continue;
233     }
234
235     read_types_list(ci->values[i].value.string);
236   }
237   return 0;
238 } /* int dispatch_value_typesdb */
239
240 static int dispatch_value_plugindir(oconfig_item_t *ci) {
241   assert(strcasecmp(ci->key, "PluginDir") == 0);
242
243   if (ci->values_num != 1 || ci->values[0].type != OCONFIG_TYPE_STRING) {
244     ERROR("configfile: The `PluginDir' option needs exactly one string "
245           "argument.");
246     return -1;
247   }
248
249   plugin_set_dir(ci->values[0].value.string);
250   return 0;
251 }
252
253 static int dispatch_loadplugin(oconfig_item_t *ci) {
254   bool global = false;
255
256   assert(strcasecmp(ci->key, "LoadPlugin") == 0);
257
258   if (ci->values_num != 1 || ci->values[0].type != OCONFIG_TYPE_STRING) {
259     ERROR("configfile: The `LoadPlugin' block needs exactly one string "
260           "argument.");
261     return -1;
262   }
263
264   const char *name = ci->values[0].value.string;
265   if (strcmp("libvirt", name) == 0)
266     name = "virt";
267
268   /* default to the global interval set before loading this plugin */
269   plugin_ctx_t ctx = {
270       .interval = cf_get_default_interval(),
271       .name = strdup(name),
272   };
273   if (ctx.name == NULL)
274     return ENOMEM;
275
276   for (int i = 0; i < ci->children_num; ++i) {
277     oconfig_item_t *child = ci->children + i;
278
279     if (strcasecmp("Globals", child->key) == 0)
280       cf_util_get_boolean(child, &global);
281     else if (strcasecmp("Interval", child->key) == 0)
282       cf_util_get_cdtime(child, &ctx.interval);
283     else if (strcasecmp("FlushInterval", child->key) == 0)
284       cf_util_get_cdtime(child, &ctx.flush_interval);
285     else if (strcasecmp("FlushTimeout", child->key) == 0)
286       cf_util_get_cdtime(child, &ctx.flush_timeout);
287     else {
288       WARNING("Ignoring unknown LoadPlugin option \"%s\" "
289               "for plugin \"%s\"",
290               child->key, name);
291     }
292   }
293
294   plugin_ctx_t old_ctx = plugin_set_ctx(ctx);
295   int ret_val = plugin_load(name, global);
296   /* reset to the "global" context */
297   plugin_set_ctx(old_ctx);
298
299   return ret_val;
300 } /* int dispatch_value_loadplugin */
301
302 static int dispatch_value_plugin(const char *plugin, oconfig_item_t *ci) {
303   char buffer[4096];
304   char *buffer_ptr;
305   int buffer_free;
306
307   buffer_ptr = buffer;
308   buffer_free = sizeof(buffer);
309
310   for (int i = 0; i < ci->values_num; i++) {
311     int status = -1;
312
313     if (ci->values[i].type == OCONFIG_TYPE_STRING)
314       status =
315           ssnprintf(buffer_ptr, buffer_free, " %s", ci->values[i].value.string);
316     else if (ci->values[i].type == OCONFIG_TYPE_NUMBER)
317       status = ssnprintf(buffer_ptr, buffer_free, " %lf",
318                          ci->values[i].value.number);
319     else if (ci->values[i].type == OCONFIG_TYPE_BOOLEAN)
320       status = ssnprintf(buffer_ptr, buffer_free, " %s",
321                          ci->values[i].value.boolean ? "true" : "false");
322
323     if ((status < 0) || (status >= buffer_free))
324       return -1;
325     buffer_free -= status;
326     buffer_ptr += status;
327   }
328   /* skip the initial space */
329   buffer_ptr = buffer + 1;
330
331   return cf_dispatch(plugin, ci->key, buffer_ptr);
332 } /* int dispatch_value_plugin */
333
334 static int dispatch_value(oconfig_item_t *ci) {
335   int ret = 0;
336
337   for (int i = 0; i < cf_value_map_num; i++)
338     if (strcasecmp(cf_value_map[i].key, ci->key) == 0) {
339       ret = cf_value_map[i].func(ci);
340       break;
341     }
342
343   if (ret != 0)
344     return ret;
345
346   for (int i = 0; i < cf_global_options_num; i++)
347     if (strcasecmp(cf_global_options[i].key, ci->key) == 0) {
348       ret = dispatch_global_option(ci);
349       break;
350     }
351
352   return ret;
353 } /* int dispatch_value */
354
355 static int dispatch_block_plugin(oconfig_item_t *ci) {
356   assert(strcasecmp(ci->key, "Plugin") == 0);
357
358   if (ci->values_num < 1) {
359     ERROR("configfile: The `Plugin' block requires arguments.");
360     return -1;
361   }
362   if (ci->values[0].type != OCONFIG_TYPE_STRING) {
363     ERROR("configfile: First argument of `Plugin' block should be a string.");
364     return -1;
365   }
366
367   const char *name = ci->values[0].value.string;
368   if (strcmp("libvirt", name) == 0) {
369     /* TODO(octo): Remove this legacy. */
370     WARNING("The \"libvirt\" plugin has been renamed to \"virt\" to avoid "
371             "problems with the build system. "
372             "Your configuration is still using the old name. "
373             "Please change it to use \"virt\" as soon as possible. "
374             "This compatibility code will go away eventually.");
375     name = "virt";
376   }
377
378   if (IS_TRUE(global_option_get("AutoLoadPlugin"))) {
379     plugin_ctx_t ctx = {0};
380     plugin_ctx_t old_ctx;
381     int status;
382
383     /* default to the global interval set before loading this plugin */
384     ctx.interval = cf_get_default_interval();
385     ctx.name = strdup(name);
386
387     old_ctx = plugin_set_ctx(ctx);
388     status = plugin_load(name, /* flags = */ false);
389     /* reset to the "global" context */
390     plugin_set_ctx(old_ctx);
391
392     if (status != 0) {
393       ERROR("Automatically loading plugin \"%s\" failed "
394             "with status %i.",
395             name, status);
396       return status;
397     }
398   }
399
400   /* Check for a complex callback first */
401   for (cf_complex_callback_t *cb = complex_callback_head; cb != NULL;
402        cb = cb->next) {
403     if (strcasecmp(name, cb->type) == 0) {
404       plugin_ctx_t old_ctx;
405       int ret_val;
406
407       old_ctx = plugin_set_ctx(cb->ctx);
408       ret_val = (cb->callback(ci));
409       plugin_set_ctx(old_ctx);
410       return ret_val;
411     }
412   }
413
414   /* Hm, no complex plugin found. Dispatch the values one by one */
415   for (int i = 0, ret = 0; i < ci->children_num; i++) {
416     if (ci->children[i].children == NULL) {
417       oconfig_item_t *child = ci->children + i;
418       ret = dispatch_value_plugin(name, child);
419       if (ret != 0) {
420         ERROR("Plugin %s failed to handle option %s, return code: %i", name,
421               child->key, ret);
422         return ret;
423       }
424     } else {
425       WARNING("There is a `%s' block within the "
426               "configuration for the %s plugin. "
427               "The plugin either only expects "
428               "\"simple\" configuration statements "
429               "or wasn't loaded using `LoadPlugin'."
430               " Please check your configuration.",
431               ci->children[i].key, name);
432     }
433   }
434
435   return 0;
436 }
437
438 static int dispatch_block(oconfig_item_t *ci) {
439   if (strcasecmp(ci->key, "LoadPlugin") == 0)
440     return dispatch_loadplugin(ci);
441   else if (strcasecmp(ci->key, "Plugin") == 0)
442     return dispatch_block_plugin(ci);
443   else if (strcasecmp(ci->key, "Chain") == 0)
444     return fc_configure(ci);
445
446   return 0;
447 }
448
449 static int cf_ci_replace_child(oconfig_item_t *dst, oconfig_item_t *src,
450                                int offset) {
451   oconfig_item_t *temp;
452
453   assert(offset >= 0);
454   assert(dst->children_num > offset);
455
456   /* Free the memory used by the replaced child. Usually that's the
457    * `Include "blah"' statement. */
458   temp = dst->children + offset;
459   for (int i = 0; i < temp->values_num; i++) {
460     if (temp->values[i].type == OCONFIG_TYPE_STRING) {
461       sfree(temp->values[i].value.string);
462     }
463   }
464   sfree(temp->values);
465   temp = NULL;
466
467   /* If (src->children_num == 0) the array size is decreased. If offset
468    * is _not_ the last element, (offset < (dst->children_num - 1)), then
469    * we need to move the trailing elements before resizing the array. */
470   if ((src->children_num == 0) && (offset < (dst->children_num - 1))) {
471     int nmemb = dst->children_num - (offset + 1);
472     memmove(dst->children + offset, dst->children + offset + 1,
473             sizeof(oconfig_item_t) * nmemb);
474   }
475
476   /* Resize the memory containing the children to be big enough to hold
477    * all children. */
478   if (dst->children_num + src->children_num - 1 == 0) {
479     dst->children_num = 0;
480     return 0;
481   }
482
483   temp =
484       realloc(dst->children, sizeof(oconfig_item_t) *
485                                  (dst->children_num + src->children_num - 1));
486   if (temp == NULL) {
487     ERROR("configfile: realloc failed.");
488     return -1;
489   }
490   dst->children = temp;
491
492   /* If there are children behind the include statement, and they have
493    * not yet been moved because (src->children_num == 0), then move them
494    * to the end of the list, so that the new children have room before
495    * them. */
496   if ((src->children_num > 0) && ((dst->children_num - (offset + 1)) > 0)) {
497     int nmemb = dst->children_num - (offset + 1);
498     int old_offset = offset + 1;
499     int new_offset = offset + src->children_num;
500
501     memmove(dst->children + new_offset, dst->children + old_offset,
502             sizeof(oconfig_item_t) * nmemb);
503   }
504
505   /* Last but not least: If there are new children, copy them to the
506    * memory reserved for them. */
507   if (src->children_num > 0) {
508     memcpy(dst->children + offset, src->children,
509            sizeof(oconfig_item_t) * src->children_num);
510   }
511
512   /* Update the number of children. */
513   dst->children_num += (src->children_num - 1);
514
515   return 0;
516 } /* int cf_ci_replace_child */
517
518 static int cf_ci_append_children(oconfig_item_t *dst, oconfig_item_t *src) {
519   oconfig_item_t *temp;
520
521   if ((src == NULL) || (src->children_num == 0))
522     return 0;
523
524   temp = realloc(dst->children, sizeof(oconfig_item_t) *
525                                     (dst->children_num + src->children_num));
526   if (temp == NULL) {
527     ERROR("configfile: realloc failed.");
528     return -1;
529   }
530   dst->children = temp;
531
532   memcpy(dst->children + dst->children_num, src->children,
533          sizeof(oconfig_item_t) * src->children_num);
534   dst->children_num += src->children_num;
535
536   return 0;
537 } /* int cf_ci_append_children */
538
539 #define CF_MAX_DEPTH 8
540 static oconfig_item_t *cf_read_generic(const char *path, const char *pattern,
541                                        int depth);
542
543 static int cf_include_all(oconfig_item_t *root, int depth) {
544   for (int i = 0; i < root->children_num; i++) {
545     oconfig_item_t *new;
546     oconfig_item_t *old;
547
548     char *pattern = NULL;
549
550     if (strcasecmp(root->children[i].key, "Include") != 0)
551       continue;
552
553     old = root->children + i;
554
555     if ((old->values_num != 1) ||
556         (old->values[0].type != OCONFIG_TYPE_STRING)) {
557       ERROR("configfile: `Include' needs exactly one string argument.");
558       continue;
559     }
560
561     for (int j = 0; j < old->children_num; ++j) {
562       oconfig_item_t *child = old->children + j;
563
564       if (strcasecmp(child->key, "Filter") == 0)
565         cf_util_get_string(child, &pattern);
566       else
567         ERROR("configfile: Option `%s' not allowed in <Include> block.",
568               child->key);
569     }
570
571     new = cf_read_generic(old->values[0].value.string, pattern, depth + 1);
572     sfree(pattern);
573
574     if (new == NULL)
575       return -1;
576
577     /* Now replace the i'th child in `root' with `new'. */
578     if (cf_ci_replace_child(root, new, i) < 0) {
579       sfree(new->values);
580       sfree(new);
581       return -1;
582     }
583
584     /* ... and go back to the new i'th child. */
585     --i;
586
587     sfree(new->values);
588     sfree(new);
589   } /* for (i = 0; i < root->children_num; i++) */
590
591   return 0;
592 } /* int cf_include_all */
593
594 static oconfig_item_t *cf_read_file(const char *file, const char *pattern,
595                                     int depth) {
596   oconfig_item_t *root;
597   int status;
598
599   assert(depth < CF_MAX_DEPTH);
600
601   if (pattern != NULL) {
602 #if HAVE_FNMATCH_H && HAVE_LIBGEN_H
603     char *tmp = sstrdup(file);
604     char *filename = basename(tmp);
605
606     if ((filename != NULL) && (fnmatch(pattern, filename, 0) != 0)) {
607       DEBUG("configfile: Not including `%s' because it "
608             "does not match pattern `%s'.",
609             filename, pattern);
610       free(tmp);
611       return NULL;
612     }
613
614     free(tmp);
615 #else
616     ERROR("configfile: Cannot apply pattern filter '%s' "
617           "to file '%s': functions basename() and / or "
618           "fnmatch() not available.",
619           pattern, file);
620 #endif /* HAVE_FNMATCH_H && HAVE_LIBGEN_H */
621   }
622
623   root = oconfig_parse_file(file);
624   if (root == NULL) {
625     ERROR("configfile: Cannot read file `%s'.", file);
626     return NULL;
627   }
628
629   status = cf_include_all(root, depth);
630   if (status != 0) {
631     oconfig_free(root);
632     return NULL;
633   }
634
635   return root;
636 } /* oconfig_item_t *cf_read_file */
637
638 static int cf_compare_string(const void *p1, const void *p2) {
639   return strcmp(*(const char **)p1, *(const char **)p2);
640 }
641
642 static oconfig_item_t *cf_read_dir(const char *dir, const char *pattern,
643                                    int depth) {
644   oconfig_item_t *root = NULL;
645   DIR *dh;
646   struct dirent *de;
647   char **filenames = NULL;
648   int filenames_num = 0;
649   int status;
650
651   assert(depth < CF_MAX_DEPTH);
652
653   dh = opendir(dir);
654   if (dh == NULL) {
655     ERROR("configfile: opendir failed: %s", STRERRNO);
656     return NULL;
657   }
658
659   root = calloc(1, sizeof(*root));
660   if (root == NULL) {
661     ERROR("configfile: calloc failed.");
662     closedir(dh);
663     return NULL;
664   }
665
666   while ((de = readdir(dh)) != NULL) {
667     char name[1024];
668     char **tmp;
669
670     if ((de->d_name[0] == '.') || (de->d_name[0] == 0))
671       continue;
672
673     status = ssnprintf(name, sizeof(name), "%s/%s", dir, de->d_name);
674     if ((status < 0) || ((size_t)status >= sizeof(name))) {
675       ERROR("configfile: Not including `%s/%s' because its"
676             " name is too long.",
677             dir, de->d_name);
678       closedir(dh);
679       for (int i = 0; i < filenames_num; ++i)
680         free(filenames[i]);
681       free(filenames);
682       free(root);
683       return NULL;
684     }
685
686     ++filenames_num;
687     tmp = realloc(filenames, filenames_num * sizeof(*filenames));
688     if (tmp == NULL) {
689       ERROR("configfile: realloc failed.");
690       closedir(dh);
691       for (int i = 0; i < filenames_num - 1; ++i)
692         free(filenames[i]);
693       free(filenames);
694       free(root);
695       return NULL;
696     }
697     filenames = tmp;
698
699     filenames[filenames_num - 1] = sstrdup(name);
700   }
701
702   if (filenames == NULL) {
703     closedir(dh);
704     return root;
705   }
706
707   qsort((void *)filenames, filenames_num, sizeof(*filenames),
708         cf_compare_string);
709
710   for (int i = 0; i < filenames_num; ++i) {
711     oconfig_item_t *temp;
712     char *name = filenames[i];
713
714     temp = cf_read_generic(name, pattern, depth);
715     if (temp == NULL) {
716       /* An error should already have been reported. */
717       sfree(name);
718       continue;
719     }
720
721     cf_ci_append_children(root, temp);
722     sfree(temp->children);
723     sfree(temp);
724
725     free(name);
726   }
727
728   closedir(dh);
729   free(filenames);
730   return root;
731 } /* oconfig_item_t *cf_read_dir */
732
733 /*
734  * cf_read_generic
735  *
736  * Path is stat'ed and either cf_read_file or cf_read_dir is called
737  * accordingly.
738  *
739  * There are two versions of this function: If `wordexp' exists shell wildcards
740  * will be expanded and the function will include all matches found. If
741  * `wordexp' (or, more precisely, its header file) is not available the
742  * simpler function is used which does not do any such expansion.
743  */
744 #if HAVE_WORDEXP_H
745 static oconfig_item_t *cf_read_generic(const char *path, const char *pattern,
746                                        int depth) {
747   oconfig_item_t *root = NULL;
748   int status;
749   const char *path_ptr;
750   wordexp_t we;
751
752   if (depth >= CF_MAX_DEPTH) {
753     ERROR("configfile: Not including `%s' because the maximum "
754           "nesting depth has been reached.",
755           path);
756     return NULL;
757   }
758
759   status = wordexp(path, &we, WRDE_NOCMD);
760   if (status != 0) {
761     ERROR("configfile: wordexp (%s) failed.", path);
762     return NULL;
763   }
764
765   root = calloc(1, sizeof(*root));
766   if (root == NULL) {
767     ERROR("configfile: calloc failed.");
768     return NULL;
769   }
770
771   /* wordexp() might return a sorted list already. That's not
772    * documented though, so let's make sure we get what we want. */
773   qsort((void *)we.we_wordv, we.we_wordc, sizeof(*we.we_wordv),
774         cf_compare_string);
775
776   for (size_t i = 0; i < we.we_wordc; i++) {
777     oconfig_item_t *temp;
778     struct stat statbuf;
779
780     path_ptr = we.we_wordv[i];
781
782     status = stat(path_ptr, &statbuf);
783     if (status != 0) {
784       WARNING("configfile: stat (%s) failed: %s", path_ptr, STRERRNO);
785       continue;
786     }
787
788     if (S_ISREG(statbuf.st_mode))
789       temp = cf_read_file(path_ptr, pattern, depth);
790     else if (S_ISDIR(statbuf.st_mode))
791       temp = cf_read_dir(path_ptr, pattern, depth);
792     else {
793       WARNING("configfile: %s is neither a file nor a "
794               "directory.",
795               path);
796       continue;
797     }
798
799     if (temp == NULL) {
800       oconfig_free(root);
801       return NULL;
802     }
803
804     cf_ci_append_children(root, temp);
805     sfree(temp->children);
806     sfree(temp);
807   }
808
809   wordfree(&we);
810
811   return root;
812 } /* oconfig_item_t *cf_read_generic */
813   /* #endif HAVE_WORDEXP_H */
814
815 #else  /* if !HAVE_WORDEXP_H */
816 static oconfig_item_t *cf_read_generic(const char *path, const char *pattern,
817                                        int depth) {
818   struct stat statbuf;
819   int status;
820
821   if (depth >= CF_MAX_DEPTH) {
822     ERROR("configfile: Not including `%s' because the maximum "
823           "nesting depth has been reached.",
824           path);
825     return NULL;
826   }
827
828   status = stat(path, &statbuf);
829   if (status != 0) {
830     ERROR("configfile: stat (%s) failed: %s", path, STRERRNO);
831     return NULL;
832   }
833
834   if (S_ISREG(statbuf.st_mode))
835     return cf_read_file(path, pattern, depth);
836   else if (S_ISDIR(statbuf.st_mode))
837     return cf_read_dir(path, pattern, depth);
838
839   ERROR("configfile: %s is neither a file nor a directory.", path);
840   return NULL;
841 } /* oconfig_item_t *cf_read_generic */
842 #endif /* !HAVE_WORDEXP_H */
843
844 /*
845  * Public functions
846  */
847 int global_option_set(const char *option, const char *value, bool from_cli) {
848   int i;
849   DEBUG("option = %s; value = %s;", option, value);
850
851   for (i = 0; i < cf_global_options_num; i++)
852     if (strcasecmp(cf_global_options[i].key, option) == 0)
853       break;
854
855   if (i >= cf_global_options_num) {
856     ERROR("configfile: Cannot set unknown global option `%s'.", option);
857     return -1;
858   }
859
860   if (cf_global_options[i].from_cli && (!from_cli)) {
861     DEBUG("configfile: Ignoring %s `%s' option because "
862           "it was overriden by a command-line option.",
863           option, value);
864     return 0;
865   }
866
867   sfree(cf_global_options[i].value);
868
869   if (value != NULL)
870     cf_global_options[i].value = strdup(value);
871   else
872     cf_global_options[i].value = NULL;
873
874   cf_global_options[i].from_cli = from_cli;
875
876   return 0;
877 }
878
879 const char *global_option_get(const char *option) {
880   int i;
881   for (i = 0; i < cf_global_options_num; i++)
882     if (strcasecmp(cf_global_options[i].key, option) == 0)
883       break;
884
885   if (i >= cf_global_options_num) {
886     ERROR("configfile: Cannot get unknown global option `%s'.", option);
887     return NULL;
888   }
889
890   return (cf_global_options[i].value != NULL) ? cf_global_options[i].value
891                                               : cf_global_options[i].def;
892 } /* char *global_option_get */
893
894 long global_option_get_long(const char *option, long default_value) {
895   const char *str;
896   long value;
897
898   str = global_option_get(option);
899   if (NULL == str)
900     return default_value;
901
902   errno = 0;
903   value = strtol(str, /* endptr = */ NULL, /* base = */ 0);
904   if (errno != 0)
905     return default_value;
906
907   return value;
908 } /* char *global_option_get_long */
909
910 cdtime_t global_option_get_time(const char *name, cdtime_t def) /* {{{ */
911 {
912   char const *optstr;
913   char *endptr = NULL;
914   double v;
915
916   optstr = global_option_get(name);
917   if (optstr == NULL)
918     return def;
919
920   errno = 0;
921   v = strtod(optstr, &endptr);
922   if ((endptr == NULL) || (*endptr != 0) || (errno != 0))
923     return def;
924   else if (v <= 0.0)
925     return def;
926
927   return DOUBLE_TO_CDTIME_T(v);
928 } /* }}} cdtime_t global_option_get_time */
929
930 cdtime_t cf_get_default_interval(void) {
931   return global_option_get_time("Interval",
932                                 DOUBLE_TO_CDTIME_T(COLLECTD_DEFAULT_INTERVAL));
933 }
934
935 void cf_unregister(const char *type) {
936   for (cf_callback_t *prev = NULL, *this = first_callback; this != NULL;
937        prev = this, this = this->next)
938     if (strcasecmp(this->type, type) == 0) {
939       if (prev == NULL)
940         first_callback = this->next;
941       else
942         prev->next = this->next;
943
944       free(this);
945       break;
946     }
947 } /* void cf_unregister */
948
949 void cf_unregister_complex(const char *type) {
950   for (cf_complex_callback_t *prev = NULL, *this = complex_callback_head;
951        this != NULL; prev = this, this = this->next)
952     if (strcasecmp(this->type, type) == 0) {
953       if (prev == NULL)
954         complex_callback_head = this->next;
955       else
956         prev->next = this->next;
957
958       sfree(this->type);
959       sfree(this);
960       break;
961     }
962 } /* void cf_unregister */
963
964 void cf_register(const char *type, int (*callback)(const char *, const char *),
965                  const char **keys, int keys_num) {
966   cf_callback_t *cf_cb;
967
968   /* Remove this module from the list, if it already exists */
969   cf_unregister(type);
970
971   /* This pointer will be free'd in `cf_unregister' */
972   if ((cf_cb = malloc(sizeof(*cf_cb))) == NULL)
973     return;
974
975   cf_cb->type = type;
976   cf_cb->callback = callback;
977   cf_cb->keys = keys;
978   cf_cb->keys_num = keys_num;
979   cf_cb->ctx = plugin_get_ctx();
980
981   cf_cb->next = first_callback;
982   first_callback = cf_cb;
983 } /* void cf_register */
984
985 int cf_register_complex(const char *type, int (*callback)(oconfig_item_t *)) {
986   cf_complex_callback_t *new;
987
988   new = malloc(sizeof(*new));
989   if (new == NULL)
990     return -1;
991
992   new->type = strdup(type);
993   if (new->type == NULL) {
994     sfree(new);
995     return -1;
996   }
997
998   new->callback = callback;
999   new->next = NULL;
1000
1001   new->ctx = plugin_get_ctx();
1002
1003   if (complex_callback_head == NULL) {
1004     complex_callback_head = new;
1005   } else {
1006     cf_complex_callback_t *last = complex_callback_head;
1007     while (last->next != NULL)
1008       last = last->next;
1009     last->next = new;
1010   }
1011
1012   return 0;
1013 } /* int cf_register_complex */
1014
1015 int cf_read(const char *filename) {
1016   oconfig_item_t *conf;
1017   int ret = 0;
1018
1019   conf = cf_read_generic(filename, /* pattern = */ NULL, /* depth = */ 0);
1020   if (conf == NULL) {
1021     ERROR("Unable to read config file %s.", filename);
1022     return -1;
1023   } else if (conf->children_num == 0) {
1024     ERROR("Configuration file %s is empty.", filename);
1025     oconfig_free(conf);
1026     return -1;
1027   }
1028
1029   for (int i = 0; i < conf->children_num; i++) {
1030     if (conf->children[i].children == NULL) {
1031       if (dispatch_value(conf->children + i) != 0)
1032         ret = -1;
1033     } else {
1034       if (dispatch_block(conf->children + i) != 0)
1035         ret = -1;
1036     }
1037   }
1038
1039   oconfig_free(conf);
1040
1041   /* Read the default types.db if no `TypesDB' option was given. */
1042   if (cf_default_typesdb) {
1043     if (read_types_list(PKGDATADIR "/types.db") != 0)
1044       ret = -1;
1045   }
1046
1047   return ret;
1048
1049 } /* int cf_read */
1050
1051 /* Assures the config option is a string, duplicates it and returns the copy in
1052  * "ret_string". If necessary "*ret_string" is freed first. Returns zero upon
1053  * success. */
1054 int cf_util_get_string(const oconfig_item_t *ci, char **ret_string) /* {{{ */
1055 {
1056   if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING)) {
1057     P_ERROR("The `%s' option requires exactly one string argument.", ci->key);
1058     return -1;
1059   }
1060
1061   char *string = strdup(ci->values[0].value.string);
1062   if (string == NULL)
1063     return -1;
1064
1065   if (*ret_string != NULL)
1066     sfree(*ret_string);
1067   *ret_string = string;
1068
1069   return 0;
1070 } /* }}} int cf_util_get_string */
1071
1072 /* Assures the config option is a string and copies it to the provided buffer.
1073  * Assures NUL-termination. */
1074 int cf_util_get_string_buffer(const oconfig_item_t *ci, char *buffer, /* {{{ */
1075                               size_t buffer_size) {
1076   if ((ci == NULL) || (buffer == NULL) || (buffer_size < 1))
1077     return EINVAL;
1078
1079   if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING)) {
1080     P_ERROR("The `%s' option requires exactly one string argument.", ci->key);
1081     return -1;
1082   }
1083
1084   strncpy(buffer, ci->values[0].value.string, buffer_size);
1085   buffer[buffer_size - 1] = '\0';
1086
1087   return 0;
1088 } /* }}} int cf_util_get_string_buffer */
1089
1090 /* Assures the config option is a number and returns it as an int. */
1091 int cf_util_get_int(const oconfig_item_t *ci, int *ret_value) /* {{{ */
1092 {
1093   if ((ci == NULL) || (ret_value == NULL))
1094     return EINVAL;
1095
1096   if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_NUMBER)) {
1097     P_ERROR("The `%s' option requires exactly one numeric argument.", ci->key);
1098     return -1;
1099   }
1100
1101   *ret_value = (int)ci->values[0].value.number;
1102
1103   return 0;
1104 } /* }}} int cf_util_get_int */
1105
1106 int cf_util_get_double(const oconfig_item_t *ci, double *ret_value) /* {{{ */
1107 {
1108   if ((ci == NULL) || (ret_value == NULL))
1109     return EINVAL;
1110
1111   if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_NUMBER)) {
1112     P_ERROR("The `%s' option requires exactly one numeric argument.", ci->key);
1113     return -1;
1114   }
1115
1116   *ret_value = ci->values[0].value.number;
1117
1118   return 0;
1119 } /* }}} int cf_util_get_double */
1120
1121 int cf_util_get_boolean(const oconfig_item_t *ci, bool *ret_bool) /* {{{ */
1122 {
1123   if ((ci == NULL) || (ret_bool == NULL))
1124     return EINVAL;
1125
1126   if ((ci->values_num != 1) || ((ci->values[0].type != OCONFIG_TYPE_BOOLEAN) &&
1127                                 (ci->values[0].type != OCONFIG_TYPE_STRING))) {
1128     P_ERROR("The `%s' option requires exactly one boolean argument.", ci->key);
1129     return -1;
1130   }
1131
1132   switch (ci->values[0].type) {
1133   case OCONFIG_TYPE_BOOLEAN:
1134     *ret_bool = ci->values[0].value.boolean ? true : false;
1135     break;
1136   case OCONFIG_TYPE_STRING:
1137     P_WARNING("Using string value `%s' for boolean option `%s' is deprecated "
1138               "and will be removed in future releases. Use unquoted true or "
1139               "false instead.",
1140               ci->values[0].value.string, ci->key);
1141
1142     if (IS_TRUE(ci->values[0].value.string))
1143       *ret_bool = true;
1144     else if (IS_FALSE(ci->values[0].value.string))
1145       *ret_bool = false;
1146     else {
1147       P_ERROR("Cannot parse string value `%s' of the `%s' option as a boolean "
1148               "value.",
1149               ci->values[0].value.string, ci->key);
1150       return -1;
1151     }
1152     break;
1153   }
1154
1155   return 0;
1156 } /* }}} int cf_util_get_boolean */
1157
1158 int cf_util_get_flag(const oconfig_item_t *ci, /* {{{ */
1159                      unsigned int *ret_value, unsigned int flag) {
1160   int status;
1161
1162   if (ret_value == NULL)
1163     return EINVAL;
1164
1165   bool b = false;
1166   status = cf_util_get_boolean(ci, &b);
1167   if (status != 0)
1168     return status;
1169
1170   if (b) {
1171     *ret_value |= flag;
1172   } else {
1173     *ret_value &= ~flag;
1174   }
1175
1176   return 0;
1177 } /* }}} int cf_util_get_flag */
1178
1179 /* Assures that the config option is a string or a number if the correct range
1180  * of 1-65535. The string is then converted to a port number using
1181  * `service_name_to_port_number' and returned.
1182  * Returns the port number in the range [1-65535] or less than zero upon
1183  * failure. */
1184 int cf_util_get_port_number(const oconfig_item_t *ci) /* {{{ */
1185 {
1186   int tmp;
1187
1188   if ((ci->values_num != 1) || ((ci->values[0].type != OCONFIG_TYPE_STRING) &&
1189                                 (ci->values[0].type != OCONFIG_TYPE_NUMBER))) {
1190     P_ERROR("The `%s' option requires exactly one string argument.", ci->key);
1191     return -1;
1192   }
1193
1194   if (ci->values[0].type == OCONFIG_TYPE_STRING)
1195     return service_name_to_port_number(ci->values[0].value.string);
1196
1197   assert(ci->values[0].type == OCONFIG_TYPE_NUMBER);
1198   tmp = (int)(ci->values[0].value.number + 0.5);
1199   if ((tmp < 1) || (tmp > 65535)) {
1200     P_ERROR("The `%s' option requires a service name or a port number. The "
1201             "number you specified, %i, is not in the valid range of 1-65535.",
1202             ci->key, tmp);
1203     return -1;
1204   }
1205
1206   return tmp;
1207 } /* }}} int cf_util_get_port_number */
1208
1209 int cf_util_get_service(const oconfig_item_t *ci, char **ret_string) /* {{{ */
1210 {
1211   int port;
1212   char *service;
1213   int status;
1214
1215   if (ci->values_num != 1) {
1216     P_ERROR("The `%s` option requires exactly one argument.", ci->key);
1217     return -1;
1218   }
1219
1220   if (ci->values[0].type == OCONFIG_TYPE_STRING)
1221     return cf_util_get_string(ci, ret_string);
1222   if (ci->values[0].type != OCONFIG_TYPE_NUMBER) {
1223     P_ERROR("The `%s` option requires exactly one string or numeric argument.",
1224             ci->key);
1225   }
1226
1227   port = 0;
1228   status = cf_util_get_int(ci, &port);
1229   if (status != 0)
1230     return status;
1231   else if ((port < 1) || (port > 65535)) {
1232     P_ERROR("The port number given for the `%s` option is out of range (%i).",
1233             ci->key, port);
1234     return -1;
1235   }
1236
1237   service = malloc(6);
1238   if (service == NULL) {
1239     P_ERROR("cf_util_get_service: Out of memory.");
1240     return -1;
1241   }
1242   ssnprintf(service, 6, "%i", port);
1243
1244   sfree(*ret_string);
1245   *ret_string = service;
1246
1247   return 0;
1248 } /* }}} int cf_util_get_service */
1249
1250 int cf_util_get_cdtime(const oconfig_item_t *ci, cdtime_t *ret_value) /* {{{ */
1251 {
1252   if ((ci == NULL) || (ret_value == NULL))
1253     return EINVAL;
1254
1255   if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_NUMBER)) {
1256     P_ERROR("The `%s' option requires exactly one numeric argument.", ci->key);
1257     return -1;
1258   }
1259
1260   if (ci->values[0].value.number < 0.0) {
1261     P_ERROR("The numeric argument of the `%s' option must not be negative.",
1262             ci->key);
1263     return -1;
1264   }
1265
1266   *ret_value = DOUBLE_TO_CDTIME_T(ci->values[0].value.number);
1267
1268   return 0;
1269 } /* }}} int cf_util_get_cdtime */