summaryrefslogtreecommitdiff
path: root/src/libstrongswan/settings.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstrongswan/settings.c')
-rw-r--r--src/libstrongswan/settings.c855
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, &current))
{
@@ -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, &current))
{
@@ -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;
}