# HG changeset patch # User Timo Sirainen # Date 1248656332 14400 # Node ID 1aec43edab2dbebbabc1222024fd5f9a0befe2c3 # Parent d6fcb6d050bab36737f07bc5298a0242b9fe1813 dovecot.conf: Added support for !include globs. Based on patch by Thomas Guthmann. diff -r d6fcb6d050ba -r 1aec43edab2d configure.in --- a/configure.in Sun Jul 26 20:13:18 2009 -0400 +++ b/configure.in Sun Jul 26 20:58:52 2009 -0400 @@ -304,7 +304,7 @@ 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 @@ -363,7 +363,7 @@ 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) diff -r d6fcb6d050ba -r 1aec43edab2d dovecot-example.conf --- a/dovecot-example.conf Sun Jul 26 20:13:18 2009 -0400 +++ b/dovecot-example.conf Sun Jul 26 20:58:52 2009 -0400 @@ -1208,3 +1208,8 @@ # 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 diff -r d6fcb6d050ba -r 1aec43edab2d src/lib-settings/settings.c --- a/src/lib-settings/settings.c Sun Jul 26 20:13:18 2009 -0400 +++ b/src/lib-settings/settings.c Sun Jul 26 20:58:52 2009 -0400 @@ -8,6 +8,9 @@ #include #include +#ifdef HAVE_GLOB_H +# include +#endif #define SECTION_ERRORMSG "%s (section changed in %s at line %d)" @@ -85,6 +88,79 @@ 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_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 @@ 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 @@ 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';