src/configfile.c: Continue parsing config files if stat'ing one file fails.
[collectd.git] / src / configfile.c
index 2ef5f04..b1cd7b8 100644 (file)
@@ -75,7 +75,7 @@ typedef struct cf_global_option_s
  */
 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);
+static int dispatch_loadplugin (const oconfig_item_t *ci);
 
 /*
  * Private variables
@@ -87,7 +87,7 @@ static cf_value_map_t cf_value_map[] =
 {
        {"TypesDB",    dispatch_value_typesdb},
        {"PluginDir",  dispatch_value_plugindir},
-       {"LoadPlugin", dispatch_value_loadplugin}
+       {"LoadPlugin", dispatch_loadplugin}
 };
 static int cf_value_map_num = STATIC_ARRAY_LEN (cf_value_map);
 
@@ -239,8 +239,10 @@ static int dispatch_value_plugindir (const oconfig_item_t *ci)
        return (0);
 }
 
-static int dispatch_value_loadplugin (const oconfig_item_t *ci)
+static int dispatch_loadplugin (const oconfig_item_t *ci)
 {
+       int i;
+       uint32_t flags = 0;
        assert (strcasecmp (ci->key, "LoadPlugin") == 0);
 
        if (ci->values_num != 1)
@@ -248,7 +250,19 @@ static int dispatch_value_loadplugin (const oconfig_item_t *ci)
        if (ci->values[0].type != OCONFIG_TYPE_STRING)
                return (-1);
 
-       return (plugin_load (ci->values[0].value.string));
+       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(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);
+               }
+       }
+       return (plugin_load (ci->values[0].value.string, flags));
 } /* int dispatch_value_loadplugin */
 
 static int dispatch_value_plugin (const char *plugin, oconfig_item_t *ci)
@@ -353,7 +367,9 @@ static int dispatch_block_plugin (oconfig_item_t *ci)
 
 static int dispatch_block (oconfig_item_t *ci)
 {
-       if (strcasecmp (ci->key, "Plugin") == 0)
+       if (strcasecmp (ci->key, "LoadPlugin") == 0)
+               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));
@@ -559,14 +575,14 @@ static oconfig_item_t *cf_read_dir (const char *dir, int depth)
                ERROR ("configfile: malloc failed.");
                return (NULL);
        }
-       memset (root, '\0', sizeof (oconfig_item_t));
+       memset (root, 0, sizeof (oconfig_item_t));
 
        while ((de = readdir (dh)) != NULL)
        {
                char   name[1024];
                char **tmp;
 
-               if ((de->d_name[0] == '.') || (de->d_name[0] == '\0'))
+               if ((de->d_name[0] == '.') || (de->d_name[0] == 0))
                        continue;
 
                status = ssnprintf (name, sizeof (name), "%s/%s",
@@ -608,13 +624,11 @@ static oconfig_item_t *cf_read_dir (const char *dir, int depth)
                char *name = filenames[i];
 
                temp = cf_read_generic (name, depth);
-               if (temp == NULL) {
-                       int j;
-                       for (j = i; j < filenames_num; ++j)
-                               free (filenames[j]);
-                       free (filenames);
-                       oconfig_free (root);
-                       return (NULL);
+               if (temp == NULL)
+               {
+                       /* An error should already have been reported. */
+                       sfree (name);
+                       continue;
                }
 
                cf_ci_append_children (root, temp);
@@ -686,11 +700,10 @@ static oconfig_item_t *cf_read_generic (const char *path, int depth)
                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))
@@ -699,7 +712,7 @@ static oconfig_item_t *cf_read_generic (const char *path, int depth)
                        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;
                }
@@ -716,6 +729,12 @@ static oconfig_item_t *cf_read_generic (const char *path, int depth)
 
        wordfree (&we);
 
+       if (root->children == NULL)
+       {
+               oconfig_free (root);
+               return (NULL);
+       }
+
        return (root);
 } /* oconfig_item_t *cf_read_generic */
 /* #endif HAVE_WORDEXP_H */
@@ -943,6 +962,23 @@ int cf_util_get_string (const oconfig_item_t *ci, char **ret_string) /* {{{ */
        return (0);
 } /* }}} int cf_util_get_string */
 
+int cf_util_get_boolean (const oconfig_item_t *ci, _Bool *ret_bool) /* {{{ */
+{
+       if ((ci == NULL) || (ret_bool == NULL))
+               return (EINVAL);
+
+       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);
+               return (-1);
+       }
+
+       *ret_bool = ci->values[0].value.boolean ? true : false;
+
+       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. */