]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
config: Several fixes. Now per-ip settings work properly.
authorTimo Sirainen <tss@iki.fi>
Thu, 3 Sep 2009 20:36:38 +0000 (16:36 -0400)
committerTimo Sirainen <tss@iki.fi>
Thu, 3 Sep 2009 20:36:38 +0000 (16:36 -0400)
doveconf parameters were also changed. Now it's possible to ask
configuration for a specified filter.

--HG--
branch : HEAD

src/config/config-connection.c
src/config/config-filter.c
src/config/config-filter.h
src/config/config-parser.c
src/config/config-request.c
src/config/config-request.h
src/config/doveconf.c

index b6af523297784c2bd796090050dc8847a40ddf36..44e9add7b7206936929d49ce4bbc7af66807d7ee 100644 (file)
@@ -102,8 +102,11 @@ static int config_connection_request(struct config_connection *conn,
        }
 
        o_stream_cork(conn->output);
-       config_request_handle(&filter, module, 0, config_request_output,
-                             conn->output);
+       if (config_request_handle(&filter, module, CONFIG_DUMP_SCOPE_SET, FALSE,
+                                 config_request_output, conn->output) < 0) {
+               config_connection_destroy(conn);
+               return -1;
+       }
        o_stream_send_str(conn->output, "\n");
        o_stream_uncork(conn->output);
        return 0;
index a50b3b5a3a8e84242eb63308023857149d50291a..783ce9b06809d7e6e5dc49d2f886e0ecba8debc7 100644 (file)
@@ -2,12 +2,13 @@
 
 #include "lib.h"
 #include "array.h"
+#include "settings-parser.h"
 #include "config-parser.h"
 #include "config-filter.h"
 
 struct config_filter_context {
        pool_t pool;
-       struct config_filter_parser_list *const *parsers;
+       struct config_filter_parser *const *parsers;
 };
 
 bool config_filter_match(const struct config_filter *mask,
@@ -75,47 +76,123 @@ void config_filter_deinit(struct config_filter_context **_ctx)
 }
 
 void config_filter_add_all(struct config_filter_context *ctx,
-                          struct config_filter_parser_list *const *parsers)
+                          struct config_filter_parser *const *parsers)
 {
        ctx->parsers = parsers;
 }
 
-static int filter_cmp(const struct config_filter *f1,
-                     const struct config_filter *f2)
+static int
+config_filter_parser_cmp(struct config_filter_parser *const *p1,
+                        struct config_filter_parser *const *p2)
 {
-       int ret;
+       const struct config_filter *f1 = &(*p1)->filter, *f2 = &(*p2)->filter;
 
-       ret = f2->remote_bits - f1->remote_bits;
-       if (ret != 0)
-               return ret;
+       /* remote_ip and local_ips are first, although it doesn't really
+          matter which one comes first */
+       if (f1->local_bits > f2->local_bits)
+               return -1;
+       if (f1->local_bits < f2->local_bits)
+               return 1;
 
-       ret = f2->local_bits - f1->local_bits;
-       if (ret != 0)
-               return ret;
+       if (f1->remote_bits > f2->remote_bits)
+               return -1;
+       if (f1->remote_bits < f2->remote_bits)
+               return 1;
 
-       if (f1->service != NULL)
+       if (f1->service != NULL && f2->service == NULL)
                return -1;
-       else
+       if (f1->service == NULL && f2->service != NULL)
                return 1;
+       return 0;
 }
 
-const struct config_filter_parser_list *
-config_filter_find(struct config_filter_context *ctx,
-                  const struct config_filter *filter)
+static struct config_filter_parser *const *
+config_filter_find_all(struct config_filter_context *ctx,
+                      const struct config_filter *filter)
 {
-       struct config_filter_parser_list *best = NULL;
+       ARRAY_TYPE(config_filter_parsers) matches;
        unsigned int i;
 
-       /* find the filter that best matches what we have.
-          FIXME: this can't really work. we'd want to merge changes from
-          different matches.. requires something larger after all. */
+       t_array_init(&matches, 8);
        for (i = 0; ctx->parsers[i] != NULL; i++) {
-               if (!config_filter_match(&ctx->parsers[i]->filter, filter))
-                       continue;
+               if (config_filter_match(&ctx->parsers[i]->filter, filter))
+                       array_append(&matches, &ctx->parsers[i], 1);
+       }
+       array_sort(&matches, config_filter_parser_cmp);
+       (void)array_append_space(&matches);
+       return array_idx(&matches, 0);
+}
+
+static bool
+config_filter_is_superset(const struct config_filter *sup,
+                         const struct config_filter *filter)
+{
+       /* assume that both of the filters match the same subset, so we don't
+          need to compare IPs and service name. */
+       if (sup->local_bits < filter->local_bits)
+               return FALSE;
+       if (sup->remote_bits < filter->remote_bits)
+               return FALSE;
+       if (sup->service != NULL && filter->service == NULL)
+               return FALSE;
+       return TRUE;
+}
+
+static int
+config_module_parser_apply_changes(struct config_module_parser *dest,
+                                  const struct config_filter_parser *src,
+                                  pool_t pool, const char **error_r)
+{
+       unsigned int i;
+
+       for (i = 0; dest[i].module_name != NULL; i++) {
+               if (settings_parser_apply_changes(dest[i].parser,
+                                                 src->parsers[i].parser, pool,
+                                                 error_r) < 0) {
+                       *error_r = t_strdup_printf("Conflict in setting %s",
+                                                  *error_r);
+                       return -1;
+               }
+       }
+       return 0;
+}
+
+int config_filter_get_parsers(struct config_filter_context *ctx, pool_t pool,
+                             const struct config_filter *filter,
+                             const struct config_module_parser **parsers_r,
+                             const char **error_r)
+{
+       struct config_filter_parser *const *src;
+       struct config_module_parser *dest;
+       const char *error, **error_p;
+       unsigned int i, count;
+
+       src = config_filter_find_all(ctx, filter);
+
+       /* all of them should have the same number of parsers.
+          duplicate our initial parsers from the first match */
+       for (count = 0; src[0]->parsers[count].module_name != NULL; count++) ;
+       dest = p_new(pool, struct config_module_parser, count + 1);
+       for (i = 0; i < count; i++) {
+               dest[i] = src[0]->parsers[i];
+               dest[i].parser =
+                       settings_parser_dup(src[0]->parsers[i].parser, pool);
+       }
 
-               if (best == NULL ||
-                   filter_cmp(&best->filter, &ctx->parsers[i]->filter) > 0)
-                       best = ctx->parsers[i];
+       /* apply the changes from rest of the matches */
+       for (i = 1; src[i] != NULL; i++) {
+               if (config_filter_is_superset(&src[i-1]->filter,
+                                             &src[i]->filter))
+                       error_p = NULL;
+               else
+                       error_p = &error;
+
+               if (config_module_parser_apply_changes(dest, src[i], pool,
+                                                      error_p) < 0) {
+                       *error_r = error;
+                       return -1;
+               }
        }
-       return best;
+       *parsers_r = dest;
+       return 0;
 }
index eb77353724e7d933d3c30a8410959b4ab096bc62..b53ee77e179502b357d511d9da683f946f7e07bc 100644 (file)
@@ -9,23 +9,25 @@ struct config_filter {
        unsigned int local_bits, remote_bits;
 };
 
-struct config_filter_parser_list {
+struct config_filter_parser {
        struct config_filter filter;
        /* NULL-terminated array of parsers */
        struct config_module_parser *parsers;
 };
+ARRAY_DEFINE_TYPE(config_filter_parsers, struct config_filter_parser *);
 
 struct config_filter_context *config_filter_init(pool_t pool);
 void config_filter_deinit(struct config_filter_context **ctx);
 
 /* Replace filter's parsers with given parser list. */
 void config_filter_add_all(struct config_filter_context *ctx,
-                          struct config_filter_parser_list *const *parsers);
+                          struct config_filter_parser *const *parsers);
 
-/* Find the filter that best matches what we have. */
-const struct config_filter_parser_list *
-config_filter_find(struct config_filter_context *ctx,
-                  const struct config_filter *filter);
+/* Build new parsers from all existing ones matching the given filter. */
+int config_filter_get_parsers(struct config_filter_context *ctx, pool_t pool,
+                             const struct config_filter *filter,
+                             const struct config_module_parser **parsers_r,
+                             const char **error_r);
 
 /* Returns TRUE if filter matches mask. */
 bool config_filter_match(const struct config_filter *mask,
index 10bf085ee6c4857d8bea9e496c49d59e344cc1e8..ecda89d21188f883355efe813454f33b6ab3a873 100644 (file)
 
 #define IS_WHITE(c) ((c) == ' ' || (c) == '\t')
 
-struct config_filter_stack {
-       struct config_filter_stack *prev;
+struct config_section_stack {
+       struct config_section_stack *prev;
+
        struct config_filter filter;
+       /* module_name=NULL-terminated list of parsers */
+       struct config_module_parser *parsers;
        unsigned int pathlen;
 };
 
@@ -41,16 +44,18 @@ struct parser_context {
        pool_t pool;
        const char *path;
 
-       ARRAY_DEFINE(all_parsers, struct config_filter_parser_list *);
-       /* parsers matching cur_filter */
-       ARRAY_TYPE(config_module_parsers) cur_parsers;
+       ARRAY_DEFINE(all_parsers, struct config_filter_parser *);
        struct config_module_parser *root_parsers;
-       struct config_filter_stack *cur_filter;
+       struct config_section_stack *cur_section;
        struct input_stack *cur_input;
 
        struct config_filter_context *filter;
 };
 
+static const enum settings_parser_flags settings_parser_flags =
+       SETTINGS_PARSER_FLAG_IGNORE_UNKNOWN_KEYS |
+       SETTINGS_PARSER_FLAG_TRACK_CHANGES;
+
 struct config_module_parser *config_module_parsers;
 struct config_filter_context *config_filter;
 
@@ -93,15 +98,15 @@ static void config_add_type(struct setting_parser_context *parser,
 }
 
 static int
-config_parsers_parse_line(struct config_module_parser *parsers,
-                         const char *key, const char *line,
-                         const char *section_name, const char **error_r)
+config_apply_line(struct parser_context *ctx, const char *key,
+                 const char *line, const char *section_name,
+                 const char **error_r)
 {
        struct config_module_parser *l;
        bool found = FALSE;
        int ret;
 
-       for (l = parsers; l->module_name != NULL; l++) {
+       for (l = ctx->cur_section->parsers; l->module_name != NULL; l++) {
                ret = settings_parse_line(l->parser, line);
                if (ret > 0) {
                        found = TRUE;
@@ -116,23 +121,6 @@ config_parsers_parse_line(struct config_module_parser *parsers,
                *error_r = t_strconcat("Unknown setting: ", key, NULL);
                return -1;
        }
-       return 0;
-}
-
-static int
-config_apply_line(struct parser_context *ctx, const char *key,
-                 const char *line, const char *section_name,
-                 const char **error_r)
-{
-       struct config_module_parser *const *parsers;
-       unsigned int i, count;
-
-       parsers = array_get(&ctx->cur_parsers, &count);
-       for (i = 0; i < count; i++) {
-               if (config_parsers_parse_line(parsers[i], key, line,
-                                             section_name, error_r) < 0)
-                       return -1;
-       }
        *error_r = NULL;
        return 0;
 }
@@ -153,61 +141,72 @@ fix_relative_path(const char *path, struct input_stack *input)
 }
 
 static struct config_module_parser *
-config_module_parsers_dup(pool_t pool, const struct config_module_parser *src)
+config_module_parsers_init(pool_t pool)
 {
        struct config_module_parser *dest;
        unsigned int i, count;
 
-       for (count = 0; src[count].module_name != NULL; count++) ;
+       for (count = 0; all_roots[count].module_name != NULL; count++) ;
 
        dest = p_new(pool, struct config_module_parser, count + 1);
        for (i = 0; i < count; i++) {
-               dest[i] = src[i];
-               dest[i].parser = settings_parser_dup(src[i].parser, pool);
+               dest[i].module_name = all_roots[i].module_name;
+               dest[i].root = all_roots[i].root;
+               dest[i].parser = settings_parser_init(pool, all_roots[i].root,
+                                                     settings_parser_flags);
        }
        return dest;
 }
 
-static struct config_filter_parser_list *
+static void
 config_add_new_parser(struct parser_context *ctx)
 {
-       struct config_filter_parser_list *parser;
-       struct config_module_parser *const *cur_parsers;
-       unsigned int count;
+       struct config_section_stack *cur_section = ctx->cur_section;
+       struct config_filter_parser *parser;
 
-       parser = p_new(ctx->pool, struct config_filter_parser_list, 1);
-       parser->filter = ctx->cur_filter->filter;
+       parser = p_new(ctx->pool, struct config_filter_parser, 1);
+       parser->filter = cur_section->filter;
+       parser->parsers = cur_section->prev == NULL ? ctx->root_parsers :
+               config_module_parsers_init(ctx->pool);
+       array_append(&ctx->all_parsers, &parser, 1);
 
-       cur_parsers = array_get(&ctx->cur_parsers, &count);
-       if (count == 0) {
-               /* first one */
-               parser->parsers = ctx->root_parsers;
-       } else {
-               /* duplicate the first settings list */
-               parser->parsers =
-                       config_module_parsers_dup(ctx->pool, cur_parsers[0]);
-       }
+       cur_section->parsers = parser->parsers;
+}
 
-       array_append(&ctx->all_parsers, &parser, 1);
-       return parser;
+static struct config_section_stack *
+config_add_new_section(struct parser_context *ctx)
+{
+       struct config_section_stack *section;
+
+       section = p_new(ctx->pool, struct config_section_stack, 1);
+       section->prev = ctx->cur_section;
+       section->filter = ctx->cur_section->filter;
+       section->parsers = ctx->cur_section->parsers;
+       return section;
 }
 
-static void config_add_new_filter(struct parser_context *ctx)
+static struct config_filter_parser *
+config_filter_parser_find(struct parser_context *ctx,
+                         const struct config_filter *filter)
 {
-       struct config_filter_stack *filter;
+       struct config_filter_parser *const *parsers;
+       unsigned int i, count;
 
-       filter = p_new(ctx->pool, struct config_filter_stack, 1);
-       filter->prev = ctx->cur_filter;
-       filter->filter = ctx->cur_filter->filter;
-       ctx->cur_filter = filter;
+       parsers = array_get(&ctx->all_parsers, &count);
+       for (i = 0; i < count; i++) {
+               if (config_filters_equal(&parsers[i]->filter, filter))
+                       return parsers[i];
+       }
+       return NULL;
 }
 
 static bool
-config_filter_add_new_parser(struct parser_context *ctx,
+config_filter_add_new_filter(struct parser_context *ctx,
                             const char *key, const char *value,
                             const char **error_r)
 {
-       struct config_filter *filter = &ctx->cur_filter->filter;
+       struct config_filter *filter = &ctx->cur_section->filter;
+       struct config_filter_parser *parser;
 
        if (strcmp(key, "protocol") == 0) {
                filter->service = p_strdup(ctx->pool, value);
@@ -223,69 +222,51 @@ config_filter_add_new_parser(struct parser_context *ctx,
                return FALSE;
        }
 
-       config_add_new_parser(ctx);
+       parser = config_filter_parser_find(ctx, filter);
+       if (parser != NULL)
+               ctx->cur_section->parsers = parser->parsers;
+       else
+               config_add_new_parser(ctx);
        return TRUE;
 }
 
-static void config_update_cur_parsers(struct parser_context *ctx)
-{
-       struct config_filter_parser_list *const *all_parsers;
-       unsigned int i, count;
-       bool full_found = FALSE;
-
-       array_clear(&ctx->cur_parsers);
-
-       all_parsers = array_get(&ctx->all_parsers, &count);
-       for (i = 0; i < count; i++) {
-               if (!config_filter_match(&ctx->cur_filter->filter,
-                                        &all_parsers[i]->filter))
-                       continue;
-
-               if (config_filters_equal(&all_parsers[i]->filter,
-                                        &ctx->cur_filter->filter)) {
-                       array_insert(&ctx->cur_parsers, 0,
-                                    &all_parsers[i]->parsers, 1);
-                       full_found = TRUE;
-               } else {
-                       array_append(&ctx->cur_parsers,
-                                    &all_parsers[i]->parsers, 1);
-               }
-       }
-       i_assert(full_found);
-}
-
 static int
-config_filter_parser_list_check(struct parser_context *ctx,
-                               struct config_filter_parser_list *parser,
-                               const char **error_r)
+config_filter_parser_check(struct parser_context *ctx,
+                          const struct config_module_parser *p,
+                          const char **error_r)
 {
-       struct config_module_parser *l = parser->parsers;
-       const char *errormsg;
-
-       for (; l->module_name != NULL; l++) {
-               if (!settings_parser_check(l->parser, ctx->pool, &errormsg)) {
-                       *error_r = t_strdup_printf(
-                               "Error in configuration file %s: %s",
-                               ctx->path, errormsg);
+       for (; p->module_name != NULL; p++) {
+               if (!settings_parser_check(p->parser, ctx->pool, error_r))
                        return -1;
-               }
        }
        return 0;
 }
 
 static int
-config_all_parsers_check(struct parser_context *ctx, const char **error_r)
+config_all_parsers_check(struct parser_context *ctx,
+                        struct config_filter_context *new_filter,
+                        const char **error_r)
 {
-       struct config_filter_parser_list *const *parsers;
+       struct config_filter_parser *const *parsers;
+       const struct config_module_parser *tmp_parsers;
        unsigned int i, count;
+       pool_t tmp_pool;
 
+       tmp_pool = pool_alloconly_create("config parsers check", 10240);
        parsers = array_get(&ctx->all_parsers, &count);
+       i_assert(count > 0 && parsers[count-1] == NULL);
+       count--;
        for (i = 0; i < count; i++) {
-               if (config_filter_parser_list_check(ctx, parsers[i],
-                                                   error_r) < 0)
-                       return -1;
+               p_clear(tmp_pool);
+               if (config_filter_get_parsers(new_filter, tmp_pool,
+                                             &parsers[i]->filter,
+                                             &tmp_parsers, error_r) < 0)
+                       break;
+
+               if (config_filter_parser_check(ctx, tmp_parsers, error_r) < 0)
+                       break;
        }
-       return 0;
+       return i == count ? 0 : -1;
 }
 
 static int
@@ -514,12 +495,31 @@ config_parse_line(char *line, string_t *full_line, const char **key_r,
        return CONFIG_LINE_TYPE_SECTION_BEGIN;
 }
 
+static int config_parse_finish(struct parser_context *ctx, const char **error_r)
+{
+       struct config_filter_context *new_filter;
+       const char *error;
+
+       new_filter = config_filter_init(ctx->pool);
+       (void)array_append_space(&ctx->all_parsers);
+       config_filter_add_all(new_filter, array_idx(&ctx->all_parsers, 0));
+
+       if (config_all_parsers_check(ctx, new_filter, &error) < 0) {
+               *error_r = t_strdup_printf("Error in configuration file %s: %s",
+                                          ctx->path, error);
+               return -1;
+       }
+
+       if (config_filter != NULL)
+               config_filter_deinit(&config_filter);
+       config_module_parsers = ctx->root_parsers;
+       config_filter = new_filter;
+       return 0;
+}
+
 int config_parse_file(const char *path, bool expand_files,
                      const char **error_r)
 {
-       enum settings_parser_flags parser_flags =
-               SETTINGS_PARSER_FLAG_IGNORE_UNKNOWN_KEYS |
-               SETTINGS_PARSER_FLAG_TRACK_CHANGES;
        struct input_stack root;
        struct parser_context ctx;
        unsigned int pathlen = 0;
@@ -548,14 +548,12 @@ int config_parse_file(const char *path, bool expand_files,
                ctx.root_parsers[i].root = all_roots[i].root;
                ctx.root_parsers[i].parser =
                        settings_parser_init(ctx.pool, all_roots[i].root,
-                                            parser_flags);
+                                            settings_parser_flags);
        }
 
-       t_array_init(&ctx.cur_parsers, 128);
        p_array_init(&ctx.all_parsers, ctx.pool, 128);
-       ctx.cur_filter = p_new(ctx.pool, struct config_filter_stack, 1);
+       ctx.cur_section = p_new(ctx.pool, struct config_section_stack, 1);
        config_add_new_parser(&ctx);
-       config_update_cur_parsers(&ctx);
 
        memset(&root, 0, sizeof(root));
        root.path = path;
@@ -591,13 +589,12 @@ prevfile:
                        (void)config_apply_line(&ctx, key, str_c(str), NULL, &errormsg);
                        break;
                case CONFIG_LINE_TYPE_SECTION_BEGIN:
-                       config_add_new_filter(&ctx);
-                       ctx.cur_filter->pathlen = pathlen;
+                       ctx.cur_section = config_add_new_section(&ctx);
+                       ctx.cur_section->pathlen = pathlen;
 
-                       if (config_filter_add_new_parser(&ctx, key, value,
+                       if (config_filter_add_new_filter(&ctx, key, value,
                                                         &errormsg)) {
-                               /* new real filter */
-                               config_update_cur_parsers(&ctx);
+                               /* new filter */
                                break;
                        }
 
@@ -620,12 +617,11 @@ prevfile:
                        pathlen = str_len(str);
                        break;
                case CONFIG_LINE_TYPE_SECTION_END:
-                       if (ctx.cur_filter->prev == NULL)
+                       if (ctx.cur_section->prev == NULL)
                                errormsg = "Unexpected '}'";
                        else {
-                               pathlen = ctx.cur_filter->pathlen;
-                               ctx.cur_filter = ctx.cur_filter->prev;
-                               config_update_cur_parsers(&ctx);
+                               pathlen = ctx.cur_section->pathlen;
+                               ctx.cur_section = ctx.cur_section->prev;
                        }
                        break;
                case CONFIG_LINE_TYPE_INCLUDE:
@@ -652,21 +648,11 @@ prevfile:
        if (line == NULL && ctx.cur_input != NULL)
                goto prevfile;
 
-       if (ret == 0) {
-               if (config_all_parsers_check(&ctx, error_r) < 0)
-                       ret = -1;
-       }
+       if (ret == 0)
+               ret = config_parse_finish(&ctx, error_r);
        if (ret < 0) {
                pool_unref(&ctx.pool);
                return -1;
        }
-
-       if (config_filter != NULL)
-               config_filter_deinit(&config_filter);
-       config_module_parsers = ctx.root_parsers;
-
-       (void)array_append_space(&ctx.all_parsers);
-       config_filter = config_filter_init(ctx.pool);
-       config_filter_add_all(config_filter, array_idx(&ctx.all_parsers, 0));
        return 1;
 }
index b92ec5bc3d1bc9eeef97a775a3125f5f59123b26..6f82fbc860c2b498413503a4e93486cf7a41a3eb 100644 (file)
@@ -231,16 +231,26 @@ static void settings_export(struct settings_export_context *ctx,
        }
 }
 
-void config_request_handle(const struct config_filter *filter,
-                          const char *module, enum config_dump_scope scope,
-                          config_request_callback_t *callback, void *context)
+int config_request_handle(const struct config_filter *filter,
+                         const char *module, enum config_dump_scope scope,
+                         bool check_settings,
+                         config_request_callback_t *callback, void *context)
 {
        const struct config_module_parser *l;
-       const struct config_filter_parser_list *list;
        struct settings_export_context ctx;
+       const char *error;
+       int ret = 0;
 
        memset(&ctx, 0, sizeof(ctx));
        ctx.pool = pool_alloconly_create("config request", 10240);
+
+       if (config_filter_get_parsers(config_filter, ctx.pool, filter,
+                                     &l, &error) < 0) {
+               i_error("%s", error);
+               pool_unref(&ctx.pool);
+               return -1;
+       }
+
        ctx.callback = callback;
        ctx.context = context;
        ctx.scope = scope;
@@ -249,15 +259,24 @@ void config_request_handle(const struct config_filter *filter,
        ctx.keys = hash_table_create(default_pool, ctx.pool, 0,
                                     str_hash, (hash_cmp_callback_t *)strcmp);
 
-       list = config_filter_find(config_filter, filter);
-       for (l = list->parsers; l->module_name != NULL; l++) {
-               if (*module == '\0' ||
-                   config_module_parser_is_in_service(l, module)) {
-                       settings_export(&ctx, l->root,
-                                       settings_parser_get(l->parser),
-                                       settings_parser_get_changes(l->parser));
+       for (; l->module_name != NULL; l++) {
+               if (*module != '\0' &&
+                   !config_module_parser_is_in_service(l, module))
+                       continue;
+
+               settings_export(&ctx, l->root, settings_parser_get(l->parser),
+                               settings_parser_get_changes(l->parser));
+
+               if (check_settings) {
+                       if (!settings_parser_check(l->parser, ctx.pool,
+                                                  &error)) {
+                               i_error("%s", error);
+                               ret = -1;
+                               break;
+                       }
                }
        }
        hash_table_destroy(&ctx.keys);
        pool_unref(&ctx.pool);
+       return ret;
 }
index b2b4b854f750fd0940366bd0f94a7002ae7175ad..38a403b73b7577f3e20a547ebe79f1296e7aba3c 100644 (file)
@@ -15,8 +15,9 @@ enum config_dump_scope {
 typedef void config_request_callback_t(const char *key, const char *value,
                                       bool list, void *context);
 
-void config_request_handle(const struct config_filter *filter,
-                          const char *module, enum config_dump_scope scope,
-                          config_request_callback_t *callback, void *context);
+int config_request_handle(const struct config_filter *filter,
+                         const char *module, enum config_dump_scope scope,
+                         bool check_settings,
+                         config_request_callback_t *callback, void *context);
 
 #endif
index c3a0572d5998c8727f810ab530a194c624cd8bea..f3804bfd540559d81a9756c5414ce2fb80f6e8b6 100644 (file)
@@ -77,8 +77,9 @@ static void config_connection_request_human(struct ostream *output,
 
        ctx.pool = pool_alloconly_create("config human strings", 10240);
        i_array_init(&ctx.strings, 256);
-       config_request_handle(filter, module, scope,
-                             config_request_get_strings, &ctx);
+       if (config_request_handle(filter, module, scope, TRUE,
+                                 config_request_get_strings, &ctx) < 0)
+               return;
 
        array_sort(&ctx.strings, config_string_cmp);
        strings = array_get(&ctx.strings, &count);
@@ -200,6 +201,23 @@ static const char *get_mail_location(void)
        return "";
 }
 
+static void filter_parse_arg(struct config_filter *filter, const char *arg)
+{
+       if (strncmp(arg, "service=", 8) == 0)
+               filter->service = arg + 8;
+       else if (strncmp(arg, "lip=", 4) == 0) {
+               if (net_parse_range(arg + 4, &filter->local_net,
+                                   &filter->local_bits) < 0)
+                       i_fatal("lip: Invalid network mask");
+       } else if (strncmp(arg, "rip=", 4) == 0) {
+               if (net_parse_range(arg + 4, &filter->remote_net,
+                                   &filter->remote_bits) < 0)
+                       i_fatal("rip: Invalid network mask");
+       } else {
+               i_fatal("Unknown filter argument: %s", arg);
+       }
+}
+
 int main(int argc, char *argv[])
 {
        enum config_dump_scope scope = CONFIG_DUMP_SCOPE_ALL;
@@ -214,7 +232,7 @@ int main(int argc, char *argv[])
                                             MASTER_SERVICE_FLAG_STANDALONE,
                                             argc, argv);
        i_set_failure_prefix("doveconf: ");
-       getopt_str = t_strconcat("am:nNp:e",
+       getopt_str = t_strconcat("af:m:nN:e",
                                 master_service_getopt_string(), NULL);
        while ((c = getopt(argc, argv, getopt_str)) > 0) {
                if (c == 'e')
@@ -222,6 +240,9 @@ int main(int argc, char *argv[])
                switch (c) {
                case 'a':
                        break;
+               case 'f':
+                       filter_parse_arg(&filter, optarg);
+                       break;
                case 'm':
                        module = optarg;
                        break;
@@ -231,9 +252,6 @@ int main(int argc, char *argv[])
                case 'N':
                        scope = CONFIG_DUMP_SCOPE_SET;
                        break;
-               case 'p':
-                       filter.service = optarg;
-                       break;
                default:
                        if (!master_service_parse_option(master_service,
                                                         c, optarg))
@@ -242,9 +260,11 @@ int main(int argc, char *argv[])
        }
        config_path = master_service_get_config_path(master_service);
 
-       if (argv[optind] != NULL)
+       if (argv[optind] != NULL) {
+               if (c != 'e')
+                       i_fatal("Unknown argument: %s", argv[optind]);
                exec_args = &argv[optind];
-       else {
+       else {
                /* print the config file path before parsing it, so in case
                   of errors it's still shown */
                printf("# "VERSION": %s\n", config_path);
@@ -268,8 +288,10 @@ int main(int argc, char *argv[])
                config_dump_human(&filter, module, scope);
        } else {
                env_put("DOVECONF_ENV=1");
-               config_request_handle(&filter, module, 0,
-                                     config_request_putenv, NULL);
+               if (config_request_handle(&filter, module,
+                                         CONFIG_DUMP_SCOPE_SET, TRUE,
+                                         config_request_putenv, NULL) < 0)
+                       i_fatal("Invalid configuration");
                execvp(exec_args[0], exec_args);
                i_fatal("execvp(%s) failed: %m", exec_args[0]);
        }