From: Timo Sirainen Date: Mon, 31 Aug 2009 16:20:38 +0000 (-0400) Subject: config: Code cleanups. X-Git-Tag: 2.0.alpha1~219 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=3c3777721b56e065fac99a0f34e4cef4f293b517;p=thirdparty%2Fdovecot%2Fcore.git config: Code cleanups. --HG-- branch : HEAD --- diff --git a/src/config/config-parser.c b/src/config/config-parser.c index d4c4266d49..19a980b5c9 100644 --- a/src/config/config-parser.c +++ b/src/config/config-parser.c @@ -92,10 +92,10 @@ static void config_add_type(struct setting_parser_context *parser, i_assert(ret > 0); } -static const char * +static int config_parsers_parse_line(struct config_setting_parser_list *parsers, const char *key, const char *line, - const char *section_name) + const char *section_name, const char **error_r) { struct config_setting_parser_list *l; bool found = FALSE; @@ -107,26 +107,30 @@ config_parsers_parse_line(struct config_setting_parser_list *parsers, found = TRUE; if (section_name != NULL) config_add_type(l->parser, line, section_name); - } else if (ret < 0) - return settings_parser_get_error(l->parser); + } else if (ret < 0) { + *error_r = settings_parser_get_error(l->parser); + return -1; + } } - - return found ? NULL : t_strconcat("Unknown setting: ", key, NULL); + if (!found) { + *error_r = t_strconcat("Unknown setting: ", key, NULL); + return -1; + } + return 0; } -static const char * -config_parse_line(struct config_setting_parser_list *const *all_parsers, - const char *key, const char *line, const char *section_name) +static int +config_apply_line(struct config_setting_parser_list *const *all_parsers, + const char *key, const char *line, const char *section_name, + const char **error_r) { - const char *ret; - for (; *all_parsers != NULL; all_parsers++) { - ret = config_parsers_parse_line(*all_parsers, key, line, - section_name); - if (ret != NULL) - return ret; + if (config_parsers_parse_line(*all_parsers, key, line, + section_name, error_r) < 0) + return -1; } - return NULL; + *error_r = NULL; + return 0; } static const char * @@ -260,7 +264,7 @@ config_all_parsers_check(struct parser_context *ctx, const char **error_r) return 0; } -static void +static int str_append_file(string_t *str, const char *key, const char *path, const char **error_r) { @@ -272,7 +276,7 @@ str_append_file(string_t *str, const char *key, const char *path, if (fd == -1) { *error_r = t_strdup_printf("%s: Can't open file %s: %m", key, path); - return; + return -1; } while ((ret = read(fd, buf, sizeof(buf))) > 0) str_append_n(str, buf, ret); @@ -281,6 +285,7 @@ str_append_file(string_t *str, const char *key, const char *path, key, path); } (void)close(fd); + return ret < 0 ? -1 : 0; } static int settings_add_include(struct parser_context *ctx, const char *path, @@ -356,6 +361,133 @@ settings_include(struct parser_context *ctx, const char *pattern, #endif } +enum config_line_type { + CONFIG_LINE_TYPE_SKIP, + CONFIG_LINE_TYPE_ERROR, + CONFIG_LINE_TYPE_KEYVALUE, + CONFIG_LINE_TYPE_SECTION_BEGIN, + CONFIG_LINE_TYPE_SECTION_END, + CONFIG_LINE_TYPE_INCLUDE, + CONFIG_LINE_TYPE_INCLUDE_TRY +}; + +static enum config_line_type +config_parse_line(char *line, string_t *full_line, const char **key_r, + const char **section_r, const char **value_r) +{ + const char *key; + unsigned int len; + char *p; + + *key_r = NULL; + *value_r = NULL; + *section_r = NULL; + + /* @UNSAFE: line is modified */ + + /* skip whitespace */ + while (IS_WHITE(*line)) + line++; + + /* ignore comments or empty lines */ + if (*line == '#' || *line == '\0') + return CONFIG_LINE_TYPE_SKIP; + + /* strip away comments. pretty kludgy way really.. */ + for (p = line; *p != '\0'; p++) { + if (*p == '\'' || *p == '"') { + char quote = *p; + for (p++; *p != quote && *p != '\0'; p++) { + if (*p == '\\' && p[1] != '\0') + p++; + } + if (*p == '\0') + break; + } else if (*p == '#') { + *p = '\0'; + break; + } + } + + /* remove whitespace from end of line */ + len = strlen(line); + while (IS_WHITE(line[len-1])) + len--; + line[len] = '\0'; + + if (len > 0 && line[len-1] == '\\') { + /* continues in next line */ + line[len-1] = '\0'; + str_append(full_line, line); + return CONFIG_LINE_TYPE_SKIP; + } + if (str_len(full_line) > 0) { + str_append(full_line, line); + line = str_c_modifiable(full_line); + } + + /* a) key = value + b) section_type [section_name] { + c) } */ + key = line; + while (!IS_WHITE(*line) && *line != '\0' && *line != '=') + line++; + if (IS_WHITE(*line)) { + *line++ = '\0'; + while (IS_WHITE(*line)) line++; + } + *key_r = key; + *value_r = line; + + if (strcmp(key, "!include") == 0) + return CONFIG_LINE_TYPE_INCLUDE; + if (strcmp(key, "!include_try") == 0) + return CONFIG_LINE_TYPE_INCLUDE_TRY; + + if (*line == '=') { + /* a) */ + *line++ = '\0'; + while (IS_WHITE(*line)) line++; + + len = strlen(line); + if (len > 0 && + ((*line == '"' && line[len-1] == '"') || + (*line == '\'' && line[len-1] == '\''))) { + line[len-1] = '\0'; + line = str_unescape(line+1); + } + *value_r = line; + return CONFIG_LINE_TYPE_KEYVALUE; + } + + if (strcmp(key, "}") == 0 && *line == '\0') + return CONFIG_LINE_TYPE_SECTION_END; + + /* b) + errors */ + line[-1] = '\0'; + + if (*line == '{') + *section_r = ""; + else { + /* get section name */ + *section_r = line; + while (!IS_WHITE(*line) && *line != '\0') + line++; + + if (*line != '\0') { + *line++ = '\0'; + while (IS_WHITE(*line)) + line++; + } + if (*line != '{') { + *value_r = "Expecting '='"; + return CONFIG_LINE_TYPE_ERROR; + } + *value_r = line; + } + return CONFIG_LINE_TYPE_SECTION_BEGIN; +} + int config_parse_file(const char *path, bool expand_files, const char **error_r) { @@ -367,11 +499,11 @@ int config_parse_file(const char *path, bool expand_files, struct parser_context ctx; unsigned int pathlen = 0; unsigned int i, count, counter = 0, auth_counter = 0, cur_counter; - const char *errormsg, *name; - char *line, *key, *p; - int fd, ret = 0; + const char *errormsg, *key, *value, *section, *p; string_t *str, *full_line; - size_t len; + enum config_line_type type; + char *line; + int fd, ret = 0; fd = open(path, O_RDONLY); if (fd < 0) { @@ -401,9 +533,9 @@ int config_parse_file(const char *path, bool expand_files, config_add_new_parser(&ctx); parsers = config_update_cur_parsers(&ctx); - errormsg = config_parse_line(parsers, "0", "auth=0", NULL); + (void)config_apply_line(parsers, "0", "auth=0", NULL, &errormsg); i_assert(errormsg == NULL); - errormsg = config_parse_line(parsers, "name", "auth/0/name=default", NULL); + (void)config_apply_line(parsers, "name", "auth/0/name=default", NULL, &errormsg); i_assert(errormsg == NULL); memset(&root, 0, sizeof(root)); @@ -418,146 +550,61 @@ int config_parse_file(const char *path, bool expand_files, prevfile: while ((line = i_stream_read_next_line(ctx.cur_input->input)) != NULL) { ctx.cur_input->linenum++; - - /* @UNSAFE: line is modified */ - - /* skip whitespace */ - while (IS_WHITE(*line)) - line++; - - /* ignore comments or empty lines */ - if (*line == '#' || *line == '\0') - continue; - - /* strip away comments. pretty kludgy way really.. */ - for (p = line; *p != '\0'; p++) { - if (*p == '\'' || *p == '"') { - char quote = *p; - for (p++; *p != quote && *p != '\0'; p++) { - if (*p == '\\' && p[1] != '\0') - p++; - } - if (*p == '\0') - break; - } else if (*p == '#') { - *p = '\0'; - break; - } - } - - /* remove whitespace from end of line */ - len = strlen(line); - while (IS_WHITE(line[len-1])) - len--; - line[len] = '\0'; - - if (len > 0 && line[len-1] == '\\') { - /* continues in next line */ - line[len-1] = '\0'; - str_append(full_line, line); - continue; - } - if (str_len(full_line) > 0) { - str_append(full_line, line); - line = str_c_modifiable(full_line); - } - - /* a) key = value - b) section_type [section_name] { - c) } */ - key = line; - while (!IS_WHITE(*line) && *line != '\0' && *line != '=') - line++; - if (IS_WHITE(*line)) { - *line++ = '\0'; - while (IS_WHITE(*line)) line++; - } - - if (strcmp(key, "!include_try") == 0 || - strcmp(key, "!include") == 0) { - if (settings_include(&ctx, fix_relative_path(line, ctx.cur_input), - strcmp(key, "!include_try") == 0, - &errormsg) == 0) - goto prevfile; - } else if (*line == '=') { - /* a) */ - *line++ = '\0'; - while (IS_WHITE(*line)) line++; - - len = strlen(line); - if (len > 0 && - ((*line == '"' && line[len-1] == '"') || - (*line == '\'' && line[len-1] == '\''))) { - line[len-1] = '\0'; - line = str_unescape(line+1); - } - + type = config_parse_line(line, full_line, + &key, §ion, &value); + switch (type) { + case CONFIG_LINE_TYPE_SKIP: + break; + case CONFIG_LINE_TYPE_ERROR: + errormsg = value; + break; + case CONFIG_LINE_TYPE_KEYVALUE: str_truncate(str, pathlen); str_append(str, key); str_append_c(str, '='); - if (*line != '<' || !expand_files) - str_append(str, line); - else - str_append_file(str, key, line+1, &errormsg); - - if (errormsg != NULL) { + if (*value != '<' || !expand_files) + str_append(str, value); + else if (str_append_file(str, key, value+1, &errormsg) < 0) { /* file reading failed */ - } else { - errormsg = config_parse_line(parsers, key, str_c(str), NULL); - if (errormsg != NULL && pathlen == 0 && - strncmp(str_c(str), "auth_", 5) == 0) { - /* verify that the setting is valid, - but delay actually adding it */ - const char *s = t_strdup(str_c(str) + 5); - - str_truncate(str, 0); - str_printfa(str, "auth/0/%s=", key + 5); - if (*line != '<' || !expand_files) - str_append(str, line); - else - str_append_file(str, key, line+1, &errormsg); - - errormsg = config_parse_line(parsers, key + 5, str_c(str), NULL); - array_append(&auth_defaults, &s, 1); - } + break; } - } else if (strcmp(key, "}") != 0 || *line != '\0') { - /* b) + errors */ - line[-1] = '\0'; - if (*line == '{') - name = ""; - else { - name = line; - while (!IS_WHITE(*line) && *line != '\0') - line++; - - if (*line != '\0') { - *line++ = '\0'; - while (IS_WHITE(*line)) - line++; - } + if (config_apply_line(parsers, key, str_c(str), NULL, &errormsg) < 0 && + pathlen == 0 && strncmp(str_c(str), "auth_", 5) == 0) { + /* get auth_* settings working outside auth + sections. we'll verify that the setting is + valid, but delay actually adding it */ + const char *s = t_strdup(str_c(str) + 5); + + str_truncate(str, 0); + str_printfa(str, "auth/0/%s=", key + 5); + if (*value != '<' || !expand_files) + str_append(str, value); + else + str_append_file(str, key, value+1, &errormsg); + + if (config_apply_line(parsers, key + 5, str_c(str), NULL, &errormsg) < 0) + break; + array_append(&auth_defaults, &s, 1); } - - if (*line != '{') - errormsg = "Expecting '='"; - + break; + case CONFIG_LINE_TYPE_SECTION_BEGIN: config_add_new_filter(&ctx); ctx.cur_filter->pathlen = pathlen; if (strcmp(key, "protocol") == 0) { ctx.cur_filter->filter.service = - p_strdup(ctx.pool, name); + p_strdup(ctx.pool, section); config_add_new_parser(&ctx); parsers = config_update_cur_parsers(&ctx); } else if (strcmp(key, "local_ip") == 0) { - if (net_parse_range(name, &ctx.cur_filter->filter.local_net, + if (net_parse_range(section, &ctx.cur_filter->filter.local_net, &ctx.cur_filter->filter.local_bits) < 0) errormsg = "Invalid network mask"; config_add_new_parser(&ctx); parsers = config_update_cur_parsers(&ctx); } else if (strcmp(key, "remote_ip") == 0) { - if (net_parse_range(name, &ctx.cur_filter->filter.remote_net, + if (net_parse_range(section, &ctx.cur_filter->filter.remote_net, &ctx.cur_filter->filter.remote_bits) < 0) errormsg = "Invalid network mask"; config_add_new_parser(&ctx); @@ -569,7 +616,7 @@ prevfile: if (strcmp(key, "auth") == 0) { cur_counter = auth_counter++; - if (cur_counter == 0 && strcmp(name, "default") != 0) + if (cur_counter == 0 && strcmp(section, "default") != 0) cur_counter = auth_counter++; } else { cur_counter = counter++; @@ -581,7 +628,8 @@ prevfile: if (cur_counter == 0 && strcmp(key, "auth") == 0) { /* already added this */ } else { - errormsg = config_parse_line(parsers, key, str_c(str), name); + if (config_apply_line(parsers, key, str_c(str), section, &errormsg) < 0) + break; } str_truncate(str, pathlen); @@ -590,7 +638,7 @@ prevfile: str_append_c(str, SETTINGS_SEPARATOR); pathlen = str_len(str); - if (strcmp(key, "auth") == 0 && errormsg == NULL) { + if (strcmp(key, "auth") == 0) { /* add auth default settings */ const char *const *lines; unsigned int i, count; @@ -602,13 +650,13 @@ prevfile: p = strchr(lines[i], '='); str_append(str, lines[i]); - errormsg = config_parse_line(parsers, t_strdup_until(lines[i], p), str_c(str), NULL); - i_assert(errormsg == NULL); + if (config_apply_line(parsers, t_strdup_until(lines[i], p), str_c(str), NULL, &errormsg) < 0) + i_unreached(); } } } - } else { - /* c) */ + break; + case CONFIG_LINE_TYPE_SECTION_END: if (ctx.cur_filter->prev == NULL) errormsg = "Unexpected '}'"; else { @@ -616,6 +664,13 @@ prevfile: ctx.cur_filter = ctx.cur_filter->prev; parsers = config_update_cur_parsers(&ctx); } + break; + case CONFIG_LINE_TYPE_INCLUDE: + case CONFIG_LINE_TYPE_INCLUDE_TRY: + (void)settings_include(&ctx, fix_relative_path(value, ctx.cur_input), + type == CONFIG_LINE_TYPE_INCLUDE_TRY, + &errormsg); + break; } if (errormsg != NULL) {