aboutsummaryrefslogtreecommitdiffstats
path: root/src/libstrongswan/utils/settings.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstrongswan/utils/settings.c')
-rw-r--r--src/libstrongswan/utils/settings.c154
1 files changed, 141 insertions, 13 deletions
diff --git a/src/libstrongswan/utils/settings.c b/src/libstrongswan/utils/settings.c
index c3ab52a0e..2727495f0 100644
--- a/src/libstrongswan/utils/settings.c
+++ b/src/libstrongswan/utils/settings.c
@@ -31,6 +31,7 @@
#include "settings.h"
+#include "collections/array.h"
#include "collections/linked_list.h"
#include "threading/rwlock.h"
#include "utils/debug.h"
@@ -78,6 +79,11 @@ struct section_t {
char *name;
/**
+ * fallback sections, as section_t
+ */
+ array_t *fallbacks;
+
+ /**
* subsections, as section_t
*/
linked_list_t *sections;
@@ -147,19 +153,45 @@ 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);
+ array_destroy(this->fallbacks);
free(this->name);
free(this);
}
+/*
+ * forward declaration
+ */
+static bool section_purge(section_t *this);
+
+/**
+ * Check if it is safe to remove the given section.
+ */
+static bool section_remove(section_t *this)
+{
+ if (section_purge(this))
+ {
+ return FALSE;
+ }
+ section_destroy(this);
+ return TRUE;
+}
+
/**
- * Purge contents of a section
+ * Purge contents of a section, returns TRUE if section has to be kept due to
+ * any subsections.
*/
-static void section_purge(section_t *this)
+static bool section_purge(section_t *this)
{
+ int count, removed;
+
this->kv->destroy_function(this->kv, (void*)kv_destroy);
this->kv = linked_list_create();
- this->sections->destroy_function(this->sections, (void*)section_destroy);
- this->sections = linked_list_create();
+ /* we ensure sections used as fallback, or configured with fallbacks (or
+ * having any such subsections) are not removed */
+ count = this->sections->get_count(this->sections);
+ removed = this->sections->remove(this->sections, NULL,
+ (void*)section_remove);
+ return this->fallbacks || removed < count;
}
/**
@@ -291,7 +323,7 @@ static section_t *find_section(private_settings_t *this, section_t *section,
* 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)
+ const char *key, va_list args)
{
char buf[128], keybuf[512];
section_t *found;
@@ -309,13 +341,72 @@ static section_t *ensure_section(private_settings_t *this, section_t *section,
}
/**
+ * Check if the given fallback section already exists
+ */
+static bool fallback_exists(section_t *section, section_t *fallback)
+{
+ if (section == fallback)
+ {
+ return TRUE;
+ }
+ else if (section->fallbacks)
+ {
+ section_t *existing;
+ int i;
+
+ for (i = 0; i < array_count(section->fallbacks); i++)
+ {
+ array_get(section->fallbacks, i, &existing);
+ if (existing == fallback)
+ {
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+/**
+ * Ensure that the section with the given key exists and add the given fallback
+ * section (thread-safe).
+ */
+static void add_fallback_to_section(private_settings_t *this,
+ section_t *section, const char *key, va_list args,
+ section_t *fallback)
+{
+ char buf[128], keybuf[512];
+ section_t *found;
+
+ if (snprintf(keybuf, sizeof(keybuf), "%s", key) >= sizeof(keybuf))
+ {
+ return;
+ }
+ this->lock->write_lock(this->lock);
+ found = find_section_buffered(section, keybuf, keybuf, args, buf,
+ sizeof(buf), TRUE);
+ if (!fallback_exists(found, fallback))
+ {
+ /* to ensure sections referred to as fallback are not purged, we create
+ * the array there too */
+ if (!fallback->fallbacks)
+ {
+ fallback->fallbacks = array_create(0, 0);
+ }
+ array_insert_create(&found->fallbacks, ARRAY_TAIL, fallback);
+ }
+ this->lock->unlock(this->lock);
+}
+
+/**
* 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.
+ * Fallbacks are only considered if "ensure" is FALSE.
*/
static kv_t *find_value_buffered(section_t *section, char *start, char *key,
va_list args, char *buf, int len, bool ensure)
{
+ int i;
char *pos;
kv_t *kv = NULL;
section_t *found = NULL;
@@ -329,12 +420,12 @@ static kv_t *find_value_buffered(section_t *section, char *start, char *key,
if (pos)
{
*pos = '\0';
- pos++;
-
if (!print_key(buf, len, start, key, args))
{
return NULL;
}
+ /* restore so we can retry for fallbacks */
+ *pos = '.';
if (!strlen(buf))
{
found = section;
@@ -343,15 +434,26 @@ static kv_t *find_value_buffered(section_t *section, char *start, char *key,
(linked_list_match_t)section_find,
(void**)&found, buf) != SUCCESS)
{
- if (!ensure)
+ if (ensure)
{
- return NULL;
+ found = section_create(buf);
+ section->sections->insert_last(section->sections, found);
+ }
+ }
+ if (found)
+ {
+ kv = find_value_buffered(found, start, pos+1, args, buf, len,
+ ensure);
+ }
+ if (!kv && !ensure && section->fallbacks)
+ {
+ for (i = 0; !kv && i < array_count(section->fallbacks); i++)
+ {
+ array_get(section->fallbacks, i, &found);
+ kv = find_value_buffered(found, start, key, args, buf, len,
+ ensure);
}
- found = section_create(buf);
- section->sections->insert_last(section->sections, found);
}
- return find_value_buffered(found, start, pos, args, buf, len,
- ensure);
}
else
{
@@ -367,6 +469,15 @@ static kv_t *find_value_buffered(section_t *section, char *start, char *key,
kv = kv_create(buf, NULL);
section->kv->insert_last(section->kv, kv);
}
+ else if (section->fallbacks)
+ {
+ for (i = 0; !kv && i < array_count(section->fallbacks); i++)
+ {
+ array_get(section->fallbacks, i, &found);
+ kv = find_value_buffered(found, start, key, args, buf, len,
+ ensure);
+ }
+ }
}
}
return kv;
@@ -727,6 +838,22 @@ METHOD(settings_t, create_key_value_enumerator, enumerator_t*,
(void*)kv_filter, this->lock, (void*)this->lock->unlock);
}
+METHOD(settings_t, add_fallback, void,
+ private_settings_t *this, const char *key, const char *fallback, ...)
+{
+ section_t *section;
+ va_list args;
+
+ /* find/create the fallback */
+ va_start(args, fallback);
+ section = ensure_section(this, this->top, fallback, args);
+ va_end(args);
+
+ va_start(args, fallback);
+ add_fallback_to_section(this, this->top, key, args, section);
+ va_end(args);
+}
+
/**
* parse text, truncate "skip" chars, delimited by term respecting brackets.
*
@@ -1235,6 +1362,7 @@ settings_t *settings_create(char *file)
.set_default_str = _set_default_str,
.create_section_enumerator = _create_section_enumerator,
.create_key_value_enumerator = _create_key_value_enumerator,
+ .add_fallback = _add_fallback,
.load_files = _load_files,
.load_files_section = _load_files_section,
.destroy = _destroy,