X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Fconfigfile.c;h=5920c53129628c3691af816843aff70af8f55e5c;hb=3faf514fd9b869cadda0f895e14e5036313c7781;hp=e162dd995edf2efe69d37cf80616c1489f9d9717;hpb=83077c18c3e78739c2d2d18debf99875944eaa72;p=collectd.git diff --git a/src/configfile.c b/src/configfile.c index e162dd99..5920c531 100644 --- a/src/configfile.c +++ b/src/configfile.c @@ -1,6 +1,6 @@ /** * collectd - src/configfile.c - * Copyright (C) 2005-2010 Florian octo Forster + * Copyright (C) 2005-2011 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 @@ -17,7 +17,7 @@ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * Authors: - * Florian octo Forster + * Florian octo Forster * Sebastian tokkee Harl **/ @@ -29,7 +29,6 @@ #include "plugin.h" #include "configfile.h" #include "types_list.h" -#include "utils_threshold.h" #include "filter_chain.h" #if HAVE_WORDEXP_H @@ -47,6 +46,7 @@ typedef struct cf_callback int (*callback) (const char *, const char *); const char **keys; int keys_num; + plugin_ctx_t ctx; struct cf_callback *next; } cf_callback_t; @@ -54,6 +54,7 @@ typedef struct cf_complex_callback_s { char *type; int (*callback) (oconfig_item_t *); + plugin_ctx_t ctx; struct cf_complex_callback_s *next; } cf_complex_callback_t; @@ -97,7 +98,7 @@ static cf_global_option_t cf_global_options[] = {"PIDFile", NULL, PIDFILE}, {"Hostname", NULL, NULL}, {"FQDNLookup", NULL, "true"}, - {"Interval", NULL, "10"}, + {"Interval", NULL, NULL}, {"ReadThreads", NULL, "5"}, {"Timeout", NULL, "2"}, {"PreCacheChain", NULL, "PreCache"}, @@ -129,6 +130,7 @@ static int cf_dispatch (const char *type, const char *orig_key, const char *orig_value) { cf_callback_t *cf_cb; + plugin_ctx_t old_ctx; char *key; char *value; int ret; @@ -157,6 +159,8 @@ static int cf_dispatch (const char *type, const char *orig_key, ret = -1; + old_ctx = plugin_set_ctx (cf_cb->ctx); + for (i = 0; i < cf_cb->keys_num; i++) { if ((cf_cb->keys[i] != NULL) @@ -167,6 +171,8 @@ static int cf_dispatch (const char *type, const char *orig_key, } } + plugin_set_ctx (old_ctx); + if (i >= cf_cb->keys_num) WARNING ("Plugin `%s' did not register for value `%s'.", type, key); @@ -243,7 +249,12 @@ static int dispatch_value_plugindir (const oconfig_item_t *ci) static int dispatch_loadplugin (const oconfig_item_t *ci) { int i; - uint32_t flags = 0; + const char *name; + unsigned int flags = 0; + plugin_ctx_t ctx; + plugin_ctx_t old_ctx; + int ret_val; + assert (strcasecmp (ci->key, "LoadPlugin") == 0); if (ci->values_num != 1) @@ -251,19 +262,53 @@ static int dispatch_loadplugin (const oconfig_item_t *ci) if (ci->values[0].type != OCONFIG_TYPE_STRING) return (-1); + name = ci->values[0].value.string; + + /* default to the global interval set before loading this plugin */ + memset (&ctx, 0, sizeof (ctx)); + ctx.interval = cf_get_default_interval (); + + /* + * XXX: Magic at work: + * + * Some of the language bindings, for example the Python and Perl + * plugins, need to be able to export symbols to the scripts they run. + * For this to happen, the "Globals" flag needs to be set. + * Unfortunately, this technical detail is hard to explain to the + * average user and she shouldn't have to worry about this, ideally. + * So in order to save everyone's sanity use a different default for a + * handful of special plugins. --octo + */ + if ((strcasecmp ("Perl", name) == 0) + || (strcasecmp ("Python", name) == 0)) + flags |= PLUGIN_FLAGS_GLOBAL; + for (i = 0; i < ci->children_num; ++i) { - if (ci->children[i].values_num != 1 || - ci->children[i].values[0].type != OCONFIG_TYPE_BOOLEAN) { - WARNING("Ignoring unknown LoadPlugin option %s for plugin %s", ci->children[i].key, ci->values[0].value.string); - continue; + if (strcasecmp("Globals", ci->children[i].key) == 0) + cf_util_get_flag (ci->children + i, &flags, PLUGIN_FLAGS_GLOBAL); + else if (strcasecmp ("Interval", ci->children[i].key) == 0) { + double interval = 0.0; + + if (cf_util_get_double (ci->children + i, &interval) != 0) { + /* cf_util_get_double will log an error */ + continue; + } + + ctx.interval = DOUBLE_TO_CDTIME_T (interval); } - if (strcasecmp(ci->children[i].key, "globals") == 0) { - flags |= PLUGIN_FLAGS_GLOBAL; - } else { - WARNING("Ignoring unknown LoadPlugin option %s for plugin %s", ci->children[i].key, ci->values[0].value.string); + else { + WARNING("Ignoring unknown LoadPlugin option \"%s\" " + "for plugin \"%s\"", + ci->children[i].key, ci->values[0].value.string); } } - return (plugin_load (ci->values[0].value.string, flags)); + + old_ctx = plugin_set_ctx (ctx); + ret_val = plugin_load (name, (uint32_t) flags); + /* reset to the "global" context */ + plugin_set_ctx (old_ctx); + + return (ret_val); } /* int dispatch_value_loadplugin */ static int dispatch_value_plugin (const char *plugin, oconfig_item_t *ci) @@ -342,8 +387,18 @@ static int dispatch_block_plugin (oconfig_item_t *ci) /* 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)); + { + plugin_ctx_t old_ctx; + int ret_val; + + old_ctx = plugin_set_ctx (cb->ctx); + ret_val = (cb->callback (ci)); + plugin_set_ctx (old_ctx); + return (ret_val); + } + } /* Hm, no complex plugin found. Dispatch the values one by one */ for (i = 0; i < ci->children_num; i++) @@ -372,8 +427,6 @@ static int dispatch_block (oconfig_item_t *ci) return (dispatch_loadplugin (ci)); else if (strcasecmp (ci->key, "Plugin") == 0) return (dispatch_block_plugin (ci)); - else if (strcasecmp (ci->key, "Threshold") == 0) - return (ut_config (ci)); else if (strcasecmp (ci->key, "Chain") == 0) return (fc_configure (ci)); @@ -815,6 +868,29 @@ const char *global_option_get (const char *option) : cf_global_options[i].def); } /* char *global_option_get */ +cdtime_t cf_get_default_interval (void) +{ + char const *str = global_option_get ("Interval"); + double interval_double = COLLECTD_DEFAULT_INTERVAL; + + if (str != NULL) + { + char *endptr = NULL; + double tmp = strtod (str, &endptr); + + if ((endptr == NULL) || (endptr == str) || (*endptr != 0)) + ERROR ("cf_get_default_interval: Unable to parse string \"%s\" " + "as number.", str); + else if (tmp <= 0.0) + ERROR ("cf_get_default_interval: Interval must be a positive number. " + "The current number is %g.", tmp); + else + interval_double = tmp; + } + + return (DOUBLE_TO_CDTIME_T (interval_double)); +} /* }}} cdtime_t cf_get_default_interval */ + void cf_unregister (const char *type) { cf_callback_t *this, *prev; @@ -871,6 +947,7 @@ void cf_register (const char *type, cf_cb->callback = callback; cf_cb->keys = keys; cf_cb->keys_num = keys_num; + cf_cb->ctx = plugin_get_ctx (); cf_cb->next = first_callback; first_callback = cf_cb; @@ -894,6 +971,8 @@ int cf_register_complex (const char *type, int (*callback) (oconfig_item_t *)) new->callback = callback; new->next = NULL; + new->ctx = plugin_get_ctx (); + if (complex_callback_head == NULL) { complex_callback_head = new; @@ -1002,6 +1081,23 @@ int cf_util_get_int (const oconfig_item_t *ci, int *ret_value) /* {{{ */ return (0); } /* }}} int cf_util_get_int */ +int cf_util_get_double (const oconfig_item_t *ci, double *ret_value) /* {{{ */ +{ + if ((ci == NULL) || (ret_value == NULL)) + return (EINVAL); + + if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_NUMBER)) + { + ERROR ("cf_util_get_double: The %s option requires " + "exactly one numeric argument.", ci->key); + return (-1); + } + + *ret_value = ci->values[0].value.number; + + return (0); +} /* }}} int cf_util_get_double */ + int cf_util_get_boolean (const oconfig_item_t *ci, _Bool *ret_bool) /* {{{ */ { if ((ci == NULL) || (ret_bool == NULL)) @@ -1045,21 +1141,90 @@ int cf_util_get_flag (const oconfig_item_t *ci, /* {{{ */ return (0); } /* }}} int cf_util_get_flag */ -/* Assures that the config option is a string. The string is then converted to - * a port number using `service_name_to_port_number' and returned. Returns the - * port number in the range [1-65535] or less than zero upon failure. */ +/* Assures that the config option is a string or a number if the correct range + * of 1-65535. The string is then converted to a port number using + * `service_name_to_port_number' and returned. + * Returns the port number in the range [1-65535] or less than zero upon + * failure. */ int cf_util_get_port_number (const oconfig_item_t *ci) /* {{{ */ { - if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING)) + int tmp; + + if ((ci->values_num != 1) + || ((ci->values[0].type != OCONFIG_TYPE_STRING) + && (ci->values[0].type != OCONFIG_TYPE_NUMBER))) { - ERROR ("cf_util_get_port_number: The %s option requires " + ERROR ("cf_util_get_port_number: The \"%s\" option requires " "exactly one string argument.", ci->key); return (-1); } - return (service_name_to_port_number (ci->values[0].value.string)); + if (ci->values[0].type == OCONFIG_TYPE_STRING) + return (service_name_to_port_number (ci->values[0].value.string)); + + assert (ci->values[0].type == OCONFIG_TYPE_NUMBER); + tmp = (int) (ci->values[0].value.number + 0.5); + if ((tmp < 1) || (tmp > 65535)) + { + ERROR ("cf_util_get_port_number: The \"%s\" option requires " + "a service name or a port number. The number " + "you specified, %i, is not in the valid " + "range of 1-65535.", + ci->key, tmp); + return (-1); + } + + return (tmp); } /* }}} int cf_util_get_port_number */ +int cf_util_get_service (const oconfig_item_t *ci, char **ret_string) /* {{{ */ +{ + int port; + char *service; + int status; + + if (ci->values_num != 1) + { + ERROR ("cf_util_get_service: The %s option requires exactly " + "one argument.", ci->key); + return (-1); + } + + if (ci->values[0].type == OCONFIG_TYPE_STRING) + return (cf_util_get_string (ci, ret_string)); + if (ci->values[0].type != OCONFIG_TYPE_NUMBER) + { + ERROR ("cf_util_get_service: The %s option requires " + "exactly one string or numeric argument.", + ci->key); + } + + port = 0; + status = cf_util_get_int (ci, &port); + if (status != 0) + return (status); + else if ((port < 1) || (port > 65535)) + { + ERROR ("cf_util_get_service: The port number given " + "for the %s option is out of " + "range (%i).", ci->key, port); + return (-1); + } + + service = malloc (6); + if (service == NULL) + { + ERROR ("cf_util_get_service: Out of memory."); + return (-1); + } + ssnprintf (service, 6, "%i", port); + + sfree (*ret_string); + *ret_string = service; + + return (0); +} /* }}} int cf_util_get_service */ + int cf_util_get_cdtime (const oconfig_item_t *ci, cdtime_t *ret_value) /* {{{ */ { if ((ci == NULL) || (ret_value == NULL))