X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Fconfigfile.c;h=706e2d137968ad44e8796d078ef12b86cc26b5aa;hb=8debae762165367f8a4f85b95f56284c7badf87d;hp=a5ae4961fda2bfd5901c41d19b164a75eb781410;hpb=2d897a731bd23f7a33b89e7b7e3004b6b26b5a94;p=collectd.git diff --git a/src/configfile.c b/src/configfile.c index a5ae4961..706e2d13 100644 --- a/src/configfile.c +++ b/src/configfile.c @@ -1,6 +1,6 @@ /** * collectd - src/configfile.c - * Copyright (C) 2005,2006 Florian octo Forster + * Copyright (C) 2005-2008 Florian octo Forster * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -27,8 +27,8 @@ #include "common.h" #include "plugin.h" #include "configfile.h" -#include "network.h" -#include "utils_debug.h" +#include "types_list.h" +#include "utils_threshold.h" #define ESCAPE_NULL(str) ((str) == NULL ? "(null)" : (str)) @@ -44,6 +44,13 @@ typedef struct cf_callback struct cf_callback *next; } cf_callback_t; +typedef struct cf_complex_callback_s +{ + char *type; + int (*callback) (oconfig_item_t *); + struct cf_complex_callback_s *next; +} cf_complex_callback_t; + typedef struct cf_value_map_s { char *key; @@ -60,6 +67,7 @@ typedef struct cf_global_option_s /* * Prototypes of callback functions */ +static int dispatch_value_typesdb (const oconfig_item_t *ci); static int dispatch_value_plugindir (const oconfig_item_t *ci); static int dispatch_value_loadplugin (const oconfig_item_t *ci); @@ -67,9 +75,11 @@ static int dispatch_value_loadplugin (const oconfig_item_t *ci); * Private variables */ static cf_callback_t *first_callback = NULL; +static cf_complex_callback_t *complex_callback_head = NULL; static cf_value_map_t cf_value_map[] = { + {"TypesDB", dispatch_value_typesdb}, {"PluginDir", dispatch_value_plugindir}, {"LoadPlugin", dispatch_value_loadplugin} }; @@ -77,14 +87,17 @@ static int cf_value_map_num = STATIC_ARRAY_LEN (cf_value_map); static cf_global_option_t cf_global_options[] = { - {"BaseDir", NULL, PKGLOCALSTATEDIR}, - {"LogFile", NULL, LOGFILE}, - {"PIDFile", NULL, PIDFILE}, - {"Hostname", NULL, NULL}, - {"Interval", NULL, "10"} + {"BaseDir", NULL, PKGLOCALSTATEDIR}, + {"PIDFile", NULL, PIDFILE}, + {"Hostname", NULL, NULL}, + {"FQDNLookup", NULL, "false"}, + {"Interval", NULL, "10"}, + {"ReadThreads", NULL, "5"} }; static int cf_global_options_num = STATIC_ARRAY_LEN (cf_global_options); +static int cf_default_typesdb = 1; + /* * Functions to handle register/unregister, search, and other plugin related * stuff @@ -112,14 +125,16 @@ static int cf_dispatch (const char *type, const char *orig_key, int ret; int i; - DBG ("type = %s, key = %s, value = %s", + DEBUG ("type = %s, key = %s, value = %s", ESCAPE_NULL(type), ESCAPE_NULL(orig_key), ESCAPE_NULL(orig_value)); if ((cf_cb = cf_search (type)) == NULL) { - syslog (LOG_WARNING, "Plugin `%s' did not register a callback.", type); + WARNING ("Found a configuration for the `%s' plugin, but " + "the plugin isn't loaded or didn't register " + "a configuration callback.", type); return (-1); } @@ -143,12 +158,12 @@ static int cf_dispatch (const char *type, const char *orig_key, } if (i >= cf_cb->keys_num) - syslog (LOG_WARNING, "Plugin `%s' did not register for value `%s'.", type, key); + WARNING ("Plugin `%s' did not register for value `%s'.", type, key); free (key); free (value); - DBG ("return (%i)", ret); + DEBUG ("return (%i)", ret); return (ret); } /* int cf_dispatch */ @@ -157,11 +172,46 @@ static int dispatch_global_option (const oconfig_item_t *ci) { if (ci->values_num != 1) return (-1); - if (ci->values[0].type != OCONFIG_TYPE_STRING) + if (ci->values[0].type == OCONFIG_TYPE_STRING) + return (global_option_set (ci->key, ci->values[0].value.string)); + else if (ci->values[0].type == OCONFIG_TYPE_NUMBER) + { + char tmp[128]; + snprintf (tmp, sizeof (tmp), "%lf", ci->values[0].value.number); + tmp[127] = '\0'; + return (global_option_set (ci->key, tmp)); + } + else if (ci->values[0].type == OCONFIG_TYPE_BOOLEAN) + { + if (ci->values[0].value.boolean) + return (global_option_set (ci->key, "true")); + else + return (global_option_set (ci->key, "false")); + } + + return (-1); +} /* int dispatch_global_option */ + +static int dispatch_value_typesdb (const oconfig_item_t *ci) +{ + int i = 0; + + assert (strcasecmp (ci->key, "TypesDB") == 0); + + cf_default_typesdb = 0; + + if (ci->values_num < 1) return (-1); - return (global_option_set (ci->key, ci->values[0].value.string)); -} + for (i = 0; i < ci->values_num; ++i) + { + if (OCONFIG_TYPE_STRING != ci->values[i].type) + continue; + + read_types_list (ci->values[i].value.string); + } + return (0); +} /* int dispatch_value_typesdb */ static int dispatch_value_plugindir (const oconfig_item_t *ci) { @@ -251,21 +301,29 @@ static int dispatch_block_plugin (oconfig_item_t *ci) int i; char *name; + cf_complex_callback_t *cb; + if (strcasecmp (ci->key, "Plugin") != 0) return (-1); - if (ci->values_num != 1) + if (ci->values_num < 1) return (-1); if (ci->values[0].type != OCONFIG_TYPE_STRING) return (-1); name = ci->values[0].value.string; + /* Check for a complex callback first */ + for (cb = complex_callback_head; cb != NULL; cb = cb->next) + if (strcasecmp (name, cb->type) == 0) + return (cb->callback (ci)); + + /* Hm, no complex plugin found. Dispatch the values one by one */ for (i = 0; i < ci->children_num; i++) { if (ci->children[i].children == NULL) dispatch_value_plugin (name, ci->children + i); else - {DBG ("No nested config blocks allow for plugins. Yet.");} + {DEBUG ("No nested config blocks allow for this plugin.");} } return (0); @@ -276,10 +334,134 @@ static int dispatch_block (oconfig_item_t *ci) { if (strcasecmp (ci->key, "Plugin") == 0) return (dispatch_block_plugin (ci)); + else if (strcasecmp (ci->key, "Threshold") == 0) + return (ut_config (ci)); return (0); } +#define CF_MAX_DEPTH 8 +static oconfig_item_t *cf_read_file (const char *file, int depth); + +static int cf_include_all (oconfig_item_t *root, int depth) +{ + int i; + + for (i = 0; i < root->children_num; i++) + { + oconfig_item_t *new; + oconfig_item_t *old; + + /* Ignore all blocks, including `Include' blocks. */ + if (root->children[i].children_num != 0) + continue; + + if (strcasecmp (root->children[i].key, "Include") != 0) + continue; + + old = root->children + i; + + if ((old->values_num != 1) + || (old->values[0].type != OCONFIG_TYPE_STRING)) + { + ERROR ("configfile: `Include' needs exactly one string argument."); + continue; + } + + new = cf_read_file (old->values[0].value.string, depth + 1); + if (new == NULL) + continue; + + /* There are more children now. We need to expand + * root->children. */ + if (new->children_num > 1) + { + oconfig_item_t *temp; + + DEBUG ("configfile: Resizing root-children from %i to %i elements.", + root->children_num, + root->children_num + new->children_num - 1); + + temp = (oconfig_item_t *) realloc (root->children, + sizeof (oconfig_item_t) + * (root->children_num + new->children_num - 1)); + if (temp == NULL) + { + ERROR ("configfile: realloc failed."); + oconfig_free (new); + continue; + } + root->children = temp; + } + + /* Clean up the old include directive while we still have a + * valid pointer */ + DEBUG ("configfile: Cleaning up `old'"); + /* sfree (old->values[0].value.string); */ + sfree (old->values); + + /* If there are trailing children and the number of children + * changes, we need to move the trailing ones either one to the + * front or (new->num - 1) to the back */ + if (((root->children_num - i) > 1) + && (new->children_num != 1)) + { + DEBUG ("configfile: Moving trailing children."); + memmove (root->children + i + new->children_num, + root->children + i + 1, + sizeof (oconfig_item_t) + * (root->children_num - (i + 1))); + } + + /* Now copy the new children to where the include statement was */ + if (new->children_num > 0) + { + DEBUG ("configfile: Copying new children."); + memcpy (root->children + i, + new->children, + sizeof (oconfig_item_t) + * new->children_num); + } + + /* Adjust the number of children and the position in the list. */ + root->children_num = root->children_num + new->children_num - 1; + i = i + new->children_num - 1; + + /* Clean up the `new' struct. We set `new->children' to NULL so + * the stuff we've just copied pointers to isn't freed by + * `oconfig_free' */ + DEBUG ("configfile: Cleaning up `new'"); + sfree (new->values); /* should be NULL anyway */ + sfree (new); + new = NULL; + } /* for (i = 0; i < root->children_num; i++) */ + + return (0); +} /* int cf_include_all */ + +static oconfig_item_t *cf_read_file (const char *file, int depth) +{ + oconfig_item_t *root; + + if (depth >= CF_MAX_DEPTH) + { + ERROR ("configfile: Not including `%s' because the maximum nesting depth has been reached.", + file); + return (NULL); + } + + root = oconfig_parse_file (file); + if (root == NULL) + { + ERROR ("configfile: Cannot read file `%s'.", file); + return (NULL); + } + + cf_include_all (root, depth); + + return (root); +} /* oconfig_item_t *cf_read_file */ + /* * Public functions */ @@ -287,7 +469,7 @@ int global_option_set (const char *option, const char *value) { int i; - DBG ("option = %s; value = %s;", option, value); + DEBUG ("option = %s; value = %s;", option, value); for (i = 0; i < cf_global_options_num; i++) if (strcasecmp (cf_global_options[i].key, option) == 0) @@ -296,8 +478,7 @@ int global_option_set (const char *option, const char *value) if (i >= cf_global_options_num) return (-1); - if (cf_global_options[i].value != NULL) - free (cf_global_options[i].value); + sfree (cf_global_options[i].value); if (value != NULL) cf_global_options[i].value = strdup (value); @@ -340,7 +521,27 @@ void cf_unregister (const char *type) free (this); break; } -} +} /* void cf_unregister */ + +void cf_unregister_complex (const char *type) +{ + cf_complex_callback_t *this, *prev; + + for (prev = NULL, this = complex_callback_head; + this != NULL; + prev = this, this = this->next) + if (strcasecmp (this->type, type) == 0) + { + if (prev == NULL) + complex_callback_head = this->next; + else + prev->next = this->next; + + sfree (this->type); + sfree (this); + break; + } +} /* void cf_unregister */ void cf_register (const char *type, int (*callback) (const char *, const char *), @@ -364,15 +565,48 @@ void cf_register (const char *type, first_callback = cf_cb; } /* void cf_register */ +int cf_register_complex (const char *type, int (*callback) (oconfig_item_t *)) +{ + cf_complex_callback_t *new; + + new = (cf_complex_callback_t *) malloc (sizeof (cf_complex_callback_t)); + if (new == NULL) + return (-1); + + new->type = strdup (type); + if (new->type == NULL) + { + sfree (new); + return (-1); + } + + new->callback = callback; + new->next = NULL; + + if (complex_callback_head == NULL) + { + complex_callback_head = new; + } + else + { + cf_complex_callback_t *last = complex_callback_head; + while (last->next != NULL) + last = last->next; + last->next = new; + } + + return (0); +} /* int cf_register_complex */ + int cf_read (char *filename) { oconfig_item_t *conf; int i; - conf = oconfig_parse_file (filename); + conf = cf_read_file (filename, 0 /* depth */); if (conf == NULL) { - syslog (LOG_ERR, "Unable to read config file %s.", filename); + ERROR ("Unable to read config file %s.", filename); return (-1); } @@ -384,5 +618,7 @@ int cf_read (char *filename) dispatch_block (conf->children + i); } + if (cf_default_typesdb) + read_types_list (PLUGINDIR"/types.db"); /* FIXME: Configure path */ return (0); } /* int cf_read */