Code

src/configfile.c: Let errors in included files propagate up to cf_read().
[collectd.git] / src / configfile.c
index b09bee8dbf66997ab96bea8ef33740d6d4ae362c..be777c52a02cbb0074c405fa7909ab0a3968c3b9 100644 (file)
@@ -98,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"},
@@ -265,7 +265,8 @@ static int dispatch_loadplugin (const oconfig_item_t *ci)
        name = ci->values[0].value.string;
 
        /* default to the global interval set before loading this plugin */
-       ctx.interval = plugin_get_interval ();
+       memset (&ctx, 0, sizeof (ctx));
+       ctx.interval = cf_get_default_interval ();
 
        /*
         * XXX: Magic at work:
@@ -563,7 +564,7 @@ static int cf_include_all (oconfig_item_t *root, int depth)
 
                new = cf_read_generic (old->values[0].value.string, depth + 1);
                if (new == NULL)
-                       continue;
+                       return (-1);
 
                /* Now replace the i'th child in `root' with `new'. */
                cf_ci_replace_child (root, new, i);
@@ -581,6 +582,7 @@ static int cf_include_all (oconfig_item_t *root, int depth)
 static oconfig_item_t *cf_read_file (const char *file, int depth)
 {
        oconfig_item_t *root;
+       int status;
 
        assert (depth < CF_MAX_DEPTH);
 
@@ -591,7 +593,12 @@ static oconfig_item_t *cf_read_file (const char *file, int depth)
                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 */
@@ -782,12 +789,6 @@ 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 */
@@ -867,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;
@@ -975,6 +999,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++)
        {
@@ -1153,6 +1183,54 @@ int cf_util_get_port_number (const oconfig_item_t *ci) /* {{{ */
        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))