}
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);
/* 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];
}
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));
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);
}
if (expand) {
config_filters_merge(ctx, config, filter,
- include_filter);
+ include_filter,
+ FALSE, FALSE);
}
}
if (expand)
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)
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
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;
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) {
}
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)
{
}
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) {
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) {
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;
}
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: ");
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;
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) {