diff --git a/src/configfile.c b/src/configfile.c
index 2eea2362a5a39396eaabacef5a339202a624ad2d..5920c53129628c3691af816843aff70af8f55e5c 100644 (file)
--- a/src/configfile.c
+++ b/src/configfile.c
/**
* collectd - src/configfile.c
- * Copyright (C) 2005-2009 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
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* Authors:
- * Florian octo Forster <octo at verplant.org>
+ * Florian octo Forster <octo at collectd.org>
* Sebastian tokkee Harl <sh at tokkee.org>
**/
#include "plugin.h"
#include "configfile.h"
#include "types_list.h"
-#include "utils_threshold.h"
#include "filter_chain.h"
#if HAVE_WORDEXP_H
int (*callback) (const char *, const char *);
const char **keys;
int keys_num;
+ plugin_ctx_t ctx;
struct cf_callback *next;
} cf_callback_t;
{
char *type;
int (*callback) (oconfig_item_t *);
+ plugin_ctx_t ctx;
struct cf_complex_callback_s *next;
} cf_complex_callback_t;
{"BaseDir", NULL, PKGLOCALSTATEDIR},
{"PIDFile", NULL, PIDFILE},
{"Hostname", NULL, NULL},
- {"FQDNLookup", NULL, "false"},
- {"Interval", NULL, "10"},
+ {"FQDNLookup", NULL, "true"},
+ {"Interval", NULL, NULL},
{"ReadThreads", NULL, "5"},
+ {"Timeout", NULL, "2"},
{"PreCacheChain", NULL, "PreCache"},
{"PostCacheChain", NULL, "PostCache"}
};
const char *orig_value)
{
cf_callback_t *cf_cb;
+ plugin_ctx_t old_ctx;
char *key;
char *value;
int ret;
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)
}
}
+ plugin_set_ctx (old_ctx);
+
if (i >= cf_cb->keys_num)
WARNING ("Plugin `%s' did not register for value `%s'.", type, key);
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)
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)
/* 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++)
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));
if (status != 0)
{
char errbuf[1024];
- ERROR ("configfile: stat (%s) failed: %s",
+ WARNING ("configfile: stat (%s) failed: %s",
path_ptr,
sstrerror (errno, errbuf, sizeof (errbuf)));
- oconfig_free (root);
- return (NULL);
+ continue;
}
if (S_ISREG (statbuf.st_mode))
temp = cf_read_dir (path_ptr, depth);
else
{
- ERROR ("configfile: %s is neither a file nor a "
+ WARNING ("configfile: %s is neither a file nor a "
"directory.", path);
continue;
}
wordfree (&we);
+ if (root->children == NULL)
+ {
+ oconfig_free (root);
+ return (NULL);
+ }
+
return (root);
} /* oconfig_item_t *cf_read_generic */
/* #endif HAVE_WORDEXP_H */
: 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;
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;
new->callback = callback;
new->next = NULL;
+ new->ctx = plugin_get_ctx ();
+
if (complex_callback_head == NULL)
{
complex_callback_head = new;
@@ -957,6 +1042,62 @@ int cf_util_get_string (const oconfig_item_t *ci, char **ret_string) /* {{{ */
return (0);
} /* }}} int cf_util_get_string */
+/* Assures the config option is a string and copies it to the provided buffer.
+ * Assures null-termination. */
+int cf_util_get_string_buffer (const oconfig_item_t *ci, char *buffer, /* {{{ */
+ size_t buffer_size)
+{
+ if ((ci == NULL) || (buffer == NULL) || (buffer_size < 1))
+ return (EINVAL);
+
+ if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
+ {
+ ERROR ("cf_util_get_string_buffer: The %s option requires "
+ "exactly one string argument.", ci->key);
+ return (-1);
+ }
+
+ strncpy (buffer, ci->values[0].value.string, buffer_size);
+ buffer[buffer_size - 1] = 0;
+
+ return (0);
+} /* }}} int cf_util_get_string_buffer */
+
+/* Assures the config option is a number and returns it as an int. */
+int cf_util_get_int (const oconfig_item_t *ci, int *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_int: The %s option requires "
+ "exactly one numeric argument.", ci->key);
+ return (-1);
+ }
+
+ *ret_value = (int) ci->values[0].value.number;
+
+ 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))
@@ -965,26 +1106,146 @@ int cf_util_get_boolean (const oconfig_item_t *ci, _Bool *ret_bool) /* {{{ */
if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_BOOLEAN))
{
ERROR ("cf_util_get_boolean: The %s option requires "
- "exactly one string argument.", ci->key);
+ "exactly one boolean argument.", ci->key);
return (-1);
}
- *ret_bool = ci->values[0].value.boolean ? true : false;
+ *ret_bool = ci->values[0].value.boolean ? 1 : 0;
return (0);
} /* }}} int cf_util_get_boolean */
-/* 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. */
+int cf_util_get_flag (const oconfig_item_t *ci, /* {{{ */
+ unsigned int *ret_value, unsigned int flag)
+{
+ int status;
+ _Bool b;
+
+ if (ret_value == NULL)
+ return (EINVAL);
+
+ b = 0;
+ status = cf_util_get_boolean (ci, &b);
+ if (status != 0)
+ return (status);
+
+ if (b)
+ {
+ *ret_value |= flag;
+ }
+ else
+ {
+ *ret_value &= ~flag;
+ }
+
+ return (0);
+} /* }}} int cf_util_get_flag */
+
+/* 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))
+ return (EINVAL);
+
+ if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
+ {
+ ERROR ("cf_util_get_cdtime: The %s option requires "
+ "exactly one numeric argument.", ci->key);
+ return (-1);
+ }
+
+ if (ci->values[0].value.number < 0.0)
+ {
+ ERROR ("cf_util_get_cdtime: The numeric argument of the %s "
+ "option must not be negative.", ci->key);
+ return (-1);
+ }
+
+ *ret_value = DOUBLE_TO_CDTIME_T (ci->values[0].value.number);
+
+ return (0);
+} /* }}} int cf_util_get_cdtime */
+