summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 1620299)
raw | patch | inline | side by side (parent: 1620299)
author | Sebastian Harl <sh@tokkee.org> | |
Sat, 24 Nov 2012 09:26:20 +0000 (10:26 +0100) | ||
committer | Sebastian Harl <sh@tokkee.org> | |
Sat, 24 Nov 2012 09:26:20 +0000 (10:26 +0100) |
An optional second argument may now be passed to the "Include" configuration
option. If specified (and if the fnmatch() function was available at build
time), only files matching this pattern will be included. For example, the
following will include all files matching "*.conf" in any subdirectory of
/etc/collectd.d/:
Include "/etc/collectd.d" "*.conf"
This is useful, e.g. for distributions in order to include a possibly empty
directory in the default configuration including all subdirectories but also
making it possible to ship further documents like README files.
option. If specified (and if the fnmatch() function was available at build
time), only files matching this pattern will be included. For example, the
following will include all files matching "*.conf" in any subdirectory of
/etc/collectd.d/:
Include "/etc/collectd.d" "*.conf"
This is useful, e.g. for distributions in order to include a possibly empty
directory in the default configuration including all subdirectories but also
making it possible to ship further documents like README files.
configure.in | patch | blob | history | |
src/collectd.conf.pod | patch | blob | history | |
src/configfile.c | patch | blob | history |
diff --git a/configure.in b/configure.in
index 98395ed14228a484c886a3659031a30b6c333c85..f0f9cfb9af553b4013c2969e629e2282d5bd51d9 100644 (file)
--- a/configure.in
+++ b/configure.in
AC_HEADER_DIRENT
AC_HEADER_STDBOOL
-AC_CHECK_HEADERS(stdio.h errno.h math.h stdarg.h syslog.h fcntl.h signal.h assert.h sys/types.h sys/socket.h sys/select.h poll.h netdb.h arpa/inet.h sys/resource.h sys/param.h kstat.h regex.h sys/ioctl.h endian.h sys/isa_defs.h)
+AC_CHECK_HEADERS(stdio.h errno.h math.h stdarg.h syslog.h fcntl.h signal.h assert.h sys/types.h sys/socket.h sys/select.h poll.h netdb.h arpa/inet.h sys/resource.h sys/param.h kstat.h regex.h sys/ioctl.h endian.h sys/isa_defs.h fnmatch.h libgen.h)
# For ping library
AC_CHECK_HEADERS(netinet/in_systm.h, [], [],
fi
# For hddtemp module
-AC_CHECK_HEADERS(linux/major.h libgen.h)
+AC_CHECK_HEADERS(linux/major.h)
# For md module (Linux only)
if test "x$ac_system" = "xLinux"
diff --git a/src/collectd.conf.pod b/src/collectd.conf.pod
index 1c8b7a4f2153183c716f83accd0dc02e7389abbd..80fd31b13141013f34239de9cc975f6b2a6e5a3a 100644 (file)
--- a/src/collectd.conf.pod
+++ b/src/collectd.conf.pod
=back
-=item B<Include> I<Path>
+=item B<Include> I<Path> [I<pattern>]
If I<Path> points to a file, includes that file. If I<Path> points to a
directory, recursively includes all files within that directory and its
Include "/etc/collectd.d/*.conf"
+If the C<fnmatch> function is available on your system, a shell-like wildcard
+I<pattern> may be specified to filter which files to include. This may be used
+in combination with recursively including a directory to easily be able to
+arbitrarily mix configuration files and other documents (e.g. README files).
+The following statement is similar to the example above but includes all files
+matching C<*.conf> in any subdirectory of C</etc/collectd.d>:
+
+ 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
diff --git a/src/configfile.c b/src/configfile.c
index 5920c53129628c3691af816843aff70af8f55e5c..1a9e28a624fed56c302cdec73c30bc563ef89597 100644 (file)
--- a/src/configfile.c
+++ b/src/configfile.c
# include <wordexp.h>
#endif /* HAVE_WORDEXP_H */
+#if HAVE_FNMATCH_H
+# include <fnmatch.h>
+#endif /* HAVE_FNMATCH_H */
+
+#if HAVE_LIBGEN_H
+# include <libgen.h>
+#endif /* HAVE_LIBGEN_H */
+
#define ESCAPE_NULL(str) ((str) == NULL ? "(null)" : (str))
/*
} /* int cf_ci_append_children */
#define CF_MAX_DEPTH 8
-static oconfig_item_t *cf_read_generic (const char *path, int depth);
+static oconfig_item_t *cf_read_generic (const char *path,
+ const char *pattern, int depth);
static int cf_include_all (oconfig_item_t *root, int depth)
{
old = root->children + i;
- if ((old->values_num != 1)
- || (old->values[0].type != OCONFIG_TYPE_STRING))
+ if ((old->values_num < 1) || (old->values_num > 2)
+ || (old->values[0].type != OCONFIG_TYPE_STRING)
+ || ((old->values_num == 2)
+ && (old->values[1].type != OCONFIG_TYPE_STRING)))
{
- ERROR ("configfile: `Include' needs exactly one string argument.");
+ ERROR ("configfile: `Include' needs exactly one or two string argument.");
continue;
}
- new = cf_read_generic (old->values[0].value.string, depth + 1);
+ new = cf_read_generic (old->values[0].value.string,
+ (old->values_num == 2) ? old->values[1].value.string : NULL,
+ depth + 1);
if (new == NULL)
continue;
return (0);
} /* int cf_include_all */
-static oconfig_item_t *cf_read_file (const char *file, int depth)
+static oconfig_item_t *cf_read_file (const char *file,
+ const char *pattern, int depth)
{
oconfig_item_t *root;
assert (depth < CF_MAX_DEPTH);
+ if (pattern != NULL) {
+#if HAVE_FNMATCH_H && HAVE_LIBGEN_H
+ char *tmp = sstrdup (file);
+ char *filename = basename (tmp);
+
+ if ((filename != NULL) && (fnmatch (pattern, filename, 0) != 0)) {
+ free (tmp);
+ return (NULL);
+ }
+
+ free (tmp);
+#else
+ ERROR ("configfile: Cannot apply pattern filter '%s' "
+ "to file '%s': functions basename() and / or "
+ "fnmatch() not available.", pattern, file);
+#endif /* HAVE_FNMATCH_H && HAVE_LIBGEN_H */
+ }
+
root = oconfig_parse_file (file);
if (root == NULL)
{
return strcmp (*(const char **) p1, *(const char **) p2);
}
-static oconfig_item_t *cf_read_dir (const char *dir, int depth)
+static oconfig_item_t *cf_read_dir (const char *dir,
+ const char *pattern, int depth)
{
oconfig_item_t *root = NULL;
DIR *dh;
oconfig_item_t *temp;
char *name = filenames[i];
- temp = cf_read_generic (name, depth);
+ temp = cf_read_generic (name, pattern, depth);
if (temp == NULL)
{
/* An error should already have been reported. */
* 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)
+static oconfig_item_t *cf_read_generic (const char *path,
+ const char *pattern, int depth)
{
oconfig_item_t *root = NULL;
int status;
}
if (S_ISREG (statbuf.st_mode))
- temp = cf_read_file (path_ptr, depth);
+ temp = cf_read_file (path_ptr, pattern, depth);
else if (S_ISDIR (statbuf.st_mode))
- temp = cf_read_dir (path_ptr, depth);
+ temp = cf_read_dir (path_ptr, pattern, depth);
else
{
WARNING ("configfile: %s is neither a file nor a "
/* #endif HAVE_WORDEXP_H */
#else /* if !HAVE_WORDEXP_H */
-static oconfig_item_t *cf_read_generic (const char *path, int depth)
+static oconfig_item_t *cf_read_generic (const char *path,
+ const char *pattern, int depth)
{
struct stat statbuf;
int status;
}
if (S_ISREG (statbuf.st_mode))
- return (cf_read_file (path, depth));
+ return (cf_read_file (path, pattern, depth));
else if (S_ISDIR (statbuf.st_mode))
- return (cf_read_dir (path, depth));
+ return (cf_read_dir (path, pattern, depth));
ERROR ("configfile: %s is neither a file nor a directory.", path);
return (NULL);
oconfig_item_t *conf;
int i;
- conf = cf_read_generic (filename, 0 /* depth */);
+ conf = cf_read_generic (filename, /* pattern = */ NULL, /* depth = */ 0);
if (conf == NULL)
{
ERROR ("Unable to read config file %s.", filename);