changeset 15087:8c003fe6f5a6

config: Support looking up config for multiple modules at the same time.
author Timo Sirainen <tss@iki.fi>
date Wed, 19 Sep 2012 15:33:10 +0300
parents 04580a59dc53
children 14df6be0111f
files src/config/config-connection.c src/config/config-filter.c src/config/config-filter.h src/config/config-parser-private.h src/config/config-parser.c src/config/config-parser.h src/config/config-request.c src/config/config-request.h src/config/doveconf.c src/config/main.c
diffstat 10 files changed, 77 insertions(+), 61 deletions(-) [+]
line wrap: on
line diff
--- a/src/config/config-connection.c	Tue Sep 18 05:12:28 2012 +0300
+++ b/src/config/config-connection.c	Wed Sep 19 15:33:10 2012 +0300
@@ -1,6 +1,7 @@
 /* Copyright (c) 2005-2012 Dovecot authors, see the included COPYING file */
 
 #include "lib.h"
+#include "array.h"
 #include "llist.h"
 #include "istream.h"
 #include "ostream.h"
@@ -69,16 +70,22 @@
 	struct config_export_context *ctx;
 	struct master_service_settings_output output;
 	struct config_filter filter;
-	const char *path, *error, *module = "";
+	const char *path, *error, *module;
+	ARRAY(const char *) modules;
+	bool is_master = FALSE;
 
 	/* [<args>] */
+	t_array_init(&modules, 4);
 	memset(&filter, 0, sizeof(filter));
 	for (; *args != NULL; args++) {
 		if (strncmp(*args, "service=", 8) == 0)
 			filter.service = *args + 8;
-		else if (strncmp(*args, "module=", 7) == 0)
+		else if (strncmp(*args, "module=", 7) == 0) {
 			module = *args + 7;
-		else if (strncmp(*args, "lname=", 6) == 0)
+			if (strcmp(module, "master") == 0)
+				is_master = TRUE;
+			array_append(&modules, &module, 1);
+		} else if (strncmp(*args, "lname=", 6) == 0)
 			filter.local_name = *args + 6;
 		else if (strncmp(*args, "lip=", 4) == 0) {
 			if (net_addr2ip(*args + 4, &filter.local_net) == 0) {
@@ -94,11 +101,12 @@
 			}
 		}
 	}
+	array_append_zero(&modules);
 
-	if (strcmp(module, "master") == 0) {
+	if (is_master) {
 		/* master reads configuration only when reloading settings */
 		path = master_service_get_config_path(master_service);
-		if (config_parse_file(path, TRUE, "", &error) <= 0) {
+		if (config_parse_file(path, TRUE, NULL, &error) <= 0) {
 			o_stream_nsend_str(conn->output,
 				t_strconcat("\nERROR ", error, "\n", NULL));
 			config_connection_destroy(conn);
@@ -108,7 +116,8 @@
 
 	o_stream_cork(conn->output);
 
-	ctx = config_export_init(module, CONFIG_DUMP_SCOPE_SET, 0,
+	ctx = config_export_init(array_idx(&modules, 0),
+				 CONFIG_DUMP_SCOPE_SET, 0,
 				 config_request_output, conn->output);
 	config_export_by_filter(ctx, &filter);
 	config_export_get_output(ctx, &output);
--- a/src/config/config-filter.c	Tue Sep 18 05:12:28 2012 +0300
+++ b/src/config/config-filter.c	Wed Sep 19 15:33:10 2012 +0300
@@ -164,15 +164,14 @@
 }
 
 static bool have_changed_settings(const struct config_filter_parser *parser,
-				  const char *module)
+				  const char *const *modules)
 {
 	const unsigned char *changes;
 	unsigned int i, j, size;
 
 	for (i = 0; parser->parsers[i].root != NULL; i++) {
-		if (*module != '\0' &&
-		    !config_module_want_parser(config_module_parsers,
-					       module, parser->parsers[i].root))
+		if (!config_module_want_parser(config_module_parsers,
+					       modules, parser->parsers[i].root))
 			continue;
 
 		changes = settings_parser_get_changes(parser->parsers[i].parser);
@@ -186,7 +185,8 @@
 }
 
 static struct config_filter_parser *const *
-config_filter_find_all(struct config_filter_context *ctx, const char *module,
+config_filter_find_all(struct config_filter_context *ctx,
+		       const char *const *modules,
 		       const struct config_filter *filter,
 		       struct master_service_settings_output *output_r)
 {
@@ -203,7 +203,7 @@
 
 		if (!config_filter_match_service(mask, filter)) {
 			if (!str_array_contains(&service_names, mask->service) &&
-			    have_changed_settings(ctx->parsers[i], module))
+			    have_changed_settings(ctx->parsers[i], modules))
 				array_append(&service_names, &mask->service, 1);
 			continue;
 		}
@@ -306,7 +306,7 @@
 }
 
 int config_filter_parsers_get(struct config_filter_context *ctx, pool_t pool,
-			      const char *module,
+			      const char *const *modules,
 			      const struct config_filter *filter,
 			      struct config_module_parser **parsers_r,
 			      struct master_service_settings_output *output_r,
@@ -322,7 +322,7 @@
 	   with an error. Merging SET_STRLIST types requires
 	   settings_parser_apply_changes() to work a bit unintuitively by
 	   letting the destination settings override the source settings. */
-	src = config_filter_find_all(ctx, module, filter, output_r);
+	src = config_filter_find_all(ctx, modules, filter, output_r);
 
 	/* all of them should have the same number of parsers.
 	   duplicate our initial parsers from the first match */
--- a/src/config/config-filter.h	Tue Sep 18 05:12:28 2012 +0300
+++ b/src/config/config-filter.h	Wed Sep 19 15:33:10 2012 +0300
@@ -33,11 +33,11 @@
 
 /* Build new parsers from all existing ones matching the given filter. */
 int config_filter_parsers_get(struct config_filter_context *ctx, pool_t pool,
-			      const char *module,
+			      const char *const *modules,
 			      const struct config_filter *filter,
 			      struct config_module_parser **parsers_r,
 			      struct master_service_settings_output *output_r,
-			      const char **error_r);
+			      const char **error_r) ATTR_NULL(3);
 void config_filter_parsers_free(struct config_module_parser *parsers);
 
 /* Return a list of filters that are a subset of the given filter. */
--- a/src/config/config-parser-private.h	Tue Sep 18 05:12:28 2012 +0300
+++ b/src/config/config-parser-private.h	Wed Sep 19 15:33:10 2012 +0300
@@ -39,7 +39,7 @@
 struct config_parser_context {
 	pool_t pool;
 	const char *path;
-	const char *module;
+	const char *const *modules;
 
 	ARRAY(struct config_filter_parser *) all_parsers;
 	struct config_module_parser *root_parsers;
--- a/src/config/config-parser.c	Tue Sep 18 05:12:28 2012 +0300
+++ b/src/config/config-parser.c	Wed Sep 19 15:33:10 2012 +0300
@@ -334,9 +334,8 @@
 {
 	for (; p->root != NULL; p++) {
 		/* skip checking settings we don't care about */
-		if (*ctx->module != '\0' &&
-		    !config_module_want_parser(ctx->root_parsers,
-					       ctx->module, p->root))
+		if (!config_module_want_parser(ctx->root_parsers,
+					       ctx->modules, p->root))
 			continue;
 
 		settings_parse_var_skip(p->parser);
@@ -396,7 +395,7 @@
 
 	global_ssl_set = get_str_setting(parsers[0], "ssl", "");
 	for (i = 0; i < count && ret == 0; i++) {
-		if (config_filter_parsers_get(new_filter, tmp_pool, "",
+		if (config_filter_parsers_get(new_filter, tmp_pool, NULL,
 					      &parsers[i]->filter,
 					      &tmp_parsers, &output,
 					      error_r) < 0) {
@@ -728,12 +727,12 @@
 {
 	struct config_module_parser *l;
 
-	if (*ctx->module == '\0')
+	if (ctx->modules == NULL)
 		return TRUE;
 
 	for (l = ctx->cur_section->parsers; l->root != NULL; l++) {
 		if (config_module_want_parser(ctx->root_parsers,
-					      ctx->module, l->root) &&
+					      ctx->modules, l->root) &&
 		    settings_parse_is_valid_key(l->parser, key))
 			return TRUE;
 	}
@@ -881,8 +880,8 @@
 	}
 }
 
-int config_parse_file(const char *path, bool expand_values, const char *module,
-		      const char **error_r)
+int config_parse_file(const char *path, bool expand_values,
+		      const char *const *modules, const char **error_r)
 {
 	struct input_stack root;
 	struct config_parser_context ctx;
@@ -924,7 +923,7 @@
 	root.path = path;
 	ctx.cur_input = &root;
 	ctx.expand_values = expand_values;
-	ctx.module = module;
+	ctx.modules = modules;
 
 	p_array_init(&ctx.all_parsers, ctx.pool, 128);
 	ctx.cur_section = p_new(ctx.pool, struct config_section_stack, 1);
@@ -1052,21 +1051,20 @@
 }
 
 bool config_module_want_parser(struct config_module_parser *parsers,
-			       const char *module,
+			       const char *const *modules,
 			       const struct setting_parser_info *root)
 {
 	struct config_module_parser *l;
 
-	if (strcmp(root->module_name, module) == 0)
+	if (modules == NULL)
 		return TRUE;
-	if (root == &master_service_setting_parser_info ||
-	    root == &master_service_ssl_setting_parser_info) {
+	if (root == &master_service_setting_parser_info) {
 		/* everyone wants master service settings */
 		return TRUE;
 	}
 
 	for (l = parsers; l->root != NULL; l++) {
-		if (strcmp(l->root->module_name, module) != 0)
+		if (!str_array_find(modules, l->root->module_name))
 			continue;
 
 		/* see if we can find a way to get from the original parser
--- a/src/config/config-parser.h	Tue Sep 18 05:12:28 2012 +0300
+++ b/src/config/config-parser.h	Wed Sep 19 15:33:10 2012 +0300
@@ -18,13 +18,15 @@
 
 int config_parse_net(const char *value, struct ip_addr *ip_r,
 		     unsigned int *bits_r, const char **error_r);
-int config_parse_file(const char *path, bool expand_values, const char *module,
-		      const char **error_r);
+int config_parse_file(const char *path, bool expand_values,
+		      const char *const *modules, const char **error_r)
+	ATTR_NULL(3);
 
 void config_parse_load_modules(void);
 
 bool config_module_want_parser(struct config_module_parser *parsers,
-			       const char *module,
-			       const struct setting_parser_info *root);
+			       const char *const *modules,
+			       const struct setting_parser_info *root)
+	ATTR_NULL(2);
 
 #endif
--- a/src/config/config-request.c	Tue Sep 18 05:12:28 2012 +0300
+++ b/src/config/config-request.c	Wed Sep 19 15:33:10 2012 +0300
@@ -21,7 +21,7 @@
 	config_request_callback_t *callback;
 	void *context;
 
-	const char *module;
+	const char *const *modules;
 	enum config_dump_flags flags;
 	const struct config_module_parser *parsers;
 	struct config_module_parser *dup_parsers;
@@ -341,20 +341,20 @@
 }
 
 struct config_export_context *
-config_export_init(const char *module, enum config_dump_scope scope,
+config_export_init(const char *const *modules, enum config_dump_scope scope,
 		   enum config_dump_flags flags,
 		   config_request_callback_t *callback, void *context)
 {
 	struct config_export_context *ctx;
 	pool_t pool;
 
-	i_assert(module != NULL);
+	i_assert(modules != NULL);
 
 	pool = pool_alloconly_create(MEMPOOL_GROWING"config export", 1024*64);
 	ctx = p_new(pool, struct config_export_context, 1);
 	ctx->pool = pool;
 
-	ctx->module = p_strdup(pool, module);
+	ctx->modules = p_strarray_dup(pool, modules);
 	ctx->flags = flags;
 	ctx->callback = callback;
 	ctx->context = context;
@@ -371,7 +371,7 @@
 	const char *error;
 
 	if (config_filter_parsers_get(config_filter, ctx->pool,
-				      ctx->module, filter,
+				      ctx->modules, filter,
 				      &ctx->dup_parsers, &ctx->output,
 				      &error) < 0) {
 		i_error("%s", error);
@@ -417,9 +417,8 @@
 
 	for (i = 0; ctx->parsers[i].root != NULL; i++) {
 		parser = &ctx->parsers[i];
-		if (*ctx->module != '\0' &&
-		    !config_module_want_parser(config_module_parsers,
-					       ctx->module, parser->root))
+		if (!config_module_want_parser(config_module_parsers,
+					       ctx->modules, parser->root))
 			continue;
 
 		settings_export(ctx, parser->root, FALSE,
--- a/src/config/config-request.h	Tue Sep 18 05:12:28 2012 +0300
+++ b/src/config/config-request.h	Wed Sep 19 15:33:10 2012 +0300
@@ -38,10 +38,10 @@
 			enum setting_type type, bool dump_default,
 			bool *dump_r) ATTR_NULL(3);
 struct config_export_context *
-config_export_init(const char *module, enum config_dump_scope scope,
+config_export_init(const char *const *modules, enum config_dump_scope scope,
 		   enum config_dump_flags flags,
 		   config_request_callback_t *callback, void *context)
-	ATTR_NULL(5);
+	ATTR_NULL(1, 5);
 void config_export_by_filter(struct config_export_context *ctx,
 			     const struct config_filter *filter);
 void config_export_parsers(struct config_export_context *ctx,
--- a/src/config/doveconf.c	Tue Sep 18 05:12:28 2012 +0300
+++ b/src/config/doveconf.c	Wed Sep 19 15:33:10 2012 +0300
@@ -118,7 +118,7 @@
 }
 
 static struct config_dump_human_context *
-config_dump_human_init(const char *module, enum config_dump_scope scope,
+config_dump_human_init(const char *const *modules, enum config_dump_scope scope,
 		       bool check_settings)
 {
 	struct config_dump_human_context *ctx;
@@ -137,7 +137,7 @@
 	if (check_settings)
 		flags |= CONFIG_DUMP_FLAG_CHECK_SETTINGS;
 
-	ctx->export_ctx = config_export_init(module, scope, flags,
+	ctx->export_ctx = config_export_init(modules, scope, flags,
 					     config_request_get_strings, ctx);
 	return ctx;
 }
@@ -390,7 +390,7 @@
 static int
 config_dump_human_sections(struct ostream *output,
 			   const struct config_filter *filter,
-			   const char *module)
+			   const char *const *modules)
 {
 	struct config_filter_parser *const *filters;
 	static struct config_dump_human_context *ctx;
@@ -404,7 +404,7 @@
 	filters++;
 
 	for (; *filters != NULL; filters++) {
-		ctx = config_dump_human_init(module, CONFIG_DUMP_SCOPE_SET,
+		ctx = config_dump_human_init(modules, CONFIG_DUMP_SCOPE_SET,
 					     FALSE);
 		indent = config_dump_filter_begin(ctx->list_prefix,
 						  &(*filters)->filter);
@@ -419,7 +419,7 @@
 }
 
 static int ATTR_NULL(4)
-config_dump_human(const struct config_filter *filter, const char *module,
+config_dump_human(const struct config_filter *filter, const char *const *modules,
 		  enum config_dump_scope scope, const char *setting_name_filter)
 {
 	static struct config_dump_human_context *ctx;
@@ -430,13 +430,13 @@
 	o_stream_set_no_error_handling(output, TRUE);
 	o_stream_cork(output);
 
-	ctx = config_dump_human_init(module, scope, TRUE);
+	ctx = config_dump_human_init(modules, scope, TRUE);
 	config_export_by_filter(ctx->export_ctx, filter);
 	ret = config_dump_human_output(ctx, output, 0, setting_name_filter);
 	config_dump_human_deinit(ctx);
 
 	if (setting_name_filter == NULL)
-		ret = config_dump_human_sections(output, filter, module);
+		ret = config_dump_human_sections(output, filter, modules);
 
 	o_stream_uncork(output);
 	o_stream_destroy(&output);
@@ -452,7 +452,7 @@
 	unsigned int len;
 	bool dump_section = FALSE;
 
-	ctx = config_dump_human_init("", scope, FALSE);
+	ctx = config_dump_human_init(NULL, scope, FALSE);
 	config_export_by_filter(ctx->export_ctx, filter);
 	if (config_export_finish(&ctx->export_ctx) < 0)
 		return -1;
@@ -478,7 +478,7 @@
 	config_dump_human_deinit(ctx);
 
 	if (dump_section)
-		(void)config_dump_human(filter, "", scope, setting_name_filter);
+		(void)config_dump_human(filter, NULL, scope, setting_name_filter);
 	return 0;
 }
 
@@ -589,7 +589,8 @@
 int main(int argc, char *argv[])
 {
 	enum config_dump_scope scope = CONFIG_DUMP_SCOPE_ALL;
-	const char *orig_config_path, *config_path, *module = "";
+	const char *orig_config_path, *config_path, *module;
+	ARRAY(const char *) module_names;
 	struct config_filter filter;
 	const char *error;
 	char **exec_args = NULL, **setting_name_filters = NULL;
@@ -611,6 +612,7 @@
 	orig_config_path = master_service_get_config_path(master_service);
 
 	i_set_failure_prefix("doveconf: ");
+	t_array_init(&module_names, 4);
 	while ((c = master_getopt(master_service)) > 0) {
 		if (c == 'e') {
 			expand_vars = TRUE;
@@ -629,7 +631,8 @@
 			hide_key = TRUE;
 			break;
 		case 'm':
-			module = optarg;
+			module = t_strdup(optarg);
+			array_append(&module_names, &module, 1);
 			break;
 		case 'n':
 			scope = CONFIG_DUMP_SCOPE_CHANGED;
@@ -650,6 +653,8 @@
 			return FATAL_DEFAULT;
 		}
 	}
+	array_append_zero(&module_names);
+
 	config_path = master_service_get_config_path(master_service);
 	/* use strcmp() instead of !=, because dovecot -n always gives us
 	   -c parameter */
@@ -673,7 +678,8 @@
 
 	if ((ret = config_parse_file(dump_defaults ? NULL : config_path,
 				     expand_vars,
-				     parse_full_config ? "" : module,
+				     parse_full_config ? NULL :
+				     array_idx(&module_names, 0),
 				     &error)) == 0 &&
 	    access(EXAMPLE_CONFIG_DIR, X_OK) == 0) {
 		i_fatal("%s (copy example configs from "EXAMPLE_CONFIG_DIR"/)",
@@ -686,7 +692,7 @@
 	if (simple_output) {
 		struct config_export_context *ctx;
 
-		ctx = config_export_init(module, scope,
+		ctx = config_export_init(array_idx(&module_names, 0), scope,
 					 CONFIG_DUMP_FLAG_CHECK_SETTINGS,
 					 config_request_simple_stdout,
 					 setting_name_filters);
@@ -713,12 +719,14 @@
 		if (!config_path_specified)
 			check_wrong_config(config_path);
 		fflush(stdout);
-		ret2 = config_dump_human(&filter, module, scope, NULL);
+		ret2 = config_dump_human(&filter, array_idx(&module_names, 0),
+					 scope, NULL);
 	} else {
 		struct config_export_context *ctx;
 
 		env_put("DOVECONF_ENV=1");
-		ctx = config_export_init(module, CONFIG_DUMP_SCOPE_SET,
+		ctx = config_export_init(array_idx(&module_names, 0),
+					 CONFIG_DUMP_SCOPE_SET,
 					 CONFIG_DUMP_FLAG_CHECK_SETTINGS,
 					 config_request_putenv, NULL);
 		config_export_by_filter(ctx, &filter);
--- a/src/config/main.c	Tue Sep 18 05:12:28 2012 +0300
+++ b/src/config/main.c	Wed Sep 19 15:33:10 2012 +0300
@@ -30,7 +30,7 @@
 	config_parse_load_modules();
 
 	path = master_service_get_config_path(master_service);
-	if (config_parse_file(path, TRUE, "", &error) <= 0)
+	if (config_parse_file(path, TRUE, NULL, &error) <= 0)
 		i_fatal("%s", error);
 
 	master_service_run(master_service, client_connected);