From 4fe00def1a70d2bd73dbcd912da2becef459d00e Mon Sep 17 00:00:00 2001 From: Sebastian Harl Date: Thu, 20 Mar 2008 13:22:15 +0100 Subject: [PATCH] configfile.c: Include more than one files in lexicographical order. 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 Signed-off-by: Florian Forster --- src/collectd.conf.pod | 5 ++++ src/configfile.c | 54 ++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 56 insertions(+), 3 deletions(-) diff --git a/src/collectd.conf.pod b/src/collectd.conf.pod index 383dda63..aa4421dc 100644 --- a/src/collectd.conf.pod +++ b/src/collectd.conf.pod @@ -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 option, the files +will be included in lexicographical order (as defined by the C +function). Thus, you can e.Eg. 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 8Elevels, which should be sufficient for most uses. Since symlinks are followed it is still possible to crash the daemon diff --git a/src/configfile.c b/src/configfile.c index 63b926af..4a9789ae 100644 --- a/src/configfile.c +++ b/src/configfile.c @@ -18,6 +18,7 @@ * * Authors: * Florian octo Forster + * Sebastian tokkee Harl **/ #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; -- 2.30.2