]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
master, config: Add default_* service settings
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Mon, 4 Nov 2024 10:45:38 +0000 (12:45 +0200)
committerAki Tuomi <aki.tuomi@open-xchange.com>
Fri, 17 Jan 2025 08:40:00 +0000 (10:40 +0200)
Added default_process_limit, default_client_limit,
default_idle_kill_interval and default_vsz_limit settings. The global
service_* settings default to using these.

These settings are added into a new global "default settings" filter.
Other default settings are kept mixed with explicit settings, because
for them it doesn't matter that they are mixed, and it simplifies
settings value lookups.

src/config/config-dump-full.c
src/config/config-filter.c
src/config/config-filter.h
src/config/config-parser.c
src/master/master-settings.c
src/master/master-settings.h

index b6c9fdba1384e83419832cc888a9d1caf7cd037a..b535196fa624295e8b3931648ceb228414068b1b 100644 (file)
@@ -242,9 +242,9 @@ static void config_dump_full_stdout_write_filter(struct dump_context *ctx)
        ctx->filter_written = TRUE;
 
        string_t *str = t_str_new(128);
-       str_append(str, ":FILTER ");
        if (ctx->filter != NULL)
                config_dump_full_append_filter(str, ctx->filter, TRUE);
+       str_insert(str, 0, ":FILTER ");
        str_append_c(str, '\n');
 
        if (ctx->include_groups != NULL) {
index 924b4f0c04394c3eb8e21a294e4fb5ed03d0e3ba..0743577396fae080dd0cf6ec9497c26f59245a0a 100644 (file)
@@ -9,6 +9,9 @@
 #include "dns-util.h"
 
 static const struct config_filter empty_filter;
+static const struct config_filter empty_defaults_filter = {
+       .default_settings = TRUE
+};
 
 static bool config_filter_match_service(const struct config_filter *mask,
                                        const struct config_filter *filter)
@@ -142,3 +145,8 @@ bool config_filter_is_empty(const struct config_filter *filter)
 {
        return config_filters_equal(filter, &empty_filter);
 }
+
+bool config_filter_is_empty_defaults(const struct config_filter *filter)
+{
+       return config_filters_equal(filter, &empty_defaults_filter);
+}
index 65b5c6b469a8fc2170441dcefb5ff78afbfca24b..f35ecc795188064c2f5137a6def5e0af8f5fdd65 100644 (file)
@@ -62,7 +62,11 @@ bool config_filter_match(const struct config_filter *mask,
 /* Returns TRUE if two filters are fully equal. */
 bool config_filters_equal(const struct config_filter *f1,
                          const struct config_filter *f2);
-/* Returns TRUE if filter is empty, and it has no parent filters. */
+/* Returns TRUE if filter is empty, and it has no parent filters, and it has
+   default_settings=FALSE. */
 bool config_filter_is_empty(const struct config_filter *filter);
+/* Returns TRUE if filter is empty, and it has no parent filters, and it has
+   default_settings=TRUE. */
+bool config_filter_is_empty_defaults(const struct config_filter *filter);
 
 #endif
index 29f1a6169b1e14d04f79e4b5b9a5fedf422b5e4a..5576b9b40ba95ef266b369cb58c6c3be82da1655 100644 (file)
@@ -81,6 +81,9 @@ static struct config_filter_parser *
 config_add_new_parser(struct config_parser_context *ctx,
                      const struct config_filter *filter,
                      struct config_filter_parser *parent_filter_parser);
+static int config_write_keyvariable(struct config_parser_context *ctx,
+                                   const char *key, const char *value,
+                                   string_t *str);
 static int
 config_apply_exact_line(struct config_parser_context *ctx,
                        const struct config_line *line,
@@ -993,7 +996,8 @@ config_add_new_parser(struct config_parser_context *ctx,
 
        filter_parser = p_new(ctx->pool, struct config_filter_parser, 1);
        filter_parser->filter = *filter;
-       filter_parser->module_parsers = parent_filter_parser == NULL ?
+       filter_parser->module_parsers =
+               parent_filter_parser == NULL && !filter->default_settings ?
                ctx->root_module_parsers :
                config_module_parsers_init(ctx->pool);
        array_push_back(&ctx->all_filter_parsers, &filter_parser);
@@ -1098,7 +1102,8 @@ config_filter_add_new_filter(struct config_parser_context *ctx,
        filter.parent = parent;
 
        if (key[0] == SETTINGS_INCLUDE_GROUP_PREFIX) {
-               if (!config_filter_is_empty(parent)) {
+               if (!config_filter_is_empty(parent) &&
+                   !config_filter_is_empty_defaults(parent)) {
                        ctx->error = "groups must defined at top-level, not under filters";
                        return TRUE;
                }
@@ -1858,6 +1863,56 @@ static void config_parse_finish_includes(struct config_parsed *config)
        }
 }
 
+static void
+config_parse_finish_service_defaults(struct config_parser_context *ctx)
+{
+       const char *const service_defaults[] = {
+               "service_process_limit", "$SET:default_process_limit",
+               "service_client_limit", "$SET:default_client_limit",
+               "service_idle_kill_interval", "$SET:default_idle_kill_interval",
+               "service_vsz_limit", "$SET:default_vsz_limit",
+       };
+       struct config_filter_parser *root_parser, *defaults_parser;
+
+       root_parser = array_idx_elem(&ctx->all_filter_parsers, 0);
+       defaults_parser = array_idx_elem(&ctx->all_filter_parsers, 1);
+       i_assert(config_filter_is_empty_defaults(&defaults_parser->filter));
+
+       /* Add the service_* settings into global defaults filter, so they
+          are used only if not overridden by default service filters. */
+       string_t *value = t_str_new(64);
+       config_parser_set_change_counter(ctx, CONFIG_PARSER_CHANGE_DEFAULTS);
+       for (unsigned int i = 0; i < N_ELEMENTS(service_defaults); i += 2) {
+               struct config_parser_key *config_key =
+                       hash_table_lookup(ctx->all_keys, service_defaults[i]);
+               struct config_module_parser *module_parser =
+                       &ctx->cur_section->filter_parser->module_parsers[config_key->info_idx];
+               if (module_parser->change_counters == NULL ||
+                   module_parser->change_counters[config_key->define_idx] == 0) {
+                       bool orig_expand_values = ctx->expand_values;
+                       str_truncate(value, 0);
+                       ctx->cur_section->filter_parser = root_parser;
+                       ctx->expand_values = TRUE;
+                       if (config_write_keyvariable(ctx, service_defaults[i],
+                                                    service_defaults[i + 1],
+                                                    value) < 0) {
+                               i_panic("Failed to expand %s=%s: %s",
+                                       service_defaults[i],
+                                       service_defaults[i + 1], ctx->error);
+                       }
+                       ctx->cur_section->filter_parser = defaults_parser;
+                       if (config_apply_line(ctx, service_defaults[i],
+                                             str_c(value), NULL) < 0) {
+                               i_panic("Failed to set default %s=%s: %s",
+                                       service_defaults[i],
+                                       service_defaults[i + 1], ctx->error);
+                       }
+                       ctx->expand_values = orig_expand_values;
+               }
+       }
+       config_parser_set_change_counter(ctx, CONFIG_PARSER_CHANGE_EXPLICIT);
+}
+
 static int
 config_parse_finish(struct config_parser_context *ctx,
                    enum config_parse_flags flags,
@@ -1867,6 +1922,8 @@ config_parse_finish(struct config_parser_context *ctx,
        const char *error;
        int ret = 0;
 
+       if ((flags & CONFIG_PARSE_FLAG_NO_DEFAULTS) == 0)
+               config_parse_finish_service_defaults(ctx);
        if (hook_config_parser_end != NULL &&
            (flags & CONFIG_PARSE_FLAG_EXTERNAL_HOOKS) != 0)
                ret = hook_config_parser_end(ctx, error_r);
@@ -2389,7 +2446,7 @@ int config_parse_file(const char *path, enum config_parse_flags flags,
        hash_table_create(&ctx.all_keys, ctx.pool, 500, str_hash, strcmp);
 
        for (count = 0; all_infos[count] != NULL; count++) ;
-       ctx.change_counter = CONFIG_PARSER_CHANGE_EXPLICIT;
+       config_parser_set_change_counter(&ctx, CONFIG_PARSER_CHANGE_DEFAULTS);
        ctx.root_module_parsers =
                p_new(ctx.pool, struct config_module_parser, count+1);
        unsigned int service_info_idx = UINT_MAX;
@@ -2422,9 +2479,18 @@ int config_parse_file(const char *path, enum config_parse_flags flags,
 
        p_array_init(&ctx.all_filter_parsers, ctx.pool, 128);
        ctx.cur_section = p_new(ctx.pool, struct config_section_stack, 1);
+       /* Global settings filter must be the first. */
        struct config_filter root_filter = { };
-       ctx.cur_section->filter_parser =
+       struct config_filter_parser *root_filter_parser =
                config_add_new_parser(&ctx, &root_filter, NULL);
+       /* Default global settings filter must be the second. This is important
+          so it will be in the correct position when dumping the config. Add
+          all default settings into this filter. */
+       struct config_filter root_default_filter = {
+               .default_settings = TRUE,
+       };
+       ctx.cur_section->filter_parser =
+               config_add_new_parser(&ctx, &root_default_filter, NULL);
 
        ctx.value = str_new(ctx.pool, 256);
        full_line = str_new(default_pool, 512);
@@ -2443,6 +2509,8 @@ int config_parse_file(const char *path, enum config_parse_flags flags,
                hook_config_parser_begin(&ctx);
        } T_END;
 
+       ctx.cur_section->filter_parser = root_filter_parser;
+       config_parser_set_change_counter(&ctx, CONFIG_PARSER_CHANGE_EXPLICIT);
 prevfile:
        while ((line = i_stream_read_next_line(ctx.cur_input->input)) != NULL) {
                struct config_line config_line;
@@ -2488,11 +2556,12 @@ prevfile:
        }
 
        old_settings_handle_post(&ctx);
+       if (ret == 0)
+               ret = config_parse_finish(&ctx, flags, config_r, error_r);
+
        hash_table_destroy(&ctx.seen_settings);
        hash_table_destroy(&ctx.all_keys);
        str_free(&full_line);
-       if (ret == 0)
-               ret = config_parse_finish(&ctx, flags, config_r, error_r);
        pool_unref(&ctx.pool);
        return ret < 0 ? ret : 1;
 }
index b6b39b64af96d59a6156238e3c24aef3e70bbb83..4b8cd6bbf8756aea7ed09d1eb51d74571d0bc1d1 100644 (file)
@@ -160,11 +160,11 @@ static const struct service_settings service_default_settings = {
        .drop_priv_before_exec = FALSE,
 
        .process_min_avail = 0,
-       .process_limit = 100,
-       .client_limit = 1000,
+       .process_limit = 0,
+       .client_limit = 0,
        .restart_request_count = SET_UINT_UNLIMITED,
-       .idle_kill_interval = 60,
-       .vsz_limit = 256*1024*1024,
+       .idle_kill_interval = 0,
+       .vsz_limit = 0,
 
        .unix_listeners = ARRAY_INIT,
        .fifo_listeners = ARRAY_INIT,
@@ -196,6 +196,10 @@ static const struct setting_define master_setting_defines[] = {
        DEF(STR, default_internal_user),
        DEF(STR, default_internal_group),
        DEF(STR, default_login_user),
+       DEF(UINT, default_process_limit),
+       DEF(UINT, default_client_limit),
+       DEF(TIME, default_idle_kill_interval),
+       DEF(SIZE, default_vsz_limit),
 
        DEF(BOOL, version_ignore),
 
@@ -220,6 +224,10 @@ static const struct master_settings master_default_settings = {
        .default_internal_user = "dovecot",
        .default_internal_group = "dovecot",
        .default_login_user = "dovenull",
+       .default_process_limit = 100,
+       .default_client_limit = 1000,
+       .default_idle_kill_interval = 60,
+       .default_vsz_limit = 256*1024*1024,
 
        .version_ignore = FALSE,
 
index a76c1db6eef9816d8372ad964112fd182d989981..10c9bd2bb93792dfa13eb5053a35a6511d54cf5c 100644 (file)
@@ -15,6 +15,10 @@ struct master_settings {
        const char *default_internal_user;
        const char *default_internal_group;
        const char *default_login_user;
+       unsigned int default_process_limit;
+       unsigned int default_client_limit;
+       unsigned int default_idle_kill_interval;
+       uoff_t default_vsz_limit;
 
        bool version_ignore;