# HG changeset patch # User Timo Sirainen # Date 1250288015 14400 # Node ID d7ccdbb58a03e73634ccf1814bcc70a997812a40 # Parent 0287c38ba6bf8ec6173a813f165e25bfee5b4881 config: If master module requests configuration, reread it before replying. If new configuration is invalid, send an ERROR reply back. diff -r 0287c38ba6bf -r d7ccdbb58a03 src/config/all-settings.h --- a/src/config/all-settings.h Fri Aug 14 17:36:27 2009 -0400 +++ b/src/config/all-settings.h Fri Aug 14 18:13:35 2009 -0400 @@ -1,14 +1,10 @@ #ifndef ALL_SETTINGS_H #define ALL_SETTINGS_H -struct config_setting_parser_list { +struct all_settings_root { const char *module_name; struct setting_parser_info *root; - struct setting_parser_context *parser; - void *settings; }; -ARRAY_DEFINE_TYPE(config_setting_parsers, struct config_setting_parser_list *); - -extern struct config_setting_parser_list config_setting_parsers[]; +extern const struct all_settings_root all_roots[]; #endif diff -r 0287c38ba6bf -r d7ccdbb58a03 src/config/config-connection.c --- a/src/config/config-connection.c Fri Aug 14 17:36:27 2009 -0400 +++ b/src/config/config-connection.c Fri Aug 14 18:13:35 2009 -0400 @@ -7,6 +7,7 @@ #include "settings-parser.h" #include "master-service.h" #include "config-request.h" +#include "config-parser.h" #include "config-connection.h" #include @@ -61,11 +62,11 @@ o_stream_send_str(output, "\n"); } -static void config_connection_request(struct config_connection *conn, - const char *const *args) +static int config_connection_request(struct config_connection *conn, + const char *const *args) { struct config_filter filter; - const char *module = ""; + const char *path, *error, *module = ""; /* [] */ memset(&filter, 0, sizeof(filter)); @@ -89,11 +90,23 @@ } } + if (strcmp(module, "master") == 0) { + /* master reads configuration only when reloading settings */ + path = master_service_get_config_path(master_service); + if (config_parse_file(path, TRUE, &error) < 0) { + o_stream_send_str(conn->output, + t_strconcat("ERROR ", error, "\n", NULL)); + config_connection_destroy(conn); + return -1; + } + } + o_stream_cork(conn->output); config_request_handle(&filter, module, 0, config_request_output, conn->output); o_stream_send_str(conn->output, "\n"); o_stream_uncork(conn->output); + return 0; } static void config_connection_input(void *context) @@ -130,8 +143,10 @@ while ((args = config_connection_next_line(conn)) != NULL) { if (args[0] == NULL) continue; - if (strcmp(args[0], "REQ") == 0) - config_connection_request(conn, args + 1); + if (strcmp(args[0], "REQ") == 0) { + if (config_connection_request(conn, args + 1) < 0) + break; + } } } diff -r 0287c38ba6bf -r d7ccdbb58a03 src/config/config-filter.c --- a/src/config/config-filter.c Fri Aug 14 17:36:27 2009 -0400 +++ b/src/config/config-filter.c Fri Aug 14 18:13:35 2009 -0400 @@ -2,6 +2,7 @@ #include "lib.h" #include "array.h" +#include "config-parser.h" #include "config-filter.h" struct config_filter_context { diff -r 0287c38ba6bf -r d7ccdbb58a03 src/config/config-filter.h --- a/src/config/config-filter.h Fri Aug 14 17:36:27 2009 -0400 +++ b/src/config/config-filter.h Fri Aug 14 18:13:35 2009 -0400 @@ -2,7 +2,6 @@ #define CONFIG_FILTER_H #include "network.h" -#include "all-settings.h" struct config_filter { const char *service; diff -r 0287c38ba6bf -r d7ccdbb58a03 src/config/config-parser.c --- a/src/config/config-parser.c Fri Aug 14 17:36:27 2009 -0400 +++ b/src/config/config-parser.c Fri Aug 14 18:13:35 2009 -0400 @@ -7,6 +7,7 @@ #include "strescape.h" #include "istream.h" #include "settings-parser.h" +#include "all-settings.h" #include "config-filter.h" #include "config-parser.h" @@ -43,12 +44,14 @@ ARRAY_DEFINE(all_parsers, struct config_filter_parser_list *); /* parsers matching cur_filter */ ARRAY_TYPE(config_setting_parsers) cur_parsers; + struct config_setting_parser_list *root_parsers; struct config_filter_stack *cur_filter; struct input_stack *cur_input; struct config_filter_context *filter; }; +struct config_setting_parser_list *config_setting_parsers; struct config_filter_context *config_filter; static const char *info_type_name_find(const struct setting_parser_info *info) @@ -171,7 +174,7 @@ cur_parsers = array_get(&ctx->cur_parsers, &count); if (count == 0) { /* first one */ - parser->parser_list = config_setting_parsers; + parser->parser_list = ctx->root_parsers; } else { /* duplicate the first settings list */ parser->parser_list = @@ -223,30 +226,38 @@ return array_idx(&ctx->cur_parsers, 0); } -static void +static int config_filter_parser_list_check(struct parser_context *ctx, - struct config_filter_parser_list *parser) + struct config_filter_parser_list *parser, + const char **error_r) { struct config_setting_parser_list *l = parser->parser_list; const char *errormsg; for (; l->module_name != NULL; l++) { if (!settings_parser_check(l->parser, ctx->pool, &errormsg)) { - i_fatal("Error in configuration file %s: %s", + *error_r = t_strdup_printf( + "Error in configuration file %s: %s", ctx->path, errormsg); + return -1; } } + return 0; } -static void -config_all_parsers_check(struct parser_context *ctx) +static int +config_all_parsers_check(struct parser_context *ctx, const char **error_r) { struct config_filter_parser_list *const *parsers; unsigned int i, count; parsers = array_get(&ctx->all_parsers, &count); - for (i = 0; i < count; i++) - config_filter_parser_list_check(ctx, parsers[i]); + for (i = 0; i < count; i++) { + if (config_filter_parser_list_check(ctx, parsers[i], + error_r) < 0) + return -1; + } + return 0; } static void @@ -345,37 +356,45 @@ #endif } -void config_parse_file(const char *path, bool expand_files) +int config_parse_file(const char *path, bool expand_files, + const char **error_r) { enum settings_parser_flags parser_flags = SETTINGS_PARSER_FLAG_IGNORE_UNKNOWN_KEYS; struct input_stack root; ARRAY_TYPE(const_string) auth_defaults; - struct config_setting_parser_list *l, *const *parsers; + struct config_setting_parser_list *const *parsers; struct parser_context ctx; unsigned int pathlen = 0; - unsigned int counter = 0, auth_counter = 0, cur_counter; + unsigned int i, count, counter = 0, auth_counter = 0, cur_counter; const char *errormsg, *name; char *line, *key, *p; - int fd, ret; + int fd, ret = 0; string_t *str, *full_line; size_t len; + fd = open(path, O_RDONLY); + if (fd < 0) { + *error_r = t_strdup_printf("open(%s) failed: %m", path); + return -1; + } + memset(&ctx, 0, sizeof(ctx)); ctx.pool = pool_alloconly_create("config file parser", 1024*64); ctx.path = path; - fd = open(path, O_RDONLY); - if (fd < 0) - i_fatal("open(%s) failed: %m", path); + for (count = 0; all_roots[count].module_name != NULL; count++) ; + ctx.root_parsers = + p_new(ctx.pool, struct config_setting_parser_list, count+1); + for (i = 0; i < count; i++) { + ctx.root_parsers[i].module_name = all_roots[i].module_name; + ctx.root_parsers[i].root = all_roots[i].root; + ctx.root_parsers[i].parser = + settings_parser_init(ctx.pool, all_roots[i].root, + parser_flags); + } t_array_init(&auth_defaults, 32); - - for (l = config_setting_parsers; l->module_name != NULL; l++) { - i_assert(l->parser == NULL); - l->parser = settings_parser_init(ctx.pool, l->root, parser_flags); - } - t_array_init(&ctx.cur_parsers, 128); p_array_init(&ctx.all_parsers, ctx.pool, 128); ctx.cur_filter = p_new(ctx.pool, struct config_filter_stack, 1); @@ -454,7 +473,6 @@ while (IS_WHITE(*line)) line++; } - ret = 1; if (strcmp(key, "!include_try") == 0 || strcmp(key, "!include") == 0) { if (settings_include(&ctx, fix_relative_path(line, ctx.cur_input), @@ -600,9 +618,11 @@ } if (errormsg != NULL) { - i_fatal("Error in configuration file %s line %d: %s", + *error_r = t_strdup_printf( + "Error in configuration file %s line %d: %s", ctx.cur_input->path, ctx.cur_input->linenum, errormsg); + ret = -1; break; } str_truncate(full_line, 0); @@ -613,9 +633,21 @@ if (line == NULL && ctx.cur_input != NULL) goto prevfile; - config_all_parsers_check(&ctx); + if (ret == 0) { + if (config_all_parsers_check(&ctx, error_r) < 0) + ret = -1; + } + if (ret < 0) { + pool_unref(&ctx.pool); + return -1; + } + + if (config_filter != NULL) + config_filter_deinit(&config_filter); + config_setting_parsers = ctx.root_parsers; (void)array_append_space(&ctx.all_parsers); config_filter = config_filter_init(ctx.pool); config_filter_add_all(config_filter, array_idx(&ctx.all_parsers, 0)); + return 0; } diff -r 0287c38ba6bf -r d7ccdbb58a03 src/config/config-parser.h --- a/src/config/config-parser.h Fri Aug 14 17:36:27 2009 -0400 +++ b/src/config/config-parser.h Fri Aug 14 18:13:35 2009 -0400 @@ -1,8 +1,18 @@ #ifndef CONFIG_PARSER_H #define CONFIG_PARSER_H +struct config_setting_parser_list { + const char *module_name; + struct setting_parser_info *root; + struct setting_parser_context *parser; + void *settings; +}; +ARRAY_DEFINE_TYPE(config_setting_parsers, struct config_setting_parser_list *); + +extern struct config_setting_parser_list *config_setting_parsers; extern struct config_filter_context *config_filter; -void config_parse_file(const char *path, bool expand_files); +int config_parse_file(const char *path, bool expand_files, + const char **error_r); #endif diff -r 0287c38ba6bf -r d7ccdbb58a03 src/config/doveconf.c --- a/src/config/doveconf.c Fri Aug 14 17:36:27 2009 -0400 +++ b/src/config/doveconf.c Fri Aug 14 18:13:35 2009 -0400 @@ -205,6 +205,7 @@ enum config_dump_flags flags = CONFIG_DUMP_FLAG_DEFAULTS; const char *getopt_str, *config_path, *module = ""; struct config_filter filter; + const char *error; char **exec_args = NULL; int c; @@ -247,7 +248,8 @@ } master_service_init_finish(master_service); - config_parse_file(config_path, FALSE); + if (config_parse_file(config_path, FALSE, &error) < 0) + i_fatal("%s", error); if (exec_args == NULL) { const char *info; diff -r 0287c38ba6bf -r d7ccdbb58a03 src/config/main.c --- a/src/config/main.c Fri Aug 14 17:36:27 2009 -0400 +++ b/src/config/main.c Fri Aug 14 18:13:35 2009 -0400 @@ -18,6 +18,7 @@ int main(int argc, char *argv[]) { + const char *path, *error; int c; master_service = master_service_init("config", 0, argc, argv); @@ -28,7 +29,10 @@ master_service_init_log(master_service, "config: ", 0); master_service_init_finish(master_service); - config_parse_file(master_service_get_config_path(master_service), TRUE); + + path = master_service_get_config_path(master_service); + if (config_parse_file(path, TRUE, &error) < 0) + i_fatal("%s", error); master_service_run(master_service, client_connected); config_connections_destroy_all(); diff -r 0287c38ba6bf -r d7ccdbb58a03 src/config/settings-get.pl --- a/src/config/settings-get.pl Fri Aug 14 17:36:27 2009 -0400 +++ b/src/config/settings-get.pl Fri Aug 14 18:13:35 2009 -0400 @@ -87,7 +87,7 @@ close $f; } -print "struct config_setting_parser_list config_setting_parsers[] = {\n"; +print "const struct all_settings_root all_roots[] = {\n"; foreach my $name (keys %parsers) { next if (!$parsers{$name}); @@ -95,7 +95,7 @@ if ($name =~ /^([^_]*)/) { $module = $1; } - print " { \"$module\", &".$name.", NULL, NULL }, \n"; + print " { \"$module\", &".$name." }, \n"; } -print " { NULL, NULL, NULL, NULL }\n"; +print " { NULL, NULL }\n"; print "};\n";