]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
config: If master module requests configuration, reread it before replying.
authorTimo Sirainen <tss@iki.fi>
Fri, 14 Aug 2009 22:13:35 +0000 (18:13 -0400)
committerTimo Sirainen <tss@iki.fi>
Fri, 14 Aug 2009 22:13:35 +0000 (18:13 -0400)
If new configuration is invalid, send an ERROR reply back.

--HG--
branch : HEAD

src/config/all-settings.h
src/config/config-connection.c
src/config/config-filter.c
src/config/config-filter.h
src/config/config-parser.c
src/config/config-parser.h
src/config/doveconf.c
src/config/main.c
src/config/settings-get.pl

index 8060196a4ffef052f6bf489094d8426f32b585d0..d04335a764d1806627631b6b1cea3d4511c59c55 100644 (file)
@@ -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
index 3f261bbc9b11c65f1e3aa68268eb2cf10d4bb05b..d56d2453613037b8576a1620ad0e0fad9105380b 100644 (file)
@@ -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 <stdlib.h>
@@ -61,11 +62,11 @@ config_request_output(const char *key, const char *value,
        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 = "";
 
        /* [<args>] */
        memset(&filter, 0, sizeof(filter));
@@ -89,11 +90,23 @@ static void config_connection_request(struct config_connection *conn,
                }
        }
 
+       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 @@ static void config_connection_input(void *context)
        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;
+               }
        }
 }
 
index 8fd0c6ad8f241d9f3774cac6f65e21d6b5c49084..223950957c2cc88276e7f8d19855b639696a89b3 100644 (file)
@@ -2,6 +2,7 @@
 
 #include "lib.h"
 #include "array.h"
+#include "config-parser.h"
 #include "config-filter.h"
 
 struct config_filter_context {
index de184a2e2a8d7c82c5bc9ef3c377c2b4e420326f..3c69bfcf3e6fe230906081cd7bffadaff0ab5453 100644 (file)
@@ -2,7 +2,6 @@
 #define CONFIG_FILTER_H
 
 #include "network.h"
-#include "all-settings.h"
 
 struct config_filter {
        const char *service;
index b57d9eb26c518392b2284e00f394cf9660769c0c..32a903a0e66da8d2235999bc07cac3926d2f961d 100644 (file)
@@ -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 @@ struct parser_context {
        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 @@ config_add_new_parser(struct parser_context *ctx)
        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 @@ config_update_cur_parsers(struct parser_context *ctx)
        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 @@ settings_include(struct parser_context *ctx, const char *pattern,
 #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);
-
-       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);
+       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);
        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 @@ prevfile:
                        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 @@ prevfile:
                }
 
                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 @@ prevfile:
        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;
 }
index 33b11063904aaa343fb43ab6b001efe84222a318..ba6a2b1d5882739d7381f5f453a56d4ace836922 100644 (file)
@@ -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
index 4420edc80e369d128f29fee4a4b2a15f3338e114..937da4a9020339966fa3ca349e1184badf867e84 100644 (file)
@@ -205,6 +205,7 @@ int main(int argc, char *argv[])
        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 @@ int main(int argc, char *argv[])
        }
        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;
index 6f651137c48f0c221b90c1992dc0063a8ebc237a..2f7b7f5f14da2377702103e7487feae9c46bfc93 100644 (file)
@@ -18,6 +18,7 @@ static void client_connected(const struct master_service_connection *conn)
 
 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 @@ int main(int argc, char *argv[])
 
        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();
index 26f113d5ed6d80b0ed430a7e691e77fa4ce8164f..c2d200ac62a6888f66670043180a02ba180c0370 100755 (executable)
@@ -87,7 +87,7 @@ foreach my $file (@ARGV) {
   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 @@ foreach my $name (keys %parsers) {
   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";