]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
dovecot.conf: Added support for !include globs.
authorTimo Sirainen <tss@iki.fi>
Mon, 27 Jul 2009 00:59:40 +0000 (20:59 -0400)
committerTimo Sirainen <tss@iki.fi>
Mon, 27 Jul 2009 00:59:40 +0000 (20:59 -0400)
Based on patch by Thomas Guthmann.

--HG--
branch : HEAD

configure.in
dovecot-example.conf
src/config/config-parser.c
src/lib-settings/settings.c

index fa1f0483627e28bc58b724b74379372d6feea717..c36ee7627ba7c03fac4d77dc33a51320cd050c03 100644 (file)
@@ -292,7 +292,7 @@ AC_CHECK_HEADERS(strings.h stdint.h unistd.h dirent.h malloc.h inttypes.h \
   sys/quota.h sys/fs/ufs_quota.h ufs/ufs/quota.h jfs/quota.h sys/fs/quota_common.h \
   mntent.h sys/mnttab.h sys/event.h sys/time.h sys/mkdev.h linux/dqblk_xfs.h \
   xfs/xqm.h execinfo.h ucontext.h malloc_np.h sys/utsname.h sys/vmount.h \
-  sys/utsname.h)
+  sys/utsname.h glob.h)
 
 dnl * gcc specific options
 if test "x$ac_cv_c_compiler_gnu" = "xyes"; then
@@ -351,7 +351,7 @@ AC_CHECK_FUNCS(fcntl flock lockf inet_aton sigaction getpagesize madvise \
               setrlimit setproctitle seteuid setreuid setegid setresgid \
               strtoull strtoll strtouq strtoq \
               setpriority quotactl getmntent kqueue kevent backtrace_symbols \
-              walkcontext dirfd clearenv malloc_usable_size)
+              walkcontext dirfd clearenv malloc_usable_size glob)
 
 AC_CHECK_LIB(rt, clock_gettime, [
   AC_DEFINE(HAVE_CLOCK_GETTIME,, Define if you have the clock_gettime function)
index eaa1da7dc709abd5328ae800fba9d9bf766100cc..ff25253c386a7f382c044d21c30d3c130ae73169 100644 (file)
@@ -1213,3 +1213,8 @@ plugin {
   # size and vsize are available only for expunge and copy events.
   #mail_log_fields = uid box msgid size
 }
+
+# Config files can also be included:
+#!include = /etc/dovecot/conf.d/*.conf
+# Optional configurations, don't give an error if it's not found:
+#!include_try = /etc/dovecot/extra.conf
index 2d92227b1abae82ee86aed785ac0cea84e8b045d..d2cd8fa9254694f414ef6f311bdf5159f54e4ff8 100644 (file)
@@ -12,6 +12,9 @@
 
 #include <unistd.h>
 #include <fcntl.h>
+#ifdef HAVE_GLOB_H
+#  include <glob.h>
+#endif
 
 #define IS_WHITE(c) ((c) == ' ' || (c) == '\t')
 
@@ -265,11 +268,84 @@ str_append_file(string_t *str, const char *key, const char *path,
        (void)close(fd);
 }
 
+static int settings_add_include(struct parser_context *ctx, const char *path,
+                               bool ignore_errors, const char **error_r)
+{
+       struct input_stack *tmp, *new_input;
+       int fd;
+
+       for (tmp = ctx->cur_input; tmp != NULL; tmp = tmp->prev) {
+               if (strcmp(tmp->path, path) == 0)
+                       break;
+       }
+       if (tmp != NULL) {
+               *error_r = t_strdup_printf("Recursive include file: %s", path);
+               return -1;
+       }
+
+       if ((fd = open(path, O_RDONLY)) == -1) {
+               if (ignore_errors)
+                       return 0;
+
+               *error_r = t_strdup_printf("Couldn't open include file %s: %m",
+                                          path);
+               return -1;
+       }
+
+       new_input = t_new(struct input_stack, 1);
+       new_input->prev = ctx->cur_input;
+       new_input->path = t_strdup(path);
+       new_input->input = i_stream_create_fd(fd, 2048, TRUE);
+       i_stream_set_return_partial_line(new_input->input, TRUE);
+       ctx->cur_input = new_input;
+       return 0;
+}
+
+static int
+settings_include(struct parser_context *ctx, const char *pattern,
+                bool ignore_errors, const char **error_r)
+{
+#ifdef HAVE_GLOB
+       glob_t globbers;
+       unsigned int i;
+
+       switch (glob(pattern, GLOB_BRACE, NULL, &globbers)) {
+       case 0:
+               break;
+       case GLOB_NOSPACE:
+               *error_r = "glob() failed: Not enough memory";
+               return -1;
+       case GLOB_ABORTED:
+               *error_r = "glob() failed: Read error";
+               return -1;
+       case GLOB_NOMATCH:
+               if (ignore_errors)
+                       return 0;
+               *error_r = "No matches";
+               return -1;
+       default:
+               *error_r = "glob() failed: Unknown error";
+               return -1;
+       }
+
+       /* iterate throuth the different files matching the globbing */
+       for (i = 0; i < globbers.gl_pathc; i++) {
+               if (settings_add_include(ctx, globbers.gl_pathv[i],
+                                        ignore_errors, error_r) < 0)
+                       return -1;
+       }
+       globfree(&globbers);
+       return 0;
+#else
+       return settings_add_include(ctx, pattern, ignore_errors, error_r);
+#endif
+}
+
 void config_parse_file(const char *path, bool expand_files)
 {
        enum settings_parser_flags parser_flags =
                 SETTINGS_PARSER_FLAG_IGNORE_UNKNOWN_KEYS;
-       struct input_stack root, *new_input;
+       struct input_stack root;
        ARRAY_TYPE(const_string) auth_defaults;
        struct config_setting_parser_list *l, *const *parsers;
        struct parser_context ctx;
@@ -314,7 +390,6 @@ void config_parse_file(const char *path, bool expand_files)
        str = t_str_new(256);
        full_line = t_str_new(512);
        errormsg = NULL;
-newfile:
        ctx.cur_input->input = i_stream_create_fd(fd, (size_t)-1, TRUE);
        i_stream_set_return_partial_line(ctx.cur_input->input, TRUE);
 prevfile:
@@ -378,29 +453,10 @@ prevfile:
                ret = 1;
                if (strcmp(key, "!include_try") == 0 ||
                    strcmp(key, "!include") == 0) {
-                       struct input_stack *tmp;
-                       const char *path;
-
-                       path = fix_relative_path(line, ctx.cur_input);
-                       for (tmp = ctx.cur_input; tmp != NULL; tmp = tmp->prev) {
-                               if (strcmp(tmp->path, path) == 0)
-                                       break;
-                       }
-                       if (tmp != NULL) {
-                               errormsg = "Recursive include";
-                       } else if ((fd = open(path, O_RDONLY)) != -1) {
-                               new_input = t_new(struct input_stack, 1);
-                               new_input->prev = ctx.cur_input;
-                               new_input->path = t_strdup(path);
-                               ctx.cur_input = new_input;
-                               goto newfile;
-                       } else {
-                               /* failed, but ignore failures with include_try. */
-                               if (strcmp(key, "!include") == 0) {
-                                       errormsg = t_strdup_printf(
-                                               "Couldn't open include file %s: %m", line);
-                               }
-                       }
+                       if (settings_include(&ctx, fix_relative_path(line, ctx.cur_input),
+                                            strcmp(key, "!include_try") == 0,
+                                            &errormsg) == 0)
+                               goto prevfile;
                } else if (*line == '=') {
                        /* a) */
                        *line++ = '\0';
index 305f6be464270d23a0cdd0d9e202566e1dcdf7eb..575b2c9e8637ed34b777c25a79875063ad40b739 100644 (file)
@@ -8,6 +8,9 @@
 
 #include <stdio.h>
 #include <fcntl.h>
+#ifdef HAVE_GLOB_H
+#  include <glob.h>
+#endif
 
 #define SECTION_ERRORMSG "%s (section changed in %s at line %d)"
 
@@ -85,6 +88,79 @@ fix_relative_path(const char *path, struct input_stack *input)
        return t_strconcat(t_strdup_until(input->path, p+1), path, NULL);
 }
 
+static int settings_add_include(const char *path, struct input_stack **inputp,
+                               bool ignore_errors, const char **error_r)
+{
+       struct input_stack *tmp, *new_input;
+       int fd;
+
+       for (tmp = *inputp; tmp != NULL; tmp = tmp->prev) {
+               if (strcmp(tmp->path, path) == 0)
+                       break;
+       }
+       if (tmp != NULL) {
+               *error_r = t_strdup_printf("Recursive include file: %s", path);
+               return -1;
+       }
+
+       if ((fd = open(path, O_RDONLY)) == -1) {
+               if (ignore_errors)
+                       return 0;
+
+               *error_r = t_strdup_printf("Couldn't open include file %s: %m",
+                                          path);
+               return -1;
+       }
+
+       new_input = t_new(struct input_stack, 1);
+       new_input->prev = *inputp;
+       new_input->path = t_strdup(path);
+       new_input->input = i_stream_create_fd(fd, 2048, TRUE);
+       i_stream_set_return_partial_line(new_input->input, TRUE);
+       *inputp = new_input;
+       return 0;
+}
+
+static int
+settings_include(const char *pattern, struct input_stack **inputp,
+                bool ignore_errors, const char **error_r)
+{
+#ifdef HAVE_GLOB
+       glob_t globbers;
+       unsigned int i;
+
+       switch (glob(pattern, GLOB_BRACE, NULL, &globbers)) {
+       case 0:
+               break;
+       case GLOB_NOSPACE:
+               *error_r = "glob() failed: Not enough memory";
+               return -1;
+       case GLOB_ABORTED:
+               *error_r = "glob() failed: Read error";
+               return -1;
+       case GLOB_NOMATCH:
+               if (ignore_errors)
+                       return 0;
+               *error_r = "No matches";
+               return -1;
+       default:
+               *error_r = "glob() failed: Unknown error";
+               return -1;
+       }
+
+       /* iterate throuth the different files matching the globbing */
+       for (i = 0; i < globbers.gl_pathc; i++) {
+               if (settings_add_include(globbers.gl_pathv[i], inputp,
+                                        ignore_errors, error_r) < 0)
+                       return -1;
+       }
+       globfree(&globbers);
+       return 0;
+#else
+       return settings_add_include(pattern, inputp, ignore_errors, error_r);
+#endif
+}
+
 #define IS_WHITE(c) ((c) == ' ' || (c) == '\t')
 
 static bool
@@ -93,7 +169,7 @@ settings_read_real(const char *path, const char *section,
                   settings_section_callback_t *sect_callback, void *context)
 {
        /* pretty horrible code, but v2.0 will have this rewritten anyway.. */
-       struct input_stack root, *input, *new_input;
+       struct input_stack root, *input;
        const char *errormsg, *next_section, *name, *last_section_path = NULL;
        char *line, *key, *p, quote;
        string_t *full_line;
@@ -120,7 +196,6 @@ settings_read_real(const char *path, const char *section,
 
        full_line = t_str_new(512);
        sections = 0; root_section = 0; errormsg = NULL;
-newfile:
        input->input = i_stream_create_fd(fd, 2048, TRUE);
        i_stream_set_return_partial_line(input->input, TRUE);
 prevfile:
@@ -183,29 +258,11 @@ prevfile:
 
                if (strcmp(key, "!include_try") == 0 ||
                    strcmp(key, "!include") == 0) {
-                       struct input_stack *tmp;
-                       const char *path;
-
-                       path = fix_relative_path(line, input);
-                       for (tmp = input; tmp != NULL; tmp = tmp->prev) {
-                               if (strcmp(tmp->path, path) == 0)
-                                       break;
-                       }
-                       if (tmp != NULL) {
-                               errormsg = "Recursive include";
-                       } else if ((fd = open(path, O_RDONLY)) != -1) {
-                               new_input = t_new(struct input_stack, 1);
-                               new_input->prev = input;
-                               new_input->path = t_strdup(path);
-                               input = new_input;
-                               goto newfile;
-                       } else {
-                               /* failed, but ignore failures with include_try. */
-                               if (strcmp(key, "!include") == 0) {
-                                       errormsg = t_strdup_printf(
-                                               "Couldn't open include file %s: %m", line);
-                               }
-                       }
+                       if (settings_include(fix_relative_path(line, input),
+                                            &input,
+                                            strcmp(key, "!include_try") == 0,
+                                            &errormsg) == 0)
+                               goto prevfile;
                } else if (*line == '=') {
                        /* a) */
                        *line++ = '\0';