Code

Merge remote-tracking branch 'github/pr/387'
[collectd.git] / src / configfile.c
index 1a9e28a624fed56c302cdec73c30bc563ef89597..0e54f267f9fdd08c15d4d4d11a427f409d708723 100644 (file)
@@ -98,7 +98,7 @@ static cf_value_map_t cf_value_map[] =
        {"PluginDir",  dispatch_value_plugindir},
        {"LoadPlugin", dispatch_loadplugin}
 };
-static int cf_value_map_num = STATIC_ARRAY_LEN (cf_value_map);
+static int cf_value_map_num = STATIC_ARRAY_SIZE (cf_value_map);
 
 static cf_global_option_t cf_global_options[] =
 {
@@ -108,11 +108,15 @@ static cf_global_option_t cf_global_options[] =
        {"FQDNLookup",  NULL, "true"},
        {"Interval",    NULL, NULL},
        {"ReadThreads", NULL, "5"},
+       {"WriteThreads", NULL, "5"},
+       {"WriteQueueLimitHigh", NULL, NULL},
+       {"WriteQueueLimitLow", NULL, NULL},
        {"Timeout",     NULL, "2"},
+       {"AutoLoadPlugin", NULL, "false"},
        {"PreCacheChain",  NULL, "PreCache"},
        {"PostCacheChain", NULL, "PostCache"}
 };
-static int cf_global_options_num = STATIC_ARRAY_LEN (cf_global_options);
+static int cf_global_options_num = STATIC_ARRAY_SIZE (cf_global_options);
 
 static int cf_default_typesdb = 1;
 
@@ -276,21 +280,6 @@ static int dispatch_loadplugin (const oconfig_item_t *ci)
        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 (strcasecmp("Globals", ci->children[i].key) == 0)
                        cf_util_get_flag (ci->children + i, &flags, PLUGIN_FLAGS_GLOBAL);
@@ -393,6 +382,19 @@ static int dispatch_block_plugin (oconfig_item_t *ci)
 
        name = ci->values[0].value.string;
 
+       if (IS_TRUE (global_option_get ("AutoLoadPlugin")))
+       {
+               int status;
+
+               status = plugin_load (name, /* flags = */ 0);
+               if (status != 0)
+               {
+                       ERROR ("Automatically loading plugin \"%s\" failed "
+                                       "with status %i.", name, status);
+                       return (status);
+               }
+       }
+
        /* Check for a complex callback first */
        for (cb = complex_callback_head; cb != NULL; cb = cb->next)
        {
@@ -555,29 +557,38 @@ static int cf_include_all (oconfig_item_t *root, int depth)
                oconfig_item_t *new;
                oconfig_item_t *old;
 
-               /* Ignore all blocks, including `Include' blocks. */
-               if (root->children[i].children_num != 0)
-                       continue;
+               char *pattern = NULL;
+
+               int j;
 
                if (strcasecmp (root->children[i].key, "Include") != 0)
                        continue;
 
                old = root->children + i;
 
-               if ((old->values_num < 1) || (old->values_num > 2)
-                               || (old->values[0].type != OCONFIG_TYPE_STRING)
-                               || ((old->values_num == 2)
-                                       && (old->values[1].type != OCONFIG_TYPE_STRING)))
+               if ((old->values_num != 1)
+                               || (old->values[0].type != OCONFIG_TYPE_STRING))
                {
-                       ERROR ("configfile: `Include' needs exactly one or two string argument.");
+                       ERROR ("configfile: `Include' needs exactly one string argument.");
                        continue;
                }
 
-               new = cf_read_generic (old->values[0].value.string,
-                               (old->values_num == 2) ? old->values[1].value.string : NULL,
-                               depth + 1);
+               for (j = 0; j < old->children_num; ++j)
+               {
+                       oconfig_item_t *child = old->children + j;
+
+                       if (strcasecmp (child->key, "Filter") == 0)
+                               cf_util_get_string (child, &pattern);
+                       else
+                               ERROR ("configfile: Option `%s' not allowed in <Include> block.",
+                                               child->key);
+               }
+
+               new = cf_read_generic (old->values[0].value.string, pattern, depth + 1);
+               sfree (pattern);
+
                if (new == NULL)
-                       continue;
+                       return (-1);
 
                /* Now replace the i'th child in `root' with `new'. */
                cf_ci_replace_child (root, new, i);
@@ -596,6 +607,7 @@ static oconfig_item_t *cf_read_file (const char *file,
                const char *pattern, int depth)
 {
        oconfig_item_t *root;
+       int status;
 
        assert (depth < CF_MAX_DEPTH);
 
@@ -605,6 +617,9 @@ static oconfig_item_t *cf_read_file (const char *file,
                char *filename = basename (tmp);
 
                if ((filename != NULL) && (fnmatch (pattern, filename, 0) != 0)) {
+                       DEBUG ("configfile: Not including `%s' because it "
+                                       "does not match pattern `%s'.",
+                                       filename, pattern);
                        free (tmp);
                        return (NULL);
                }
@@ -624,7 +639,12 @@ static oconfig_item_t *cf_read_file (const char *file,
                return (NULL);
        }
 
-       cf_include_all (root, depth);
+       status = cf_include_all (root, depth);
+       if (status != 0)
+       {
+               oconfig_free (root);
+               return (NULL);
+       }
 
        return (root);
 } /* oconfig_item_t *cf_read_file */
@@ -817,12 +837,6 @@ static oconfig_item_t *cf_read_generic (const char *path,
 
        wordfree (&we);
 
-       if (root->children == NULL)
-       {
-               oconfig_free (root);
-               return (NULL);
-       }
-
        return (root);
 } /* oconfig_item_t *cf_read_generic */
 /* #endif HAVE_WORDEXP_H */
@@ -903,6 +917,23 @@ const char *global_option_get (const char *option)
                        : cf_global_options[i].def);
 } /* char *global_option_get */
 
+long global_option_get_long (const char *option, long default_value)
+{
+               const char *str;
+               long value;
+
+               str = global_option_get (option);
+               if (NULL == str)
+                       return (default_value);
+
+               errno = 0;
+               value = strtol (str, /* endptr = */ NULL, /* base = */ 0);
+               if (errno != 0)
+                       return (default_value);
+
+               return (value);
+} /* char *global_option_get_long */
+
 cdtime_t cf_get_default_interval (void)
 {
   char const *str = global_option_get ("Interval");
@@ -1034,6 +1065,12 @@ int cf_read (char *filename)
                ERROR ("Unable to read config file %s.", filename);
                return (-1);
        }
+       else if (conf->children_num == 0)
+       {
+               ERROR ("Configuration file %s is empty.", filename);
+               oconfig_free (conf);
+               return (-1);
+       }
 
        for (i = 0; i < conf->children_num; i++)
        {