]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
config: doveconf - Add -f filter parameters
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Thu, 7 Nov 2024 16:48:03 +0000 (18:48 +0200)
committerAki Tuomi <aki.tuomi@open-xchange.com>
Fri, 17 Jan 2025 08:40:01 +0000 (10:40 +0200)
src/config/config-connection.c
src/config/config-filter.h
src/config/config-parser.c
src/config/config-parser.h
src/config/doveconf.c
src/config/test-config-parser.c

index 2f4a1f2a47e2622f936848d94f3684452d342a45..d9e0a1320708f235e8f480cf9ddf66fe45d65366 100644 (file)
@@ -58,7 +58,7 @@ static int config_global_reload(const char **error_r)
        path = master_service_get_config_path(master_service);
        if (config_parse_file(path, CONFIG_PARSE_FLAG_EXPAND_VALUES |
                              CONFIG_PARSE_FLAG_EXTERNAL_HOOKS,
-                             &new_config, error_r) <= 0)
+                             NULL, &new_config, error_r) <= 0)
                return -1;
 
        config_parsed_free(&global_config);
index 5c75d7b8735fb8a93ede511e60444d88dfb0d4e3..8b9b7dad943f89fcc15aaf1a8da4119c13302c03 100644 (file)
@@ -57,6 +57,10 @@ struct config_filter_parser {
           boolean tracks whether that setting has been changed in this
           filter. */
        bool filter_required_setting_seen;
+       /* TRUE if this filter shouldn't be included in the config output.
+          This is used by doveconf -f filter handling to drop filters that
+          were merged to parents. */
+       bool dropped;
 };
 
 /* Returns TRUE if filter matches mask. The parents must also match. */
index 3b71b0e64c8eff953b526c7a2e53c2f3be8afbd3..20640afbb98bf5fe587900f5ed50254ca28fa007 100644 (file)
@@ -1898,7 +1898,8 @@ group_find_name(struct config_include_group_filters *group, const char *name)
 }
 
 static void config_module_parsers_merge(struct config_module_parser *dest,
-                                       const struct config_module_parser *src)
+                                       const struct config_module_parser *src,
+                                       bool overwrite)
 {
        for (; dest->info != NULL; dest++, src++) {
                i_assert(dest->info == src->info);
@@ -1926,7 +1927,7 @@ static void config_module_parsers_merge(struct config_module_parser *dest,
                /* copy settings that have changed in source, but not in dest */
                for (unsigned int i = 0; i < src->set_count; i++) {
                        if (src->change_counters[i] != 0 &&
-                           dest->change_counters[i] == 0) {
+                           (dest->change_counters[i] == 0 || overwrite)) {
                                dest->settings[i] = src->settings[i];
                                dest->change_counters[i] = src->change_counters[i];
                        }
@@ -1951,9 +1952,10 @@ config_filters_find_child(struct config_filter_parser *parent,
 static void
 config_filters_merge_tree(struct config_parser_context *ctx,
                          struct config_filter_parser *dest_parent,
-                         const struct config_filter_parser *src_parent)
+                         struct config_filter_parser *src_parent,
+                         bool drop_merged, bool overwrite)
 {
-       const struct config_filter_parser *src;
+       struct config_filter_parser *src;
        struct config_filter_parser *dest;
 
        i_assert(array_is_empty(&src_parent->include_groups));
@@ -1963,22 +1965,29 @@ config_filters_merge_tree(struct config_parser_context *ctx,
                        dest = config_add_new_parser(ctx, &src->filter,
                                                     dest_parent);
                }
+               if (drop_merged)
+                       src->dropped = TRUE;
                config_module_parsers_merge(dest->module_parsers,
-                                           src->module_parsers);
-               config_filters_merge_tree(ctx, dest, src);
+                                           src->module_parsers, overwrite);
+               config_filters_merge_tree(ctx, dest, src,
+                                         drop_merged, overwrite);
        }
 }
 
 static void config_filters_merge(struct config_parser_context *ctx,
                                 struct config_parsed *config,
                                 struct config_filter_parser *dest_filter,
-                                const struct config_filter_parser *src_filter)
+                                struct config_filter_parser *src_filter,
+                                bool drop_merged, bool overwrite)
 {
        i_assert(array_is_empty(&src_filter->include_groups));
 
+       if (drop_merged)
+               src_filter->dropped = TRUE;
        config_module_parsers_merge(dest_filter->module_parsers,
-                                   src_filter->module_parsers);
-       config_filters_merge_tree(ctx, dest_filter, src_filter);
+                                   src_filter->module_parsers, overwrite);
+       config_filters_merge_tree(ctx, dest_filter, src_filter,
+                                 drop_merged, overwrite);
 
        array_append_zero(&ctx->all_filter_parsers);
        array_pop_back(&ctx->all_filter_parsers);
@@ -2056,7 +2065,8 @@ config_parse_finish_includes(struct config_parser_context *ctx,
                        }
                        if (expand) {
                                config_filters_merge(ctx, config, filter,
-                                                    include_filter);
+                                                    include_filter,
+                                                    FALSE, FALSE);
                        }
                }
                if (expand)
@@ -2065,6 +2075,31 @@ config_parse_finish_includes(struct config_parser_context *ctx,
        return 0;
 }
 
+static void
+config_parse_merge_filters(struct config_parser_context *ctx,
+                          struct config_parsed *config,
+                          const struct config_filter *dump_filter)
+{
+       for (unsigned int i = 2; config->filter_parsers[i] != NULL; i++) {
+               struct config_filter_parser *filter = config->filter_parsers[i];
+
+               int ret = config_filter_match_no_recurse(&filter->filter,
+                                                        dump_filter);
+               if (ret < 0 || filter->filter.filter_name != NULL) {
+                       /* Incomplete filter */
+                       continue;
+               }
+               if (ret == 0) {
+                       /* Filter mismatch */
+                       filter->dropped = TRUE;
+                       continue;
+               }
+
+               config_filters_merge(ctx, config, filter->parent, filter,
+                                    TRUE, TRUE);
+       }
+}
+
 static void
 config_parse_merge_default_filters(struct config_parser_context *ctx,
                                   struct config_parsed *config)
@@ -2075,7 +2110,8 @@ config_parse_merge_default_filters(struct config_parser_context *ctx,
        defaults_parser = array_idx_elem(&ctx->all_filter_parsers, 1);
        i_assert(config_filter_is_empty_defaults(&defaults_parser->filter));
 
-       config_filters_merge(ctx, config, root_parser, defaults_parser);
+       config_filters_merge(ctx, config, root_parser, defaults_parser,
+                            FALSE, FALSE);
 }
 
 static void
@@ -2131,6 +2167,7 @@ config_parse_finish_service_defaults(struct config_parser_context *ctx)
 static int
 config_parse_finish(struct config_parser_context *ctx,
                    enum config_parse_flags flags,
+                   const struct config_filter *dump_filter,
                    struct config_parsed **config_r, const char **error_r)
 {
        struct config_parsed *new_config;
@@ -2160,6 +2197,9 @@ config_parse_finish(struct config_parser_context *ctx,
                        error_r);
        }
 
+       if (ret == 0 && dump_filter != NULL)
+               config_parse_merge_filters(ctx, new_config, dump_filter);
+
        if (ret < 0)
                ;
        else if ((ret = config_all_parsers_check(ctx, new_config, &error)) < 0) {
@@ -2647,6 +2687,7 @@ config_parser_get_filter_name_prefixes(struct config_parser_context *ctx)
 }
 
 int config_parse_file(const char *path, enum config_parse_flags flags,
+                     const struct config_filter *dump_filter,
                      struct config_parsed **config_r,
                      const char **error_r)
 {
@@ -2811,8 +2852,10 @@ prevfile:
        }
 
        old_settings_handle_post(&ctx);
-       if (ret == 0)
-               ret = config_parse_finish(&ctx, flags, config_r, error_r);
+       if (ret == 0) {
+               ret = config_parse_finish(&ctx, flags, dump_filter,
+                                         config_r, error_r);
+       }
 
        if (ret == 0 && !dump_defaults &&
            (flags & CONFIG_PARSE_FLAG_NO_DEFAULTS) == 0) {
index fd35d892052acc76992411aadae64db57d0142fc..673fb2c4d7d0ef5f37b6d88e3af5486710b2c41a 100644 (file)
@@ -74,6 +74,7 @@ int config_filter_parse(struct config_filter *filter, pool_t pool,
                        const char *key, const char *value,
                        const char **error_r);
 int config_parse_file(const char *path, enum config_parse_flags flags,
+                     const struct config_filter *dump_filter,
                      struct config_parsed **config_r,
                      const char **error_r)
        ATTR_NULL(3);
index 14375367c69e8f24adb42fe7522b9baea6175ebf..f63706cdedea189d1fff2f44e65f5c423f965361 100644 (file)
@@ -724,6 +724,9 @@ config_dump_human_filter_path(enum config_dump_scope scope,
                const char *suffix, *set_name_filter = NULL;
                const char *const *sub_filter_path = set_filter_path;
 
+               if (filter_parser->dropped)
+                       continue;
+
                if (set_filter_path[0] == NULL) {
                        /* show everything */
                } else if (filter_parser->filter.filter_name == NULL) {
@@ -1022,7 +1025,9 @@ int main(int argc, char *argv[])
        char **exec_args = NULL, **setting_name_filters = NULL;
        unsigned int i;
        int c, ret, ret2;
-       bool config_path_specified, hide_key = FALSE;
+       struct config_filter dump_filter_parent = {};
+       struct config_filter dump_filter = { .parent = &dump_filter_parent };
+       bool config_path_specified, hide_key = FALSE, have_dump_filter = FALSE;
        bool simple_output = FALSE, check_full_config = FALSE;
        bool dump_defaults = FALSE, host_verify = FALSE, dump_full = FALSE;
        bool print_banners = FALSE, hide_passwords = TRUE;
@@ -1035,7 +1040,7 @@ int main(int argc, char *argv[])
        }
 
        master_service = master_service_init("config", master_service_flags,
-                                            &argc, &argv, "aCdFhHI:nNPwxs");
+                                            &argc, &argv, "aCdf:FhHI:nNPwxs");
        orig_config_path = t_strdup(master_service_get_config_path(master_service));
 
        i_set_failure_prefix("doveconf: ");
@@ -1052,6 +1057,20 @@ int main(int argc, char *argv[])
                        dump_defaults = TRUE;
                        flags |= CONFIG_PARSE_FLAG_MERGE_DEFAULT_FILTERS;
                        break;
+               case 'f': {
+                       const char *key, *value;
+                       if (!t_split_key_value_eq(optarg, &key, &value))
+                               i_fatal("-f parameters must be in key=value format");
+                       ret = config_filter_parse(&dump_filter,
+                                                 pool_datastack_create(),
+                                                 key, value, &error);
+                       if (ret < 0)
+                               i_fatal("-f %s=%s: %s", key, value, error);
+                       if (ret == 0)
+                               i_fatal("-f %s: Unknown filter key", key);
+                       have_dump_filter = TRUE;
+                       break;
+               }
                case 'F':
                        dump_full = TRUE;
                        simple_output = TRUE;
@@ -1154,7 +1173,8 @@ int main(int argc, char *argv[])
                flags |= CONFIG_PARSE_FLAG_EXTERNAL_HOOKS;
        T_BEGIN {
                ret = config_parse_file(dump_defaults ? NULL : config_path,
-                                       flags, &config, &error);
+                       flags, have_dump_filter ? &dump_filter : NULL,
+                       &config, &error);
        } T_END_PASS_STR_IF(ret <= 0, &error);
        if (ret == 0 &&
            access(EXAMPLE_CONFIG_DIR, X_OK) == 0) {
index 78000655f4ab749674bafe131b91c5eec4de1ac7..acfd49c7e1c1bfaa81860daca3b1e4cc00b3ea5f 100644 (file)
@@ -120,7 +120,7 @@ static void test_config_parser(void)
        test_assert(config_parse_file(TEST_CONFIG_FILE,
                                      CONFIG_PARSE_FLAG_EXPAND_VALUES |
                                      CONFIG_PARSE_FLAG_NO_DEFAULTS,
-                                     &config, &error) == 1);
+                                     NULL, &config, &error) == 1);
        if (error != NULL)
                i_error("config_parse_file(): %s", error);
 
@@ -151,7 +151,7 @@ static void test_config_parser(void)
        /* try again unexpanded */
        test_assert(config_parse_file(TEST_CONFIG_FILE,
                                      CONFIG_PARSE_FLAG_NO_DEFAULTS,
-                                     &config, &error) == 1);
+                                     NULL, &config, &error) == 1);
 
        p_clear(pool);
        global_filter = config_parsed_get_global_filter_parser(config);