unsigned int i, count = str_array_length(list);
if (!array_is_created(arr))
p_array_init(arr, ctx->set_pool, count);
+ unsigned int insert_pos = 0;
for (i = 0; i < count; i++) {
const char *value = p_strdup(ctx->set_pool,
settings_section_unescape(list[i]));
- array_push_back(arr, &value);
+ if ((ctx->flags & SETTINGS_PARSER_FLAG_INSERT_FILTERS) != 0)
+ array_insert(arr, insert_pos++, &value, 1);
+ else
+ array_push_back(arr, &value);
}
break;
}
key, value, FALSE);
}
+bool settings_parse_strlist_has_key(struct setting_parser_context *ctx,
+ unsigned int key_idx,
+ const char *key_suffix)
+{
+ const struct setting_define *def = &ctx->info->defines[key_idx];
+ i_assert(def->type == SET_STRLIST);
+
+ ARRAY_TYPE(const_string) *array =
+ STRUCT_MEMBER_P(ctx->set_struct, def->offset);
+ if (!array_is_created(array))
+ return FALSE;
+
+ unsigned int i, count;
+ const char *const *items = array_get(array, &count);
+ for (i = 0; i < count; i += 2) {
+ if (strcmp(items[i], key_suffix) == 0)
+ return TRUE;
+ }
+ return FALSE;
+}
+
const void *
settings_parse_get_value(struct setting_parser_context *ctx,
const char **key, enum setting_type *type_r)
struct setting_parser_context *parser;
struct settings_mmap_pool *mpool;
void *set_struct;
+ ARRAY_TYPE(bool) set_seen;
};
static const char *settings_override_type_names[] = {
unsigned int key_idx;
for (key_idx = 0; ctx->info->defines[key_idx].key != NULL; key_idx++) {
+ bool *setp = array_idx_get_space(&ctx->set_seen, key_idx);
+ if (*setp)
+ continue;
+
void *set = PTR_OFFSET(ctx->info->defaults,
ctx->info->defines[key_idx].offset);
if (ctx->info->defines[key_idx].type != SET_STR_VARS)
}
offset += sizeof(key_idx);
+ bool set_apply;
const char *strlist_key = NULL;
if (ctx->info->defines[key_idx].type == SET_STRLIST) {
strlist_key = (const char *)mmap->mmap_base + offset;
offset += strlen(strlist_key)+1;
+ set_apply = !settings_parse_strlist_has_key(ctx->parser,
+ key_idx, strlist_key);
+ } else if (ctx->info->defines[key_idx].type == SET_FILTER_ARRAY)
+ set_apply = TRUE;
+ else {
+ bool *setp = array_idx_get_space(&ctx->set_seen, key_idx);
+ if (*setp)
+ set_apply = FALSE;
+ else {
+ *setp = TRUE;
+ set_apply = TRUE;
+ }
}
if (offset >= end_offset) {
return -1;
}
int ret;
- T_BEGIN {
+ if (!set_apply)
+ ret = 0;
+ else T_BEGIN {
ret = settings_mmap_apply_key(ctx, key_idx, strlist_key,
value, error_r);
} T_END_PASS_STR_IF(ret < 0, error_r);
block->settings_validated = TRUE;
}
- if (settings_mmap_apply_blob(ctx, block, block->base_start_offset,
- block->base_end_offset, error_r) < 0)
- return -1;
-
const struct failure_context failure_ctx = {
.type = LOG_TYPE_DEBUG,
};
+ /* go through the filters in reverse sorted order, so we always set the
+ setting just once, never overriding anything. */
bool seen_filter = FALSE;
- for (uint32_t i = 0; i < block->filter_count; i++) {
+ for (uint32_t i = block->filter_count; i > 0; ) {
+ i--;
uint32_t event_filter_idx = be32_to_cpu_unaligned(
CONST_PTR_OFFSET(mmap->mmap_base,
block->filter_indexes_start_offset +
return -1;
}
}
+ /* apply the base settings last after all filters */
+ if (settings_mmap_apply_blob(ctx, block, block->base_start_offset,
+ block->base_end_offset, error_r) < 0)
+ return -1;
return seen_filter ? 1 : 0;
}
static int settings_override_cmp(const struct settings_override *set1,
const struct settings_override *set2)
{
- return set1->type - set2->type;
+ return set2->type - set1->type;
}
static int
array_append_array(&overrides, &ctx->instance->overrides);
if (array_is_created(&ctx->root->overrides))
array_append_array(&overrides, &ctx->root->overrides);
+ /* sort overrides so that the most specific ones are first */
array_sort(&overrides, settings_override_cmp);
const struct failure_context failure_ctx = {
/* setting doesn't exist in this info */
continue;
}
+ if (ctx->info->defines[key_idx].type == SET_STRLIST) {
+ const char *suffix;
+ if (!str_begins(key, ctx->info->defines[key_idx].key, &suffix) ||
+ suffix[0] != '/')
+ i_unreached();
+ if (settings_parse_strlist_has_key(ctx->parser, key_idx,
+ suffix + 1))
+ continue;
+ } else if (ctx->info->defines[key_idx].type != SET_FILTER_ARRAY) {
+ bool *setp = array_idx_get_space(&ctx->set_seen, key_idx);
+ if (*setp) {
+ /* already set - skip */
+ continue;
+ }
+ *setp = TRUE;
+ }
if (value != set->value)
value = p_strdup(&ctx->mpool->pool, value);
source_filename, source_linenum);
pool_t set_pool = &ctx->mpool->pool;
ctx->parser = settings_parser_init(set_pool, ctx->info,
- SETTINGS_PARSER_FLAG_IGNORE_UNKNOWN_KEYS);
+ SETTINGS_PARSER_FLAG_IGNORE_UNKNOWN_KEYS |
+ SETTINGS_PARSER_FLAG_INSERT_FILTERS);
/* Set the pool early on before any callbacks are called. */
ctx->set_struct = settings_parser_get_set(ctx->parser);
ctx->info->pool_offset1 - 1);
*pool_p = set_pool;
- settings_mmap_apply_defaults(ctx);
- if (ctx->instance->mmap != NULL) {
+ i_array_init(&ctx->set_seen, 64);
+
+ settings_parse_set_expanded(ctx->parser, TRUE);
+ ret = settings_instance_override(ctx, error_r);
+ settings_parse_set_expanded(ctx->parser, FALSE);
+ if (ret > 0)
+ seen_filter = TRUE;
+
+ if (ctx->instance->mmap != NULL && ret >= 0) {
ret = settings_mmap_apply(ctx, &error);
if (ret < 0) {
*error_r = t_strdup_printf(
"Failed to parse configuration: %s", error);
- pool_unref(&set_pool);
- return -1;
}
if (ret > 0)
seen_filter = TRUE;
}
-
- /* if we change any settings afterwards, they're in expanded form.
- especially all settings from userdb are already expanded. */
- settings_parse_set_expanded(ctx->parser, TRUE);
-
- ret = settings_instance_override(ctx, error_r);
+ if (ret >= 0)
+ settings_mmap_apply_defaults(ctx);
if (ret < 0) {
pool_unref(&set_pool);
return -1;
}
- if (ret > 0)
- seen_filter = TRUE;
if (ctx->filter_key != NULL && !seen_filter &&
ctx->filter_name_required) {
} T_END_PASS_STR_IF(ret < 0, error_r);
settings_parser_unref(&ctx.parser);
event_unref(&ctx.event);
+ array_free(&ctx.set_seen);
return ret;
}