config-parser.c revision 8cea8e2b699970cb7cf4d1a8b4c48a855219e9e9
/* Copyright (C) 2005-2009 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
#include "str.h"
#include "hash.h"
#include "strescape.h"
#include "istream.h"
#include "module-dir.h"
#include "settings-parser.h"
#include "service-settings.h"
#include "all-settings.h"
#include "config-filter.h"
#include "config-parser.h"
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#ifdef HAVE_GLOB_H
# include <glob.h>
#endif
#ifndef GLOB_BRACE
# define GLOB_BRACE 0
#endif
struct config_section_stack {
struct config_section_stack *prev;
struct config_filter filter;
/* root=NULL-terminated list of parsers */
struct config_module_parser *parsers;
unsigned int pathlen;
};
struct input_stack {
struct input_stack *prev;
const char *path;
unsigned int linenum;
};
struct parser_context {
const char *path;
struct config_module_parser *root_parsers;
struct config_section_stack *cur_section;
struct input_stack *cur_input;
struct config_filter_context *filter;
};
static const enum settings_parser_flags settings_parser_flags =
struct config_filter_context *config_filter;
{
unsigned int i;
}
i_panic("setting parser: Invalid type_offset value");
return NULL;
}
const char *line, const char *section_name)
{
const struct setting_parser_info *info;
const char *p;
int ret;
return;
}
static int
const char *line, const char *section_name,
const char **error_r)
{
struct config_module_parser *l;
int ret;
if (ret > 0) {
if (section_name != NULL)
} else if (ret < 0) {
return -1;
}
}
if (!found) {
return -1;
}
return 0;
}
static const char *
{
const char *p;
if (*path == '/')
return path;
if (p == NULL)
return path;
}
static struct config_module_parser *
{
struct config_module_parser *dest;
unsigned int i, count;
for (i = 0; i < count; i++) {
}
return dest;
}
static void
{
struct config_filter_parser *parser;
} else {
}
}
static struct config_section_stack *
{
struct config_section_stack *section;
return section;
}
static struct config_filter_parser *
const struct config_filter *filter)
{
struct config_filter_parser *const *parsers;
return parser;
}
return NULL;
}
static int
{
const char *p;
unsigned int ip_count;
int ret;
return 0;
if (p != NULL) {
p++;
}
if (ret != 0) {
return -1;
}
else
return 0;
}
static bool
const char **error_r)
{
struct config_filter_parser *parser;
*error_r = "protocol must not be under protocol";
else
if (parent->remote_bits > 0)
*error_r = "local must not be under remote";
*error_r = "local must not be under protocol";
;
(parent->local_bits > 0 &&
parent->local_bits)))
*error_r = "local not a subset of parent local";
*error_r = "remote must not be under protocol";
&filter->remote_net,
;
(parent->remote_bits > 0 &&
&parent->remote_net,
parent->remote_bits)))
*error_r = "remote not a subset of parent remote";
} else {
return FALSE;
}
else
return TRUE;
}
static int
const struct config_module_parser *p,
const char **error_r)
{
return -1;
}
return 0;
}
static int
struct config_filter_context *new_filter,
const char **error_r)
{
struct config_filter_parser *const *parsers;
struct config_module_parser *tmp_parsers;
unsigned int i, count;
int ret = 0;
count--;
&tmp_parsers, error_r) < 0) {
ret = -1;
break;
}
}
return ret;
}
static int
const char **error_r)
{
unsigned char buf[1024];
int fd;
if (fd == -1) {
return -1;
}
if (ret < 0) {
}
return ret < 0 ? -1 : 0;
}
bool ignore_errors, const char **error_r)
{
int fd;
break;
}
return -1;
}
if (ignore_errors)
return 0;
path);
return -1;
}
return 0;
}
static int
bool ignore_errors, const char **error_r)
{
#ifdef HAVE_GLOB
unsigned int i;
case 0:
break;
case GLOB_NOSPACE:
*error_r = "glob() failed: Not enough memory";
return -1;
case GLOB_ABORTED:
*error_r = "glob() failed: Read error";
return -1;
case GLOB_NOMATCH:
if (ignore_errors)
return 0;
*error_r = "No matches";
return -1;
default:
*error_r = "glob() failed: Unknown error";
return -1;
}
/* iterate throuth the different files matching the globbing */
ignore_errors, error_r) < 0)
return -1;
}
return 0;
#else
#endif
}
enum config_line_type {
};
static enum config_line_type
{
const char *key;
unsigned int len;
char *p;
/* @UNSAFE: line is modified */
/* skip whitespace */
line++;
/* ignore comments or empty lines */
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 == '#') {
if (!IS_WHITE(p[-1])) {
i_warning("Configuration file %s line %u: "
"Ambiguous '#' character in line, treating it as comment. "
"Add a space before it to remove this warning.",
}
*p = '\0';
break;
}
}
/* remove whitespace from end of line */
len--;
/* continues in next line */
len--;
len--;
return CONFIG_LINE_TYPE_SKIP;
}
}
/* a) key = value
b) section_type [section_name] {
c) } */
line++;
*line++ = '\0';
}
return CONFIG_LINE_TYPE_INCLUDE;
return CONFIG_LINE_TYPE_INCLUDE_TRY;
if (*line == '=') {
/* a) */
*line++ = '\0';
if (*line == '<') {
return CONFIG_LINE_TYPE_KEYFILE;
}
if (len > 0 &&
}
return CONFIG_LINE_TYPE_KEYVALUE;
}
return CONFIG_LINE_TYPE_SECTION_END;
/* b) + errors */
if (*line == '{')
*value_r = "";
else {
/* get section name */
line++;
if (*line != '\0') {
*line++ = '\0';
line++;
}
if (*line != '{') {
*value_r = "Expecting '='";
return CONFIG_LINE_TYPE_ERROR;
}
*value_r = "Garbage after '{'";
return CONFIG_LINE_TYPE_ERROR;
}
}
return CONFIG_LINE_TYPE_SECTION_BEGIN;
}
{
struct config_filter_context *new_filter;
const char *error;
int ret;
}
if (config_filter != NULL)
return ret;
}
const char **error_r)
{
struct input_stack root;
struct parser_context ctx;
unsigned int pathlen = 0;
enum config_line_type type;
char *line;
if (fd < 0) {
return 0;
}
for (i = 0; i < count; i++) {
}
switch (type) {
case CONFIG_LINE_TYPE_SKIP:
break;
case CONFIG_LINE_TYPE_ERROR:
break;
case CONFIG_LINE_TYPE_KEYFILE:
if (type != CONFIG_LINE_TYPE_KEYFILE)
else if (!expand_files) {
/* file reading failed */
break;
}
break;
&errormsg)) {
/* new filter */
break;
}
/* new config section */
if (*value == '\0') {
/* no section name, use a counter */
} else {
}
break;
break;
errormsg = "Unexpected '}'";
else {
}
break;
case CONFIG_LINE_TYPE_INCLUDE:
&errormsg);
break;
}
"Error in configuration file %s line %d: %s",
errormsg);
ret = -2;
break;
}
str_truncate(full_line, 0);
}
goto prevfile;
if (ret == 0)
}
void config_parse_load_modules(void)
{
struct module_dir_load_settings mod_set;
const struct setting_parser_info **roots;
unsigned int i, count;
}
if (service_set != NULL)
}
if (array_count(&new_roots) > 0) {
/* modules added new settings. add the defaults and start
using the new list. */
(void)array_append_space(&new_roots);
}
if (array_count(&new_services) > 0) {
/* module added new services. update the defaults. */
for (i = 0; i < count; i++)
}
}