From: Timo Sirainen Date: Thu, 7 Nov 2024 16:48:03 +0000 (+0200) Subject: config: doveconf - Add -f filter parameters X-Git-Tag: 2.4.0~236 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=86f8afdc2a42441ee24f4d297397e3a7403bb49f;p=thirdparty%2Fdovecot%2Fcore.git config: doveconf - Add -f filter parameters --- diff --git a/src/config/config-connection.c b/src/config/config-connection.c index 2f4a1f2a47..d9e0a13207 100644 --- a/src/config/config-connection.c +++ b/src/config/config-connection.c @@ -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); diff --git a/src/config/config-filter.h b/src/config/config-filter.h index 5c75d7b873..8b9b7dad94 100644 --- a/src/config/config-filter.h +++ b/src/config/config-filter.h @@ -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. */ diff --git a/src/config/config-parser.c b/src/config/config-parser.c index 3b71b0e64c..20640afbb9 100644 --- a/src/config/config-parser.c +++ b/src/config/config-parser.c @@ -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) { diff --git a/src/config/config-parser.h b/src/config/config-parser.h index fd35d89205..673fb2c4d7 100644 --- a/src/config/config-parser.h +++ b/src/config/config-parser.h @@ -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); diff --git a/src/config/doveconf.c b/src/config/doveconf.c index 14375367c6..f63706cded 100644 --- a/src/config/doveconf.c +++ b/src/config/doveconf.c @@ -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) { diff --git a/src/config/test-config-parser.c b/src/config/test-config-parser.c index 78000655f4..acfd49c7e1 100644 --- a/src/config/test-config-parser.c +++ b/src/config/test-config-parser.c @@ -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);