configfile.c: Include more than one files in lexicographical order.
authorSebastian Harl <sh@tokkee.org>
Thu, 20 Mar 2008 12:22:15 +0000 (13:22 +0100)
committerFlorian Forster <octo@huhu.verplant.org>
Sat, 22 Mar 2008 08:34:26 +0000 (09:34 +0100)
Using qsort() and strcmp() the list of files (after reading the contents
of a directory or expanding globs) is sorted before inclusion. As the
order of options in the config file matters this is more convenient.

Signed-off-by: Sebastian Harl <sh@tokkee.org>
Signed-off-by: Florian Forster <octo@huhu.verplant.org>
src/collectd.conf.pod
src/configfile.c

index 383dda6..aa4421d 100644 (file)
@@ -63,6 +63,11 @@ use statements like the following:
 
   Include "/etc/collectd.d/*.conf"
 
+If more than one files are included by a single B<Include> option, the files
+will be included in lexicographical order (as defined by the C<strcmp>
+function). Thus, you can e.E<nbsp>g. use numbered prefixes to specify the
+order in which the files are loaded.
+
 To prevent loops and shooting yourself in the foot in interesting ways the
 nesting is limited to a depth of 8E<nbsp>levels, which should be sufficient for
 most uses. Since symlinks are followed it is still possible to crash the daemon
index 63b926a..4a9789a 100644 (file)
@@ -18,6 +18,7 @@
  *
  * Authors:
  *   Florian octo Forster <octo at verplant.org>
+ *   Sebastian tokkee Harl <sh at tokkee.org>
  **/
 
 #include "collectd.h"
@@ -505,13 +506,20 @@ static oconfig_item_t *cf_read_file (const char *file, int depth)
        return (root);
 } /* oconfig_item_t *cf_read_file */
 
+static int cf_compare_string (const void *p1, const void *p2)
+{
+       return strcmp (*(const char **) p1, *(const char **) p2);
+}
+
 static oconfig_item_t *cf_read_dir (const char *dir, int depth)
 {
        oconfig_item_t *root = NULL;
        DIR *dh;
        struct dirent *de;
-       char name[1024];
+       char **filenames = NULL;
+       int filenames_num = 0;
        int status;
+       int i;
 
        assert (depth < CF_MAX_DEPTH);
 
@@ -534,7 +542,8 @@ static oconfig_item_t *cf_read_dir (const char *dir, int depth)
 
        while ((de = readdir (dh)) != NULL)
        {
-               oconfig_item_t *temp;
+               char   name[1024];
+               char **tmp;
 
                if ((de->d_name[0] == '.') || (de->d_name[0] == '\0'))
                        continue;
@@ -546,12 +555,43 @@ static oconfig_item_t *cf_read_dir (const char *dir, int depth)
                        ERROR ("configfile: Not including `%s/%s' because its"
                                        " name is too long.",
                                        dir, de->d_name);
-                       oconfig_free (root);
+                       for (i = 0; i < filenames_num; ++i)
+                               free (filenames[i]);
+                       free (filenames);
+                       free (root);
+                       return (NULL);
+               }
+
+               ++filenames_num;
+               tmp = (char **) realloc (filenames,
+                               filenames_num * sizeof (*filenames));
+               if (tmp == NULL) {
+                       ERROR ("configfile: realloc failed.");
+                       for (i = 0; i < filenames_num - 1; ++i)
+                               free (filenames[i]);
+                       free (filenames);
+                       free (root);
                        return (NULL);
                }
+               filenames = tmp;
+
+               filenames[filenames_num - 1] = sstrdup (name);
+       }
+
+       qsort ((void *) filenames, filenames_num, sizeof (*filenames),
+                       cf_compare_string);
+
+       for (i = 0; i < filenames_num; ++i)
+       {
+               oconfig_item_t *temp;
+               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);
                }
@@ -559,8 +599,11 @@ static oconfig_item_t *cf_read_dir (const char *dir, int depth)
                cf_ci_append_children (root, temp);
                sfree (temp->children);
                sfree (temp);
+
+               free (name);
        }
 
+       free(filenames);
        return (root);
 } /* oconfig_item_t *cf_read_dir */
 
@@ -606,6 +649,11 @@ static oconfig_item_t *cf_read_generic (const char *path, int depth)
        }
        memset (root, '\0', sizeof (oconfig_item_t));
 
+       /* wordexp() might return a sorted list already. That's not
+        * documented though, so let's make sure we get what we want. */
+       qsort ((void *) we.we_wordv, we.we_wordc, sizeof (*we.we_wordv),
+                       cf_compare_string);
+
        for (i = 0; i < we.we_wordc; i++)
        {
                oconfig_item_t *temp;