Mercurial > dovecot > core-2.2
changeset 9669:6cc6913fee1c HEAD
dovecot.conf: Added support for !include globs.
Based on patch by Thomas Guthmann.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Sun, 26 Jul 2009 20:59:40 -0400 |
parents | 462dcad58a92 |
children | c163bc483c9e |
files | configure.in dovecot-example.conf src/config/config-parser.c src/lib-settings/settings.c |
diffstat | 4 files changed, 170 insertions(+), 52 deletions(-) [+] |
line wrap: on
line diff
--- a/configure.in Sun Jul 26 20:13:18 2009 -0400 +++ b/configure.in Sun Jul 26 20:59:40 2009 -0400 @@ -292,7 +292,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 @@ -351,7 +351,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)
--- a/dovecot-example.conf Sun Jul 26 20:13:18 2009 -0400 +++ b/dovecot-example.conf Sun Jul 26 20:59:40 2009 -0400 @@ -1213,3 +1213,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
--- a/src/config/config-parser.c Sun Jul 26 20:13:18 2009 -0400 +++ b/src/config/config-parser.c Sun Jul 26 20:59:40 2009 -0400 @@ -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 @@ (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 @@ 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 @@ 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';
--- a/src/lib-settings/settings.c Sun Jul 26 20:13:18 2009 -0400 +++ b/src/lib-settings/settings.c Sun Jul 26 20:59:40 2009 -0400 @@ -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 @@ 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';