Renamed: src/utils_logtail.[ch] -> src/utils_tail_match.[ch]
[collectd.git] / src / configfile.c
index 3b6cb6b..ce4e774 100644 (file)
 #include "types_list.h"
 #include "utils_threshold.h"
 
+#if HAVE_WORDEXP_H
+# include <wordexp.h>
+#endif /* HAVE_WORDEXP_H */
+
 #define ESCAPE_NULL(str) ((str) == NULL ? "(null)" : (str))
 
 /*
@@ -349,18 +353,6 @@ static int cf_ci_replace_child (oconfig_item_t *dst, oconfig_item_t *src,
        assert (offset >= 0);
        assert (dst->children_num > offset);
 
-       /* Resize the memory containing the children to be big enough to hold
-        * all children. */
-       temp = (oconfig_item_t *) realloc (dst->children,
-                       sizeof (oconfig_item_t)
-                       * (dst->children_num + src->children_num - 1));
-       if (temp == NULL)
-       {
-               ERROR ("configfile: realloc failed.");
-               return (-1);
-       }
-       dst->children = temp;
-
        /* Free the memory used by the replaced child. Usually that's the
         * `Include "blah"' statement. */
        temp = dst->children + offset;
@@ -374,9 +366,34 @@ static int cf_ci_replace_child (oconfig_item_t *dst, oconfig_item_t *src,
        sfree (temp->values);
        temp = NULL;
 
-       /* If there are children behind the include statement, move them to the
-        * end of the list, so that the new children have room before them. */
-       if ((dst->children_num - (offset + 1)) > 0)
+       /* If (src->children_num == 0) the array size is decreased. If offset
+        * is _not_ the last element, (offset < (src->children_num - 1)), then
+        * we need to move the trailing elements before resizing the array. */
+       if ((src->children_num == 0) && (offset < (src->children_num - 1)))
+       {
+               int nmemb = src->children_num - (offset + 1);
+               memmove (src->children + offset, src->children + offset + 1,
+                               sizeof (oconfig_item_t) * nmemb);
+       }
+
+       /* Resize the memory containing the children to be big enough to hold
+        * all children. */
+       temp = (oconfig_item_t *) realloc (dst->children,
+                       sizeof (oconfig_item_t)
+                       * (dst->children_num + src->children_num - 1));
+       if (temp == NULL)
+       {
+               ERROR ("configfile: realloc failed.");
+               return (-1);
+       }
+       dst->children = temp;
+
+       /* If there are children behind the include statement, and they have
+        * not yet been moved because (src->children_num == 0), then move them
+        * to the end of the list, so that the new children have room before
+        * them. */
+       if ((src->children_num > 0)
+                       && ((dst->children_num - (offset + 1)) > 0))
        {
                int nmemb = dst->children_num - (offset + 1);
                int old_offset = offset + 1;
@@ -546,11 +563,20 @@ static oconfig_item_t *cf_read_dir (const char *dir, int depth)
  *
  * Path is stat'ed and either cf_read_file or cf_read_dir is called
  * accordingly.
+ *
+ * There are two versions of this function: If `wordexp' exists shell wildcards
+ * will be expanded and the function will include all matches found. If
+ * `wordexp' (or, more precisely, it's header file) is not available the
+ * simpler function is used which does not do any such expansion.
  */
+#if HAVE_WORDEXP_H
 static oconfig_item_t *cf_read_generic (const char *path, int depth)
 {
-       struct stat statbuf;
+       oconfig_item_t *root = NULL;
        int status;
+       const char *path_ptr;
+       wordexp_t we;
+       int i;
 
        if (depth >= CF_MAX_DEPTH)
        {
@@ -559,7 +585,72 @@ static oconfig_item_t *cf_read_generic (const char *path, int depth)
                return (NULL);
        }
 
-       fprintf (stderr, "cf_read_generic (path = %s, depth = %i);", path, depth);
+       status = wordexp (path, &we, WRDE_NOCMD);
+       if (status != 0)
+       {
+               ERROR ("configfile: wordexp (%s) failed.", path);
+               return (NULL);
+       }
+
+       root = (oconfig_item_t *) malloc (sizeof (oconfig_item_t));
+       if (root == NULL)
+       {
+               ERROR ("configfile: malloc failed.");
+               return (NULL);
+       }
+       memset (root, '\0', sizeof (oconfig_item_t));
+
+       for (i = 0; i < we.we_wordc; i++)
+       {
+               oconfig_item_t *temp;
+               struct stat statbuf;
+
+               path_ptr = we.we_wordv[i];
+
+               status = stat (path_ptr, &statbuf);
+               if (status != 0)
+               {
+                       char errbuf[1024];
+                       ERROR ("configfile: stat (%s) failed: %s",
+                                       path_ptr,
+                                       sstrerror (errno, errbuf, sizeof (errbuf)));
+                       return (NULL);
+               }
+
+               if (S_ISREG (statbuf.st_mode))
+                       temp = cf_read_file (path_ptr, depth);
+               else if (S_ISDIR (statbuf.st_mode))
+                       temp = cf_read_dir (path_ptr, depth);
+               else
+               {
+                       ERROR ("configfile: %s is neither a file nor a "
+                                       "directory.", path);
+                       continue;
+               }
+
+               cf_ci_append_children (root, temp);
+               sfree (temp->children);
+               sfree (temp);
+       }
+
+       wordfree (&we);
+
+       return (root);
+} /* oconfig_item_t *cf_read_generic */
+/* #endif HAVE_WORDEXP_H */
+
+#else /* if !HAVE_WORDEXP_H */
+static oconfig_item_t *cf_read_generic (const char *path, int depth)
+{
+       struct stat statbuf;
+       int status;
+
+       if (depth >= CF_MAX_DEPTH)
+       {
+               ERROR ("configfile: Not including `%s' because the maximum "
+                               "nesting depth has been reached.", path);
+               return (NULL);
+       }
 
        status = stat (path, &statbuf);
        if (status != 0)
@@ -579,6 +670,7 @@ static oconfig_item_t *cf_read_generic (const char *path, int depth)
        ERROR ("configfile: %s is neither a file nor a directory.", path);
        return (NULL);
 } /* oconfig_item_t *cf_read_generic */
+#endif /* !HAVE_WORDEXP_H */
 
 /* 
  * Public functions