config-parser.c revision e59faf65ce864fe95dc00f5d52b8323cdbd0608a
e59faf65ce864fe95dc00f5d52b8323cdbd0608aTimo Sirainen/* Copyright (c) 2005-2010 Dovecot authors, see the included COPYING file */
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#define IS_WHITE(c) ((c) == ' ' || (c) == '\t')
1cfdcb36985904eff281fc6d7ea2d13b3c375980Timo Sirainen /* root=NULL-terminated list of parsers */
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen unsigned int pathlen;
d595049948579def2d82718dbce0a6b49a281402Timo Sirainen unsigned int linenum;
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen ARRAY_DEFINE(all_parsers, struct config_filter_parser *);
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainenstatic const enum settings_parser_flags settings_parser_flags =
94163c620a8880024d0e8bbb503c788159fa222bTimo Sirainenstruct config_module_parser *config_module_parsers;
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainenstatic const char *info_type_name_find(const struct setting_parser_info *info)
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainen unsigned int i;
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainen for (i = 0; info->defines[i].key != NULL; i++) {
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainen if (info->defines[i].offset == info->type_offset)
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainen i_panic("setting parser: Invalid type_offset value");
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainenstatic void config_add_type(struct setting_parser_context *parser,
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainen const char *p;
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainen ret = settings_parse_line(parser, str_c(str));
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainenconfig_apply_line(struct parser_context *ctx, const char *key,
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen const char **error_r)
1cfdcb36985904eff281fc6d7ea2d13b3c375980Timo Sirainen for (l = ctx->cur_section->parsers; l->root != NULL; l++) {
28cb56e6957f06717e876cecb7aabc820fdf632eTimo Sirainen config_add_type(l->parser, line, section_name);
3c3777721b56e065fac99a0f34e4cef4f293b517Timo Sirainen } else if (ret < 0) {
3c3777721b56e065fac99a0f34e4cef4f293b517Timo Sirainen *error_r = settings_parser_get_error(l->parser);
3c3777721b56e065fac99a0f34e4cef4f293b517Timo Sirainen *error_r = t_strconcat("Unknown setting: ", key, NULL);
bbc30fd4fa86723f6a72309ad3a2a96f34eabd6cTimo Sirainenstatic const char *
bbc30fd4fa86723f6a72309ad3a2a96f34eabd6cTimo Sirainenfix_relative_path(const char *path, struct input_stack *input)
bbc30fd4fa86723f6a72309ad3a2a96f34eabd6cTimo Sirainen const char *p;
bbc30fd4fa86723f6a72309ad3a2a96f34eabd6cTimo Sirainen return t_strconcat(t_strdup_until(input->path, p+1), path, NULL);
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen unsigned int i, count;
1cfdcb36985904eff281fc6d7ea2d13b3c375980Timo Sirainen for (count = 0; all_roots[count] != NULL; count++) ;
94163c620a8880024d0e8bbb503c788159fa222bTimo Sirainen dest = p_new(pool, struct config_module_parser, count + 1);
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen for (i = 0; i < count; i++) {
1cfdcb36985904eff281fc6d7ea2d13b3c375980Timo Sirainen dest[i].parser = settings_parser_init(pool, all_roots[i],
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainenconfig_add_new_parser(struct parser_context *ctx)
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen struct config_section_stack *cur_section = ctx->cur_section;
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen parser = p_new(ctx->pool, struct config_filter_parser, 1);
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen parser->parsers = cur_section->prev == NULL ? ctx->root_parsers :
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainenconfig_add_new_section(struct parser_context *ctx)
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen section = p_new(ctx->pool, struct config_section_stack, 1);
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainenconfig_filter_parser_find(struct parser_context *ctx,
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen struct config_filter_parser *parser = *parsers;
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen if (config_filters_equal(&parser->filter, filter))
08e7163a8d12979119fa56c92676af4ba6304f1aTimo Sirainenconfig_parse_net(struct parser_context *ctx, const char *value,
08e7163a8d12979119fa56c92676af4ba6304f1aTimo Sirainen const char *p;
08e7163a8d12979119fa56c92676af4ba6304f1aTimo Sirainen if (net_parse_range(value, ip_r, bits_r) == 0)
08e7163a8d12979119fa56c92676af4ba6304f1aTimo Sirainen ret = net_gethostbyname(value, &ips, &ip_count);
08e7163a8d12979119fa56c92676af4ba6304f1aTimo Sirainen *error_r = t_strdup_printf("gethostbyname(%s) failed: %s",
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainenconfig_filter_add_new_filter(struct parser_context *ctx,
94163c620a8880024d0e8bbb503c788159fa222bTimo Sirainen const char **error_r)
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen struct config_filter *filter = &ctx->cur_section->filter;
dbd93ca6319a01fdea82853e8b4bd4b226d796f0Timo Sirainen struct config_filter *parent = &ctx->cur_section->prev->filter;
dbd93ca6319a01fdea82853e8b4bd4b226d796f0Timo Sirainen *error_r = "protocol must not be under protocol";
08e7163a8d12979119fa56c92676af4ba6304f1aTimo Sirainen *error_r = "local must not be under protocol";
08e7163a8d12979119fa56c92676af4ba6304f1aTimo Sirainen else if (config_parse_net(ctx, value, &filter->local_host,
dbd93ca6319a01fdea82853e8b4bd4b226d796f0Timo Sirainen else if (parent->local_bits > filter->local_bits ||
08e7163a8d12979119fa56c92676af4ba6304f1aTimo Sirainen *error_r = "local not a subset of parent local";
08e7163a8d12979119fa56c92676af4ba6304f1aTimo Sirainen *error_r = "remote must not be under protocol";
08e7163a8d12979119fa56c92676af4ba6304f1aTimo Sirainen else if (config_parse_net(ctx, value, &filter->remote_host,
dbd93ca6319a01fdea82853e8b4bd4b226d796f0Timo Sirainen else if (parent->remote_bits > filter->remote_bits ||
08e7163a8d12979119fa56c92676af4ba6304f1aTimo Sirainen *error_r = "remote not a subset of parent remote";
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen parser = config_filter_parser_find(ctx, filter);
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainenconfig_filter_parser_check(struct parser_context *ctx,
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen const char **error_r)
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen if (!settings_parser_check(p->parser, ctx->pool, error_r))
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainenconfig_all_parsers_check(struct parser_context *ctx,
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen const char **error_r)
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen unsigned int i, count;
3872c943f81f4440d54f2ac4657d3dfd31978600Timo Sirainen tmp_pool = pool_alloconly_create("config parsers check", 1024*32);
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen parsers = array_get(&ctx->all_parsers, &count);
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen i_assert(count > 0 && parsers[count-1] == NULL);
6ed1e82824590b514201d9db84ba96bdfc832dd5Timo Sirainen if (config_filter_parsers_get(new_filter, tmp_pool,
6ed1e82824590b514201d9db84ba96bdfc832dd5Timo Sirainen ret = config_filter_parser_check(ctx, tmp_parsers, error_r);
1b33e848e84e6f74aa0e3339c32fa96bc15102a2Timo Sirainenstr_append_file(string_t *str, const char *key, const char *path,
1b33e848e84e6f74aa0e3339c32fa96bc15102a2Timo Sirainen const char **error_r)
1b33e848e84e6f74aa0e3339c32fa96bc15102a2Timo Sirainen *error_r = t_strdup_printf("%s: Can't open file %s: %m",
1b33e848e84e6f74aa0e3339c32fa96bc15102a2Timo Sirainen while ((ret = read(fd, buf, sizeof(buf))) > 0)
1b33e848e84e6f74aa0e3339c32fa96bc15102a2Timo Sirainen *error_r = t_strdup_printf("%s: read(%s) failed: %m",
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainenstatic int settings_add_include(struct parser_context *ctx, const char *path,
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen for (tmp = ctx->cur_input; tmp != NULL; tmp = tmp->prev) {
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen *error_r = t_strdup_printf("Recursive include file: %s", path);
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen *error_r = t_strdup_printf("Couldn't open include file %s: %m",
c051a3dae43d9418e19f2f83eb02fbfb0a558d6bTimo Sirainen new_input->input = i_stream_create_fd(fd, (size_t)-1, TRUE);
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen i_stream_set_return_partial_line(new_input->input, TRUE);
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainensettings_include(struct parser_context *ctx, const char *pattern,
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen unsigned int i;
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen switch (glob(pattern, GLOB_BRACE, NULL, &globbers)) {
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen *error_r = "glob() failed: Not enough memory";
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen /* iterate throuth the different files matching the globbing */
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen if (settings_add_include(ctx, globbers.gl_pathv[i],
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen return settings_add_include(ctx, pattern, ignore_errors, error_r);
25e480bc781fdbcbee1d8b88ccdef163c0c63b0fTimo Sirainenconfig_parse_line(struct parser_context *ctx, char *line, string_t *full_line,
3c3777721b56e065fac99a0f34e4cef4f293b517Timo Sirainen const char *key;
3c3777721b56e065fac99a0f34e4cef4f293b517Timo Sirainen unsigned int len;
3c3777721b56e065fac99a0f34e4cef4f293b517Timo Sirainen /* @UNSAFE: line is modified */
3c3777721b56e065fac99a0f34e4cef4f293b517Timo Sirainen /* skip whitespace */
3c3777721b56e065fac99a0f34e4cef4f293b517Timo Sirainen /* ignore comments or empty lines */
3c3777721b56e065fac99a0f34e4cef4f293b517Timo Sirainen /* strip away comments. pretty kludgy way really.. */
3c3777721b56e065fac99a0f34e4cef4f293b517Timo Sirainen if (*p == '\0')
3c3777721b56e065fac99a0f34e4cef4f293b517Timo Sirainen } else if (*p == '#') {
25e480bc781fdbcbee1d8b88ccdef163c0c63b0fTimo Sirainen "Ambiguous '#' character in line, treating it as comment. "
25e480bc781fdbcbee1d8b88ccdef163c0c63b0fTimo Sirainen "Add a space before it to remove this warning.",
3c3777721b56e065fac99a0f34e4cef4f293b517Timo Sirainen /* remove whitespace from end of line */
3c3777721b56e065fac99a0f34e4cef4f293b517Timo Sirainen /* continues in next line */
3c3777721b56e065fac99a0f34e4cef4f293b517Timo Sirainen /* a) key = value
3c3777721b56e065fac99a0f34e4cef4f293b517Timo Sirainen b) section_type [section_name] {
3c3777721b56e065fac99a0f34e4cef4f293b517Timo Sirainen while (!IS_WHITE(*line) && *line != '\0' && *line != '=')
3c3777721b56e065fac99a0f34e4cef4f293b517Timo Sirainen /* b) + errors */
3c3777721b56e065fac99a0f34e4cef4f293b517Timo Sirainen /* get section name */
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainenstatic int config_parse_finish(struct parser_context *ctx, const char **error_r)
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen config_filter_add_all(new_filter, array_idx(&ctx->all_parsers, 0));
4383941ed43d004f34f77334a06ad14e6a305607Timo Sirainen if ((ret = config_all_parsers_check(ctx, new_filter, &error)) < 0) {
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen *error_r = t_strdup_printf("Error in configuration file %s: %s",
ec1a4f4306496380e9d96ee08a3718a669d0875aTimo Sirainenint config_parse_file(const char *path, bool expand_files,
ec1a4f4306496380e9d96ee08a3718a669d0875aTimo Sirainen const char **error_r)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen unsigned int pathlen = 0;
4b94ae3dcbace4781b64e87aea00ec0bc03a0d8aTimo Sirainen const char *errormsg, *key, *value, *section_name;
ec1a4f4306496380e9d96ee08a3718a669d0875aTimo Sirainen *error_r = t_strdup_printf("open(%s) failed: %m", path);
ebded144e74a668973ec9ba6e7e169d4e6dc766cTimo Sirainen ctx.pool = pool_alloconly_create("config file parser", 1024*64);
1cfdcb36985904eff281fc6d7ea2d13b3c375980Timo Sirainen for (count = 0; all_roots[count] != NULL; count++) ;
94163c620a8880024d0e8bbb503c788159fa222bTimo Sirainen p_new(ctx.pool, struct config_module_parser, count+1);
ec1a4f4306496380e9d96ee08a3718a669d0875aTimo Sirainen for (i = 0; i < count; i++) {
13be7f7215efe02d020e9d823772861df98b82bdTimo Sirainen p_array_init(&ctx.all_parsers, ctx.pool, 128);
13be7f7215efe02d020e9d823772861df98b82bdTimo Sirainen ctx.cur_section = p_new(ctx.pool, struct config_section_stack, 1);
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen ctx.cur_input->input = i_stream_create_fd(fd, (size_t)-1, TRUE);
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen i_stream_set_return_partial_line(ctx.cur_input->input, TRUE);
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen while ((line = i_stream_read_next_line(ctx.cur_input->input)) != NULL) {
25e480bc781fdbcbee1d8b88ccdef163c0c63b0fTimo Sirainen type = config_parse_line(&ctx, line, full_line,
d1a2ad6c289e77cb72f772bde4cd2d54099916bfTimo Sirainen } else if (str_append_file(str, key, value, &errormsg) < 0) {
1b33e848e84e6f74aa0e3339c32fa96bc15102a2Timo Sirainen /* file reading failed */
94163c620a8880024d0e8bbb503c788159fa222bTimo Sirainen (void)config_apply_line(&ctx, key, str_c(str), NULL, &errormsg);
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen ctx.cur_section = config_add_new_section(&ctx);
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen if (config_filter_add_new_filter(&ctx, key, value,
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen /* new filter */
94163c620a8880024d0e8bbb503c788159fa222bTimo Sirainen /* new config section */
4b94ae3dcbace4781b64e87aea00ec0bc03a0d8aTimo Sirainen /* no section name, use a counter */
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen section_name = settings_section_escape(value);
94163c620a8880024d0e8bbb503c788159fa222bTimo Sirainen if (config_apply_line(&ctx, key, str_c(str), value, &errormsg) < 0)
3c3777721b56e065fac99a0f34e4cef4f293b517Timo Sirainen (void)settings_include(&ctx, fix_relative_path(value, ctx.cur_input),
ec1a4f4306496380e9d96ee08a3718a669d0875aTimo Sirainen "Error in configuration file %s line %d: %s",
fc4b301e2dd86c096b9c41ad1b011b752fffd570Timo Sirainen ARRAY_DEFINE(new_roots, const struct setting_parser_info *);
12ab808b472ed51923945efac4156a380bd58d57Timo Sirainen struct service_settings *const *services, *service_set;
12ab808b472ed51923945efac4156a380bd58d57Timo Sirainen unsigned int i, count;
9ba7e76c20be775f368254e3059a6189fe789f16Timo Sirainen modules = module_dir_load(CONFIG_MODULE_DIR, NULL, &mod_set);
12ab808b472ed51923945efac4156a380bd58d57Timo Sirainen t_strdup_printf("%s_service_settings", m->name));
fc4b301e2dd86c096b9c41ad1b011b752fffd570Timo Sirainen /* modules added new settings. add the defaults and start
fc4b301e2dd86c096b9c41ad1b011b752fffd570Timo Sirainen using the new list. */
12ab808b472ed51923945efac4156a380bd58d57Timo Sirainen /* module added new services. update the defaults. */
12ab808b472ed51923945efac4156a380bd58d57Timo Sirainen services = array_get(default_services, &count);
12ab808b472ed51923945efac4156a380bd58d57Timo Sirainen for (i = 0; i < count; i++)