diff options
Diffstat (limited to 'src/libstrongswan/settings.c')
-rw-r--r-- | src/libstrongswan/settings.c | 855 |
1 files changed, 855 insertions, 0 deletions
diff --git a/src/libstrongswan/settings.c b/src/libstrongswan/settings.c index d85abb1df..c16c6a1f1 100644 --- a/src/libstrongswan/settings.c +++ b/src/libstrongswan/settings.c @@ -1,4 +1,8 @@ /* +<<<<<<< HEAD +======= + * Copyright (C) 2010 Tobias Brunner +>>>>>>> upstream/4.5.1 * Copyright (C) 2008 Martin Willi * Hochschule fuer Technik Rapperswil * @@ -18,12 +22,24 @@ #include <stdarg.h> #include <stdio.h> #include <errno.h> +<<<<<<< HEAD +======= +#include <limits.h> +#include <glob.h> +#include <libgen.h> +>>>>>>> upstream/4.5.1 #include "settings.h" #include "debug.h" #include "utils/linked_list.h" +<<<<<<< HEAD +======= +#include "threading/rwlock.h" + +#define MAX_INCLUSION_LEVEL 10 +>>>>>>> upstream/4.5.1 typedef struct private_settings_t private_settings_t; typedef struct section_t section_t; @@ -45,9 +61,20 @@ struct private_settings_t { section_t *top; /** +<<<<<<< HEAD * allocated file text */ char *text; +======= + * contents of loaded files and in-memory settings (char*) + */ + linked_list_t *contents; + + /** + * lock to safely access the settings + */ + rwlock_t *lock; +>>>>>>> upstream/4.5.1 }; /** @@ -88,6 +115,72 @@ struct kv_t { }; /** +<<<<<<< HEAD +======= + * create a key/value pair + */ +static kv_t *kv_create(char *key, char *value) +{ + kv_t *this; + INIT(this, + .key = strdup(key), + .value = value, + ); + return this; +} + +/** + * destroy a key/value pair + */ +static void kv_destroy(kv_t *this) +{ + free(this->key); + free(this); +} + +/** + * create a section with the given name + */ +static section_t *section_create(char *name) +{ + section_t *this; + INIT(this, + .name = strdupnull(name), + .sections = linked_list_create(), + .kv = linked_list_create(), + ); + return this; +} + +/** + * destroy a section + */ +static void section_destroy(section_t *this) +{ + this->kv->destroy_function(this->kv, (void*)kv_destroy); + this->sections->destroy_function(this->sections, (void*)section_destroy); + free(this->name); + free(this); +} + +/** + * callback to find a section by name + */ +static bool section_find(section_t *this, char *name) +{ + return streq(this->name, name); +} + +/** + * callback to find a kv pair by key + */ +static bool kv_find(kv_t *this, char *key) +{ + return streq(this->key, key); +} + +/** +>>>>>>> upstream/4.5.1 * Print a format key, but consume already processed arguments */ static bool print_key(char *buf, int len, char *start, char *key, va_list args) @@ -136,6 +229,7 @@ static bool print_key(char *buf, int len, char *start, char *key, va_list args) } /** +<<<<<<< HEAD * find a section by a given key, using buffered key, reusable buffer */ static section_t *find_section_buffered(section_t *section, @@ -144,6 +238,17 @@ static section_t *find_section_buffered(section_t *section, char *pos; enumerator_t *enumerator; section_t *current, *found = NULL; +======= + * Find a section by a given key, using buffered key, reusable buffer. + * If "ensure" is TRUE, the sections are created if they don't exist. + */ +static section_t *find_section_buffered(section_t *section, + char *start, char *key, va_list args, char *buf, int len, + bool ensure) +{ + char *pos; + section_t *found = NULL; +>>>>>>> upstream/4.5.1 if (section == NULL) { @@ -159,6 +264,7 @@ static section_t *find_section_buffered(section_t *section, { return NULL; } +<<<<<<< HEAD enumerator = section->sections->create_enumerator(section->sections); while (enumerator->enumerate(enumerator, ¤t)) { @@ -172,21 +278,47 @@ static section_t *find_section_buffered(section_t *section, if (found && pos) { return find_section_buffered(found, start, pos, args, buf, len); +======= + if (section->sections->find_first(section->sections, + (linked_list_match_t)section_find, + (void**)&found, buf) != SUCCESS) + { + if (ensure) + { + found = section_create(buf); + section->sections->insert_last(section->sections, found); + } + } + if (found && pos) + { + return find_section_buffered(found, start, pos, args, buf, len, ensure); +>>>>>>> upstream/4.5.1 } return found; } /** +<<<<<<< HEAD * find a section by a given key */ static section_t *find_section(section_t *section, char *key, va_list args) { char buf[128], keybuf[512]; +======= + * Find a section by a given key (thread-safe). + */ +static section_t *find_section(private_settings_t *this, section_t *section, + char *key, va_list args) +{ + char buf[128], keybuf[512]; + section_t *found; +>>>>>>> upstream/4.5.1 if (snprintf(keybuf, sizeof(keybuf), "%s", key) >= sizeof(keybuf)) { return NULL; } +<<<<<<< HEAD return find_section_buffered(section, keybuf, keybuf, args, buf, sizeof(buf)); } @@ -200,6 +332,47 @@ static char *find_value_buffered(section_t *section, enumerator_t *enumerator; kv_t *kv; section_t *current, *found = NULL; +======= + this->lock->read_lock(this->lock); + found = find_section_buffered(section, keybuf, keybuf, args, buf, + sizeof(buf), FALSE); + this->lock->unlock(this->lock); + return found; +} + +/** + * Ensure that the section with the given key exists (thread-safe). + */ +static section_t *ensure_section(private_settings_t *this, section_t *section, + char *key, va_list args) +{ + char buf[128], keybuf[512]; + section_t *found; + + if (snprintf(keybuf, sizeof(keybuf), "%s", key) >= sizeof(keybuf)) + { + return NULL; + } + /* we might have to change the tree */ + this->lock->write_lock(this->lock); + found = find_section_buffered(section, keybuf, keybuf, args, buf, + sizeof(buf), TRUE); + this->lock->unlock(this->lock); + return found; +} + +/** + * Find the key/value pair for a key, using buffered key, reusable buffer + * If "ensure" is TRUE, the sections (and key/value pair) are created if they + * don't exist. + */ +static kv_t *find_value_buffered(section_t *section, char *start, char *key, + va_list args, char *buf, int len, bool ensure) +{ + char *pos; + kv_t *kv = NULL; + section_t *found = NULL; +>>>>>>> upstream/4.5.1 if (section == NULL) { @@ -216,6 +389,7 @@ static char *find_value_buffered(section_t *section, { return NULL; } +<<<<<<< HEAD enumerator = section->sections->create_enumerator(section->sections); while (enumerator->enumerate(enumerator, ¤t)) { @@ -230,6 +404,21 @@ static char *find_value_buffered(section_t *section, { return find_value_buffered(found, start, pos, args, buf, len); } +======= + if (section->sections->find_first(section->sections, + (linked_list_match_t)section_find, + (void**)&found, buf) != SUCCESS) + { + if (!ensure) + { + return NULL; + } + found = section_create(buf); + section->sections->insert_last(section->sections, found); + } + return find_value_buffered(found, start, pos, args, buf, len, + ensure); +>>>>>>> upstream/4.5.1 } else { @@ -237,6 +426,7 @@ static char *find_value_buffered(section_t *section, { return NULL; } +<<<<<<< HEAD enumerator = section->kv->create_enumerator(section->kv); while (enumerator->enumerate(enumerator, &kv)) { @@ -257,11 +447,35 @@ static char *find_value_buffered(section_t *section, static char *find_value(section_t *section, char *key, va_list args) { char buf[128], keybuf[512]; +======= + if (section->kv->find_first(section->kv, (linked_list_match_t)kv_find, + (void**)&kv, buf) != SUCCESS) + { + if (ensure) + { + kv = kv_create(buf, NULL); + section->kv->insert_last(section->kv, kv); + } + } + } + return kv; +} + +/** + * Find the string value for a key (thread-safe). + */ +static char *find_value(private_settings_t *this, section_t *section, + char *key, va_list args) +{ + char buf[128], keybuf[512], *value = NULL; + kv_t *kv; +>>>>>>> upstream/4.5.1 if (snprintf(keybuf, sizeof(keybuf), "%s", key) >= sizeof(keybuf)) { return NULL; } +<<<<<<< HEAD return find_value_buffered(section, keybuf, keybuf, args, buf, sizeof(buf)); } @@ -269,12 +483,66 @@ static char *find_value(section_t *section, char *key, va_list args) * Implementation of settings_t.get. */ static char* get_str(private_settings_t *this, char *key, char *def, ...) +======= + this->lock->read_lock(this->lock); + kv = find_value_buffered(section, keybuf, keybuf, args, buf, sizeof(buf), + FALSE); + if (kv) + { + value = kv->value; + } + this->lock->unlock(this->lock); + return value; +} + +/** + * Set a value to a copy of the given string (thread-safe). + */ +static void set_value(private_settings_t *this, section_t *section, + char *key, va_list args, char *value) +{ + char buf[128], keybuf[512]; + kv_t *kv; + + if (snprintf(keybuf, sizeof(keybuf), "%s", key) >= sizeof(keybuf)) + { + return; + } + this->lock->write_lock(this->lock); + kv = find_value_buffered(section, keybuf, keybuf, args, buf, sizeof(buf), + TRUE); + if (kv) + { + if (!value) + { + kv->value = NULL; + } + else if (kv->value && (strlen(value) <= strlen(kv->value))) + { /* overwrite in-place, if possible */ + strcpy(kv->value, value); + } + else + { /* otherwise clone the string and store it in the cache */ + kv->value = strdup(value); + this->contents->insert_last(this->contents, kv->value); + } + } + this->lock->unlock(this->lock); +} + +METHOD(settings_t, get_str, char*, + private_settings_t *this, char *key, char *def, ...) +>>>>>>> upstream/4.5.1 { char *value; va_list args; va_start(args, def); +<<<<<<< HEAD value = find_value(this->top, key, args); +======= + value = find_value(this, this->top, key, args); +>>>>>>> upstream/4.5.1 va_end(args); if (value) { @@ -284,6 +552,7 @@ static char* get_str(private_settings_t *this, char *key, char *def, ...) } /** +<<<<<<< HEAD * Implementation of settings_t.get_bool. */ static bool get_bool(private_settings_t *this, char *key, bool def, ...) @@ -307,6 +576,25 @@ static bool get_bool(private_settings_t *this, char *key, bool def, ...) strcaseeq(value, "disabled") || strcaseeq(value, "no") || strcaseeq(value, "0")) +======= + * Described in header + */ +inline bool settings_value_as_bool(char *value, bool def) +{ + if (value) + { + if (strcaseeq(value, "1") || + strcaseeq(value, "yes") || + strcaseeq(value, "true") || + strcaseeq(value, "enabled")) + { + return TRUE; + } + else if (strcaseeq(value, "0") || + strcaseeq(value, "no") || + strcaseeq(value, "false") || + strcaseeq(value, "disabled")) +>>>>>>> upstream/4.5.1 { return FALSE; } @@ -314,6 +602,7 @@ static bool get_bool(private_settings_t *this, char *key, bool def, ...) return def; } +<<<<<<< HEAD /** * Implementation of settings_t.get_int. */ @@ -326,6 +615,26 @@ static int get_int(private_settings_t *this, char *key, int def, ...) va_start(args, def); value = find_value(this->top, key, args); va_end(args); +======= +METHOD(settings_t, get_bool, bool, + private_settings_t *this, char *key, bool def, ...) +{ + char *value; + va_list args; + + va_start(args, def); + value = find_value(this, this->top, key, args); + va_end(args); + return settings_value_as_bool(value, def); +} + +/** + * Described in header + */ +inline int settings_value_as_int(char *value, int def) +{ + int intval; +>>>>>>> upstream/4.5.1 if (value) { errno = 0; @@ -338,6 +647,7 @@ static int get_int(private_settings_t *this, char *key, int def, ...) return def; } +<<<<<<< HEAD /** * Implementation of settings_t.get_double. */ @@ -350,6 +660,26 @@ static double get_double(private_settings_t *this, char *key, double def, ...) va_start(args, def); value = find_value(this->top, key, args); va_end(args); +======= +METHOD(settings_t, get_int, int, + private_settings_t *this, char *key, int def, ...) +{ + char *value; + va_list args; + + va_start(args, def); + value = find_value(this, this->top, key, args); + va_end(args); + return settings_value_as_int(value, def); +} + +/** + * Described in header + */ +inline double settings_value_as_double(char *value, double def) +{ + double dval; +>>>>>>> upstream/4.5.1 if (value) { errno = 0; @@ -362,6 +692,7 @@ static double get_double(private_settings_t *this, char *key, double def, ...) return def; } +<<<<<<< HEAD /** * Implementation of settings_t.get_time. */ @@ -374,6 +705,27 @@ static u_int32_t get_time(private_settings_t *this, char *key, u_int32_t def, .. va_start(args, def); value = find_value(this->top, key, args); va_end(args); +======= +METHOD(settings_t, get_double, double, + private_settings_t *this, char *key, double def, ...) +{ + char *value; + va_list args; + + va_start(args, def); + value = find_value(this, this->top, key, args); + va_end(args); + return settings_value_as_double(value, def); +} + +/** + * Described in header + */ +inline u_int32_t settings_value_as_time(char *value, u_int32_t def) +{ + char *endptr; + u_int32_t timeval; +>>>>>>> upstream/4.5.1 if (value) { errno = 0; @@ -392,7 +744,11 @@ static u_int32_t get_time(private_settings_t *this, char *key, u_int32_t def, .. timeval *= 60; break; case 's': /* time in seconds */ +<<<<<<< HEAD default: +======= + default: +>>>>>>> upstream/4.5.1 break; } return timeval; @@ -401,6 +757,78 @@ static u_int32_t get_time(private_settings_t *this, char *key, u_int32_t def, .. return def; } +<<<<<<< HEAD +======= +METHOD(settings_t, get_time, u_int32_t, + private_settings_t *this, char *key, u_int32_t def, ...) +{ + char *value; + va_list args; + + va_start(args, def); + value = find_value(this, this->top, key, args); + va_end(args); + return settings_value_as_time(value, def); +} + +METHOD(settings_t, set_str, void, + private_settings_t *this, char *key, char *value, ...) +{ + va_list args; + va_start(args, value); + set_value(this, this->top, key, args, value); + va_end(args); +} + +METHOD(settings_t, set_bool, void, + private_settings_t *this, char *key, bool value, ...) +{ + va_list args; + va_start(args, value); + set_value(this, this->top, key, args, value ? "1" : "0"); + va_end(args); +} + +METHOD(settings_t, set_int, void, + private_settings_t *this, char *key, int value, ...) +{ + char val[16]; + va_list args; + va_start(args, value); + if (snprintf(val, sizeof(val), "%d", value) < sizeof(val)) + { + set_value(this, this->top, key, args, val); + } + va_end(args); +} + +METHOD(settings_t, set_double, void, + private_settings_t *this, char *key, double value, ...) +{ + char val[64]; + va_list args; + va_start(args, value); + if (snprintf(val, sizeof(val), "%f", value) < sizeof(val)) + { + set_value(this, this->top, key, args, val); + } + va_end(args); +} + +METHOD(settings_t, set_time, void, + private_settings_t *this, char *key, u_int32_t value, ...) +{ + char val[16]; + va_list args; + va_start(args, value); + if (snprintf(val, sizeof(val), "%u", value) < sizeof(val)) + { + set_value(this, this->top, key, args, val); + } + va_end(args); +} + +>>>>>>> upstream/4.5.1 /** * Enumerate section names, not sections */ @@ -410,26 +838,42 @@ static bool section_filter(void *null, section_t **in, char **out) return TRUE; } +<<<<<<< HEAD /** * Implementation of settings_t.create_section_enumerator */ static enumerator_t* create_section_enumerator(private_settings_t *this, char *key, ...) +======= +METHOD(settings_t, create_section_enumerator, enumerator_t*, + private_settings_t *this, char *key, ...) +>>>>>>> upstream/4.5.1 { section_t *section; va_list args; va_start(args, key); +<<<<<<< HEAD section = find_section(this->top, key, args); +======= + section = find_section(this, this->top, key, args); +>>>>>>> upstream/4.5.1 va_end(args); if (!section) { return enumerator_create_empty(); } +<<<<<<< HEAD return enumerator_create_filter( section->sections->create_enumerator(section->sections), (void*)section_filter, NULL, NULL); +======= + this->lock->read_lock(this->lock); + return enumerator_create_filter( + section->sections->create_enumerator(section->sections), + (void*)section_filter, this->lock, (void*)this->lock->unlock); +>>>>>>> upstream/4.5.1 } /** @@ -443,23 +887,33 @@ static bool kv_filter(void *null, kv_t **in, char **key, return TRUE; } +<<<<<<< HEAD /** * Implementation of settings_t.create_key_value_enumerator */ static enumerator_t* create_key_value_enumerator(private_settings_t *this, char *key, ...) +======= +METHOD(settings_t, create_key_value_enumerator, enumerator_t*, + private_settings_t *this, char *key, ...) +>>>>>>> upstream/4.5.1 { section_t *section; va_list args; va_start(args, key); +<<<<<<< HEAD section = find_section(this->top, key, args); +======= + section = find_section(this, this->top, key, args); +>>>>>>> upstream/4.5.1 va_end(args); if (!section) { return enumerator_create_empty(); } +<<<<<<< HEAD return enumerator_create_filter( section->kv->create_enumerator(section->kv), (void*)kv_filter, NULL, NULL); @@ -474,6 +928,12 @@ static void section_destroy(section_t *this) this->sections->destroy_function(this->sections, (void*)section_destroy); free(this); +======= + this->lock->read_lock(this->lock); + return enumerator_create_filter( + section->kv->create_enumerator(section->kv), + (void*)kv_filter, this->lock, (void*)this->lock->unlock); +>>>>>>> upstream/4.5.1 } /** @@ -551,6 +1011,7 @@ static char parse(char **text, char *skip, char *term, char *br, char **token) } /** +<<<<<<< HEAD * Parse a section */ static section_t* parse_section(char **text, char *name) @@ -569,27 +1030,152 @@ static section_t* parse_section(char **text, char *name) while (!finished) { +======= + * Check if "text" starts with "pattern". + * Characters in "skip" are skipped first. If found, TRUE is returned and "text" + * is modified to point to the character right after "pattern". + */ +static bool starts_with(char **text, char *skip, char *pattern) +{ + char *pos = *text; + int len = strlen(pattern); + while (strchr(skip, *pos)) + { + pos++; + if (!*pos) + { + return FALSE; + } + } + if (strlen(pos) < len || !strneq(pos, pattern, len)) + { + return FALSE; + } + *text = pos + len; + return TRUE; +} + +/** + * Check if what follows in "text" is an include statement. + * If this function returns TRUE, "text" will point to the character right after + * the include pattern, which is returned in "pattern". + */ +static bool parse_include(char **text, char **pattern) +{ + char *pos = *text; + if (!starts_with(&pos, "\n\t ", "include")) + { + return FALSE; + } + if (starts_with(&pos, "\t ", "=")) + { /* ignore "include = value" */ + return FALSE; + } + *text = pos; + return parse(text, "\t ", "\n", NULL, pattern) != 0; +} + +/** + * Forward declaration. + */ +static bool parse_files(linked_list_t *contents, char *file, int level, + char *pattern, section_t *section); + +/** + * Parse a section + */ +static bool parse_section(linked_list_t *contents, char *file, int level, + char **text, section_t *section) +{ + bool finished = FALSE; + char *key, *value, *inner; + + while (!finished) + { + if (parse_include(text, &value)) + { + if (!parse_files(contents, file, level, value, section)) + { + DBG1(DBG_LIB, "failed to include '%s'", value); + return FALSE; + } + continue; + } +>>>>>>> upstream/4.5.1 switch (parse(text, "\t\n ", "{=#", NULL, &key)) { case '{': if (parse(text, "\t ", "}", "{", &inner)) { +<<<<<<< HEAD sub = parse_section(&inner, key); if (sub) { section->sections->insert_last(section->sections, sub); continue; } +======= + section_t *sub; + if (!strlen(key)) + { + DBG1(DBG_LIB, "skipping section without name in '%s'", + section->name); + continue; + } + if (section->sections->find_first(section->sections, + (linked_list_match_t)section_find, + (void**)&sub, key) != SUCCESS) + { + sub = section_create(key); + if (parse_section(contents, file, level, &inner, sub)) + { + section->sections->insert_last(section->sections, + sub); + continue; + } + section_destroy(sub); + } + else + { /* extend the existing section */ + if (parse_section(contents, file, level, &inner, sub)) + { + continue; + } + } + DBG1(DBG_LIB, "parsing subsection '%s' failed", key); + break; +>>>>>>> upstream/4.5.1 } DBG1(DBG_LIB, "matching '}' not found near %s", *text); break; case '=': if (parse(text, "\t ", "\n", NULL, &value)) { +<<<<<<< HEAD kv_t *kv = malloc_thing(kv_t); kv->key = key; kv->value = value; section->kv->insert_last(section->kv, kv); +======= + kv_t *kv; + if (!strlen(key)) + { + DBG1(DBG_LIB, "skipping value without key in '%s'", + section->name); + continue; + } + if (section->kv->find_first(section->kv, + (linked_list_match_t)kv_find, + (void**)&kv, key) != SUCCESS) + { + kv = kv_create(key, value); + section->kv->insert_last(section->kv, kv); + } + else + { /* replace with the most recently read value */ + kv->value = value; + } +>>>>>>> upstream/4.5.1 continue; } DBG1(DBG_LIB, "parsing value failed near %s", *text); @@ -601,6 +1187,7 @@ static section_t* parse_section(char **text, char *name) finished = TRUE; continue; } +<<<<<<< HEAD section_destroy(section); return NULL; } @@ -673,6 +1260,274 @@ settings_t *settings_create(char *file) free(this->text); this->text = NULL; } +======= + return FALSE; + } + return TRUE; +} + +/** + * Parse a file and add the settings to the given section. + */ +static bool parse_file(linked_list_t *contents, char *file, int level, + section_t *section) +{ + bool success; + char *text, *pos; + FILE *fd; + int len; + + DBG2(DBG_LIB, "loading config file '%s'", file); + fd = fopen(file, "r"); + if (fd == NULL) + { + DBG1(DBG_LIB, "'%s' does not exist or is not readable", file); + return FALSE; + } + fseek(fd, 0, SEEK_END); + len = ftell(fd); + rewind(fd); + text = malloc(len + 1); + text[len] = '\0'; + if (fread(text, 1, len, fd) != len) + { + free(text); + return FALSE; + } + fclose(fd); + + pos = text; + success = parse_section(contents, file, level, &pos, section); + if (!success) + { + free(text); + } + else + { + contents->insert_last(contents, text); + } + return success; +} + +/** + * Load the files matching "pattern", which is resolved with glob(3). + * If the pattern is relative, the directory of "file" is used as base. + */ +static bool parse_files(linked_list_t *contents, char *file, int level, + char *pattern, section_t *section) +{ + bool success = TRUE; + int status; + glob_t buf; + char **expanded, pat[PATH_MAX]; + + if (level > MAX_INCLUSION_LEVEL) + { + DBG1(DBG_LIB, "maximum level of %d includes reached, ignored", + MAX_INCLUSION_LEVEL); + return TRUE; + } + + if (!strlen(pattern)) + { + DBG2(DBG_LIB, "empty include pattern, ignored"); + return TRUE; + } + + if (!file || pattern[0] == '/') + { /* absolute path */ + if (snprintf(pat, sizeof(pat), "%s", pattern) >= sizeof(pat)) + { + DBG1(DBG_LIB, "include pattern too long, ignored"); + return TRUE; + } + } + else + { /* base relative paths to the directory of the current file */ + char *dir = strdup(file); + dir = dirname(dir); + if (snprintf(pat, sizeof(pat), "%s/%s", dir, pattern) >= sizeof(pat)) + { + DBG1(DBG_LIB, "include pattern too long, ignored"); + free(dir); + return TRUE; + } + free(dir); + } + status = glob(pat, GLOB_ERR, NULL, &buf); + if (status == GLOB_NOMATCH) + { + DBG2(DBG_LIB, "no files found matching '%s', ignored", pat); + } + else if (status != 0) + { + DBG1(DBG_LIB, "expanding file pattern '%s' failed", pat); + success = FALSE; + } + else + { + for (expanded = buf.gl_pathv; *expanded != NULL; expanded++) + { + success &= parse_file(contents, *expanded, level + 1, section); + if (!success) + { + break; + } + } + } + globfree(&buf); + return success; +} + +/** + * Recursivly extends "base" with "extension". + */ +static void section_extend(section_t *base, section_t *extension) +{ + enumerator_t *enumerator; + section_t *sec; + kv_t *kv; + + enumerator = extension->sections->create_enumerator(extension->sections); + while (enumerator->enumerate(enumerator, (void**)&sec)) + { + section_t *found; + if (base->sections->find_first(base->sections, + (linked_list_match_t)section_find, (void**)&found, + sec->name) == SUCCESS) + { + section_extend(found, sec); + } + else + { + extension->sections->remove_at(extension->sections, enumerator); + base->sections->insert_last(base->sections, sec); + } + } + enumerator->destroy(enumerator); + + enumerator = extension->kv->create_enumerator(extension->kv); + while (enumerator->enumerate(enumerator, (void**)&kv)) + { + kv_t *found; + if (base->kv->find_first(base->kv, (linked_list_match_t)kv_find, + (void**)&found, kv->key) == SUCCESS) + { + found->value = kv->value; + } + else + { + extension->kv->remove_at(extension->kv, enumerator); + base->kv->insert_last(base->kv, kv); + } + } + enumerator->destroy(enumerator); +} + +/** + * Load settings from files matching the given file pattern. + * All sections and values are added relative to "parent". + * All files (even included ones) have to be loaded successfully. + */ +static bool load_files_internal(private_settings_t *this, section_t *parent, + char *pattern) +{ + char *text; + linked_list_t *contents = linked_list_create(); + section_t *section = section_create(NULL); + + if (!parse_files(contents, NULL, 0, pattern, section)) + { + contents->destroy_function(contents, (void*)free); + section_destroy(section); + return FALSE; + } + + this->lock->write_lock(this->lock); + /* extend parent section */ + section_extend(parent, section); + /* move contents of loaded files to main store */ + while (contents->remove_first(contents, (void**)&text) == SUCCESS) + { + this->contents->insert_last(this->contents, text); + } + this->lock->unlock(this->lock); + + section_destroy(section); + contents->destroy(contents); + return TRUE; +} + +METHOD(settings_t, load_files, bool, + private_settings_t *this, char *pattern) +{ + return load_files_internal(this, this->top, pattern); +} + +METHOD(settings_t, load_files_section, bool, + private_settings_t *this, char *pattern, char *key, ...) +{ + section_t *section; + va_list args; + + va_start(args, key); + section = ensure_section(this, this->top, key, args); + va_end(args); + + if (!section) + { + return FALSE; + } + return load_files_internal(this, section, pattern); +} + +METHOD(settings_t, destroy, void, + private_settings_t *this) +{ + section_destroy(this->top); + this->contents->destroy_function(this->contents, (void*)free); + this->lock->destroy(this->lock); + free(this); +} + +/* + * see header file + */ +settings_t *settings_create(char *file) +{ + private_settings_t *this; + + INIT(this, + .public = { + .get_str = _get_str, + .get_int = _get_int, + .get_double = _get_double, + .get_time = _get_time, + .get_bool = _get_bool, + .set_str = _set_str, + .set_int = _set_int, + .set_double = _set_double, + .set_time = _set_time, + .set_bool = _set_bool, + .create_section_enumerator = _create_section_enumerator, + .create_key_value_enumerator = _create_key_value_enumerator, + .load_files = _load_files, + .load_files_section = _load_files_section, + .destroy = _destroy, + }, + .top = section_create(NULL), + .contents = linked_list_create(), + .lock = rwlock_create(RWLOCK_TYPE_DEFAULT), + ); + + if (file == NULL) + { + file = STRONGSWAN_CONF; + } + + load_files(this, file); + +>>>>>>> upstream/4.5.1 return &this->public; } |