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>
Include "/etc/collectd.d/*.conf"
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
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
*
* Authors:
* Florian octo Forster <octo at verplant.org>
*
* Authors:
* Florian octo Forster <octo at verplant.org>
+ * Sebastian tokkee Harl <sh at tokkee.org>
**/
#include "collectd.h"
**/
#include "collectd.h"
return (root);
} /* oconfig_item_t *cf_read_file */
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;
static oconfig_item_t *cf_read_dir (const char *dir, int depth)
{
oconfig_item_t *root = NULL;
DIR *dh;
struct dirent *de;
+ char **filenames = NULL;
+ int filenames_num = 0;
assert (depth < CF_MAX_DEPTH);
assert (depth < CF_MAX_DEPTH);
while ((de = readdir (dh)) != NULL)
{
while ((de = readdir (dh)) != NULL)
{
+ char name[1024];
+ char **tmp;
if ((de->d_name[0] == '.') || (de->d_name[0] == '\0'))
continue;
if ((de->d_name[0] == '.') || (de->d_name[0] == '\0'))
continue;
ERROR ("configfile: Not including `%s/%s' because its"
" name is too long.",
dir, de->d_name);
ERROR ("configfile: Not including `%s/%s' because its"
" name is too long.",
dir, de->d_name);
+ 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);
+ 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) {
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);
}
oconfig_free (root);
return (NULL);
}
cf_ci_append_children (root, temp);
sfree (temp->children);
sfree (temp);
cf_ci_append_children (root, temp);
sfree (temp->children);
sfree (temp);
return (root);
} /* oconfig_item_t *cf_read_dir */
return (root);
} /* oconfig_item_t *cf_read_dir */
}
memset (root, '\0', sizeof (oconfig_item_t));
}
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;
for (i = 0; i < we.we_wordc; i++)
{
oconfig_item_t *temp;