2 * Copyright (C) 2010 Tobias Brunner
3 * Copyright (C) 2008 Martin Willi
4 * Hochschule fuer Technik Rapperswil
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
24 #include <sys/types.h>
30 #endif /* HAVE_GLOB_H */
34 #include "collections/linked_list.h"
35 #include "threading/rwlock.h"
36 #include "utils/debug.h"
38 #define MAX_INCLUSION_LEVEL 10
40 typedef struct private_settings_t private_settings_t
;
41 typedef struct section_t section_t
;
42 typedef struct kv_t kv_t
;
45 * private data of settings
47 struct private_settings_t
{
60 * contents of loaded files and in-memory settings (char*)
62 linked_list_t
*contents
;
65 * lock to safely access the settings
71 * section containing subsections and key value pairs
81 * subsections, as section_t
83 linked_list_t
*sections
;
86 * key value pairs, as kv_t
97 * key string, relative
108 * create a key/value pair
110 static kv_t
*kv_create(char *key
, char *value
)
121 * destroy a key/value pair
123 static void kv_destroy(kv_t
*this)
130 * create a section with the given name
132 static section_t
*section_create(char *name
)
136 .name
= strdupnull(name
),
137 .sections
= linked_list_create(),
138 .kv
= linked_list_create(),
146 static void section_destroy(section_t
*this)
148 this->kv
->destroy_function(this->kv
, (void*)kv_destroy
);
149 this->sections
->destroy_function(this->sections
, (void*)section_destroy
);
155 * Purge contents of a section
157 static void section_purge(section_t
*this)
159 this->kv
->destroy_function(this->kv
, (void*)kv_destroy
);
160 this->kv
= linked_list_create();
161 this->sections
->destroy_function(this->sections
, (void*)section_destroy
);
162 this->sections
= linked_list_create();
166 * callback to find a section by name
168 static bool section_find(section_t
*this, char *name
)
170 return streq(this->name
, name
);
174 * callback to find a kv pair by key
176 static bool kv_find(kv_t
*this, char *key
)
178 return streq(this->key
, key
);
182 * Print a format key, but consume already processed arguments
184 static bool print_key(char *buf
, int len
, char *start
, char *key
, va_list args
)
193 pos
= strchr(start
, '%');
196 start
+= strlen(start
) + 1;
209 va_arg(copy
, enum_name_t
*);
215 DBG1(DBG_CFG
, "settings with %%%c not supported!", *pos
);
224 res
= vsnprintf(buf
, len
, key
, copy
) < len
;
230 * Find a section by a given key, using buffered key, reusable buffer.
231 * If "ensure" is TRUE, the sections are created if they don't exist.
233 static section_t
*find_section_buffered(section_t
*section
,
234 char *start
, char *key
, va_list args
, char *buf
, int len
,
238 section_t
*found
= NULL
;
244 pos
= strchr(key
, '.');
250 if (!print_key(buf
, len
, start
, key
, args
))
254 if (section
->sections
->find_first(section
->sections
,
255 (linked_list_match_t
)section_find
,
256 (void**)&found
, buf
) != SUCCESS
)
260 found
= section_create(buf
);
261 section
->sections
->insert_last(section
->sections
, found
);
266 return find_section_buffered(found
, start
, pos
, args
, buf
, len
, ensure
);
272 * Find a section by a given key (thread-safe).
274 static section_t
*find_section(private_settings_t
*this, section_t
*section
,
275 char *key
, va_list args
)
277 char buf
[128], keybuf
[512];
280 if (snprintf(keybuf
, sizeof(keybuf
), "%s", key
) >= sizeof(keybuf
))
284 this->lock
->read_lock(this->lock
);
285 found
= find_section_buffered(section
, keybuf
, keybuf
, args
, buf
,
287 this->lock
->unlock(this->lock
);
292 * Ensure that the section with the given key exists (thread-safe).
294 static section_t
*ensure_section(private_settings_t
*this, section_t
*section
,
295 char *key
, va_list args
)
297 char buf
[128], keybuf
[512];
300 if (snprintf(keybuf
, sizeof(keybuf
), "%s", key
) >= sizeof(keybuf
))
304 /* we might have to change the tree */
305 this->lock
->write_lock(this->lock
);
306 found
= find_section_buffered(section
, keybuf
, keybuf
, args
, buf
,
308 this->lock
->unlock(this->lock
);
313 * Find the key/value pair for a key, using buffered key, reusable buffer
314 * If "ensure" is TRUE, the sections (and key/value pair) are created if they
317 static kv_t
*find_value_buffered(section_t
*section
, char *start
, char *key
,
318 va_list args
, char *buf
, int len
, bool ensure
)
322 section_t
*found
= NULL
;
329 pos
= strchr(key
, '.');
335 if (!print_key(buf
, len
, start
, key
, args
))
339 if (section
->sections
->find_first(section
->sections
,
340 (linked_list_match_t
)section_find
,
341 (void**)&found
, buf
) != SUCCESS
)
347 found
= section_create(buf
);
348 section
->sections
->insert_last(section
->sections
, found
);
350 return find_value_buffered(found
, start
, pos
, args
, buf
, len
,
355 if (!print_key(buf
, len
, start
, key
, args
))
359 if (section
->kv
->find_first(section
->kv
, (linked_list_match_t
)kv_find
,
360 (void**)&kv
, buf
) != SUCCESS
)
364 kv
= kv_create(buf
, NULL
);
365 section
->kv
->insert_last(section
->kv
, kv
);
373 * Find the string value for a key (thread-safe).
375 static char *find_value(private_settings_t
*this, section_t
*section
,
376 char *key
, va_list args
)
378 char buf
[128], keybuf
[512], *value
= NULL
;
381 if (snprintf(keybuf
, sizeof(keybuf
), "%s", key
) >= sizeof(keybuf
))
385 this->lock
->read_lock(this->lock
);
386 kv
= find_value_buffered(section
, keybuf
, keybuf
, args
, buf
, sizeof(buf
),
392 this->lock
->unlock(this->lock
);
397 * Set a value to a copy of the given string (thread-safe).
399 static void set_value(private_settings_t
*this, section_t
*section
,
400 char *key
, va_list args
, char *value
)
402 char buf
[128], keybuf
[512];
405 if (snprintf(keybuf
, sizeof(keybuf
), "%s", key
) >= sizeof(keybuf
))
409 this->lock
->write_lock(this->lock
);
410 kv
= find_value_buffered(section
, keybuf
, keybuf
, args
, buf
, sizeof(buf
),
418 else if (kv
->value
&& (strlen(value
) <= strlen(kv
->value
)))
419 { /* overwrite in-place, if possible */
420 strcpy(kv
->value
, value
);
423 { /* otherwise clone the string and store it in the cache */
424 kv
->value
= strdup(value
);
425 this->contents
->insert_last(this->contents
, kv
->value
);
428 this->lock
->unlock(this->lock
);
431 METHOD(settings_t
, get_str
, char*,
432 private_settings_t
*this, char *key
, char *def
, ...)
438 value
= find_value(this, this->top
, key
, args
);
448 * Described in header
450 inline bool settings_value_as_bool(char *value
, bool def
)
454 if (strcaseeq(value
, "1") ||
455 strcaseeq(value
, "yes") ||
456 strcaseeq(value
, "true") ||
457 strcaseeq(value
, "enabled"))
461 else if (strcaseeq(value
, "0") ||
462 strcaseeq(value
, "no") ||
463 strcaseeq(value
, "false") ||
464 strcaseeq(value
, "disabled"))
472 METHOD(settings_t
, get_bool
, bool,
473 private_settings_t
*this, char *key
, bool def
, ...)
479 value
= find_value(this, this->top
, key
, args
);
481 return settings_value_as_bool(value
, def
);
485 * Described in header
487 inline int settings_value_as_int(char *value
, int def
)
493 intval
= strtol(value
, NULL
, 10);
502 METHOD(settings_t
, get_int
, int,
503 private_settings_t
*this, char *key
, int def
, ...)
509 value
= find_value(this, this->top
, key
, args
);
511 return settings_value_as_int(value
, def
);
515 * Described in header
517 inline double settings_value_as_double(char *value
, double def
)
523 dval
= strtod(value
, NULL
);
532 METHOD(settings_t
, get_double
, double,
533 private_settings_t
*this, char *key
, double def
, ...)
539 value
= find_value(this, this->top
, key
, args
);
541 return settings_value_as_double(value
, def
);
545 * Described in header
547 inline u_int32_t
settings_value_as_time(char *value
, u_int32_t def
)
554 timeval
= strtoul(value
, &endptr
, 10);
559 case 'd': /* time in days */
560 timeval
*= 24 * 3600;
562 case 'h': /* time in hours */
565 case 'm': /* time in minutes */
568 case 's': /* time in seconds */
578 METHOD(settings_t
, get_time
, u_int32_t
,
579 private_settings_t
*this, char *key
, u_int32_t def
, ...)
585 value
= find_value(this, this->top
, key
, args
);
587 return settings_value_as_time(value
, def
);
590 METHOD(settings_t
, set_str
, void,
591 private_settings_t
*this, char *key
, char *value
, ...)
594 va_start(args
, value
);
595 set_value(this, this->top
, key
, args
, value
);
599 METHOD(settings_t
, set_bool
, void,
600 private_settings_t
*this, char *key
, bool value
, ...)
603 va_start(args
, value
);
604 set_value(this, this->top
, key
, args
, value ?
"1" : "0");
608 METHOD(settings_t
, set_int
, void,
609 private_settings_t
*this, char *key
, int value
, ...)
613 va_start(args
, value
);
614 if (snprintf(val
, sizeof(val
), "%d", value
) < sizeof(val
))
616 set_value(this, this->top
, key
, args
, val
);
621 METHOD(settings_t
, set_double
, void,
622 private_settings_t
*this, char *key
, double value
, ...)
626 va_start(args
, value
);
627 if (snprintf(val
, sizeof(val
), "%f", value
) < sizeof(val
))
629 set_value(this, this->top
, key
, args
, val
);
634 METHOD(settings_t
, set_time
, void,
635 private_settings_t
*this, char *key
, u_int32_t value
, ...)
639 va_start(args
, value
);
640 if (snprintf(val
, sizeof(val
), "%u", value
) < sizeof(val
))
642 set_value(this, this->top
, key
, args
, val
);
648 * Enumerate section names, not sections
650 static bool section_filter(void *null
, section_t
**in
, char **out
)
656 METHOD(settings_t
, create_section_enumerator
, enumerator_t
*,
657 private_settings_t
*this, char *key
, ...)
663 section
= find_section(this, this->top
, key
, args
);
668 return enumerator_create_empty();
670 this->lock
->read_lock(this->lock
);
671 return enumerator_create_filter(
672 section
->sections
->create_enumerator(section
->sections
),
673 (void*)section_filter
, this->lock
, (void*)this->lock
->unlock
);
677 * Enumerate key and values, not kv_t entries
679 static bool kv_filter(void *null
, kv_t
**in
, char **key
,
680 void *none
, char **value
)
683 *value
= (*in
)->value
;
687 METHOD(settings_t
, create_key_value_enumerator
, enumerator_t
*,
688 private_settings_t
*this, char *key
, ...)
694 section
= find_section(this, this->top
, key
, args
);
699 return enumerator_create_empty();
701 this->lock
->read_lock(this->lock
);
702 return enumerator_create_filter(
703 section
->kv
->create_enumerator(section
->kv
),
704 (void*)kv_filter
, this->lock
, (void*)this->lock
->unlock
);
708 * parse text, truncate "skip" chars, delimited by term respecting brackets.
710 * Chars in "skip" are truncated at the beginning and the end of the resulting
711 * token. "term" contains a list of characters to read up to (first match),
712 * while "br" contains bracket counterparts found in "term" to skip.
714 static char parse(char **text
, char *skip
, char *term
, char *br
, char **token
)
717 char best_term
= '\0';
719 /* skip leading chars */
720 while (strchr(skip
, **text
))
728 /* mark begin of subtext */
735 /* find terminator */
742 else if (br
&& *pos
== *br
)
748 if (best
== NULL
|| best
> pos
)
757 /* try next terminator */
768 /* null trailing bytes */
774 while (best
>= *token
&& strchr(skip
, *best
));
775 /* return found terminator */
782 * Check if "text" starts with "pattern".
783 * Characters in "skip" are skipped first. If found, TRUE is returned and "text"
784 * is modified to point to the character right after "pattern".
786 static bool starts_with(char **text
, char *skip
, char *pattern
)
789 int len
= strlen(pattern
);
790 while (strchr(skip
, *pos
))
798 if (strlen(pos
) < len
|| !strneq(pos
, pattern
, len
))
807 * Check if what follows in "text" is an include statement.
808 * If this function returns TRUE, "text" will point to the character right after
809 * the include pattern, which is returned in "pattern".
811 static bool parse_include(char **text
, char **pattern
)
814 if (!starts_with(&pos
, "\n\t ", "include"))
818 if (starts_with(&pos
, "\t ", "="))
819 { /* ignore "include = value" */
823 return parse(text
, "\t ", "\n", NULL
, pattern
) != 0;
827 * Forward declaration.
829 static bool parse_files(linked_list_t
*contents
, char *file
, int level
,
830 char *pattern
, section_t
*section
);
835 static bool parse_section(linked_list_t
*contents
, char *file
, int level
,
836 char **text
, section_t
*section
)
838 bool finished
= FALSE
;
839 char *key
, *value
, *inner
;
843 if (parse_include(text
, &value
))
845 if (!parse_files(contents
, file
, level
, value
, section
))
847 DBG1(DBG_LIB
, "failed to include '%s'", value
);
852 switch (parse(text
, "\t\n ", "{=#", NULL
, &key
))
855 if (parse(text
, "\t ", "}", "{", &inner
))
860 DBG1(DBG_LIB
, "skipping section without name in '%s'",
864 if (section
->sections
->find_first(section
->sections
,
865 (linked_list_match_t
)section_find
,
866 (void**)&sub
, key
) != SUCCESS
)
868 sub
= section_create(key
);
869 if (parse_section(contents
, file
, level
, &inner
, sub
))
871 section
->sections
->insert_last(section
->sections
,
875 section_destroy(sub
);
878 { /* extend the existing section */
879 if (parse_section(contents
, file
, level
, &inner
, sub
))
884 DBG1(DBG_LIB
, "parsing subsection '%s' failed", key
);
887 DBG1(DBG_LIB
, "matching '}' not found near %s", *text
);
890 if (parse(text
, "\t ", "\n", NULL
, &value
))
895 DBG1(DBG_LIB
, "skipping value without key in '%s'",
899 if (section
->kv
->find_first(section
->kv
,
900 (linked_list_match_t
)kv_find
,
901 (void**)&kv
, key
) != SUCCESS
)
903 kv
= kv_create(key
, value
);
904 section
->kv
->insert_last(section
->kv
, kv
);
907 { /* replace with the most recently read value */
912 DBG1(DBG_LIB
, "parsing value failed near %s", *text
);
915 parse(text
, "", "\n", NULL
, &value
);
927 * Parse a file and add the settings to the given section.
929 static bool parse_file(linked_list_t
*contents
, char *file
, int level
,
938 DBG2(DBG_LIB
, "loading config file '%s'", file
);
939 if (stat(file
, &st
) == -1)
943 DBG2(DBG_LIB
, "'%s' does not exist, ignored", file
);
946 DBG1(DBG_LIB
, "failed to stat '%s': %s", file
, strerror(errno
));
949 else if (!S_ISREG(st
.st_mode
))
951 DBG1(DBG_LIB
, "'%s' is not a regular file", file
);
954 fd
= fopen(file
, "r");
957 DBG1(DBG_LIB
, "'%s' is not readable", file
);
960 fseek(fd
, 0, SEEK_END
);
963 text
= malloc(len
+ 1);
965 if (fread(text
, 1, len
, fd
) != len
)
974 success
= parse_section(contents
, file
, level
, &pos
, section
);
981 contents
->insert_last(contents
, text
);
987 * Load the files matching "pattern", which is resolved with glob(3), if
989 * If the pattern is relative, the directory of "file" is used as base.
991 static bool parse_files(linked_list_t
*contents
, char *file
, int level
,
992 char *pattern
, section_t
*section
)
997 if (level
> MAX_INCLUSION_LEVEL
)
999 DBG1(DBG_LIB
, "maximum level of %d includes reached, ignored",
1000 MAX_INCLUSION_LEVEL
);
1004 if (!strlen(pattern
))
1006 DBG2(DBG_LIB
, "empty include pattern, ignored");
1010 if (!file
|| pattern
[0] == '/')
1011 { /* absolute path */
1012 if (snprintf(pat
, sizeof(pat
), "%s", pattern
) >= sizeof(pat
))
1014 DBG1(DBG_LIB
, "include pattern too long, ignored");
1019 { /* base relative paths to the directory of the current file */
1020 char *dir
= strdup(file
);
1022 if (snprintf(pat
, sizeof(pat
), "%s/%s", dir
, pattern
) >= sizeof(pat
))
1024 DBG1(DBG_LIB
, "include pattern too long, ignored");
1035 status
= glob(pat
, GLOB_ERR
, NULL
, &buf
);
1036 if (status
== GLOB_NOMATCH
)
1038 DBG2(DBG_LIB
, "no files found matching '%s', ignored", pat
);
1040 else if (status
!= 0)
1042 DBG1(DBG_LIB
, "expanding file pattern '%s' failed", pat
);
1048 for (expanded
= buf
.gl_pathv
; *expanded
!= NULL
; expanded
++)
1050 success
&= parse_file(contents
, *expanded
, level
+ 1, section
);
1059 #else /* HAVE_GLOB_H */
1060 /* if glob(3) is not available, try to load pattern directly */
1061 success
= parse_file(contents
, pat
, level
+ 1, section
);
1062 #endif /* HAVE_GLOB_H */
1067 * Recursivly extends "base" with "extension".
1069 static void section_extend(section_t
*base
, section_t
*extension
)
1071 enumerator_t
*enumerator
;
1075 enumerator
= extension
->sections
->create_enumerator(extension
->sections
);
1076 while (enumerator
->enumerate(enumerator
, (void**)&sec
))
1079 if (base
->sections
->find_first(base
->sections
,
1080 (linked_list_match_t
)section_find
, (void**)&found
,
1081 sec
->name
) == SUCCESS
)
1083 section_extend(found
, sec
);
1087 extension
->sections
->remove_at(extension
->sections
, enumerator
);
1088 base
->sections
->insert_last(base
->sections
, sec
);
1091 enumerator
->destroy(enumerator
);
1093 enumerator
= extension
->kv
->create_enumerator(extension
->kv
);
1094 while (enumerator
->enumerate(enumerator
, (void**)&kv
))
1097 if (base
->kv
->find_first(base
->kv
, (linked_list_match_t
)kv_find
,
1098 (void**)&found
, kv
->key
) == SUCCESS
)
1100 found
->value
= kv
->value
;
1104 extension
->kv
->remove_at(extension
->kv
, enumerator
);
1105 base
->kv
->insert_last(base
->kv
, kv
);
1108 enumerator
->destroy(enumerator
);
1112 * Load settings from files matching the given file pattern.
1113 * All sections and values are added relative to "parent".
1114 * All files (even included ones) have to be loaded successfully.
1116 static bool load_files_internal(private_settings_t
*this, section_t
*parent
,
1117 char *pattern
, bool merge
)
1120 linked_list_t
*contents
;
1123 if (pattern
== NULL
)
1125 #ifdef STRONGSWAN_CONF
1126 pattern
= STRONGSWAN_CONF
;
1132 contents
= linked_list_create();
1133 section
= section_create(NULL
);
1135 if (!parse_files(contents
, NULL
, 0, pattern
, section
))
1137 contents
->destroy_function(contents
, (void*)free
);
1138 section_destroy(section
);
1142 this->lock
->write_lock(this->lock
);
1145 section_purge(parent
);
1147 /* extend parent section */
1148 section_extend(parent
, section
);
1149 /* move contents of loaded files to main store */
1150 while (contents
->remove_first(contents
, (void**)&text
) == SUCCESS
)
1152 this->contents
->insert_last(this->contents
, text
);
1154 this->lock
->unlock(this->lock
);
1156 section_destroy(section
);
1157 contents
->destroy(contents
);
1161 METHOD(settings_t
, load_files
, bool,
1162 private_settings_t
*this, char *pattern
, bool merge
)
1164 return load_files_internal(this, this->top
, pattern
, merge
);
1167 METHOD(settings_t
, load_files_section
, bool,
1168 private_settings_t
*this, char *pattern
, bool merge
, char *key
, ...)
1173 va_start(args
, key
);
1174 section
= ensure_section(this, this->top
, key
, args
);
1181 return load_files_internal(this, section
, pattern
, merge
);
1184 METHOD(settings_t
, destroy
, void,
1185 private_settings_t
*this)
1187 section_destroy(this->top
);
1188 this->contents
->destroy_function(this->contents
, (void*)free
);
1189 this->lock
->destroy(this->lock
);
1196 settings_t
*settings_create(char *file
)
1198 private_settings_t
*this;
1202 .get_str
= _get_str
,
1203 .get_int
= _get_int
,
1204 .get_double
= _get_double
,
1205 .get_time
= _get_time
,
1206 .get_bool
= _get_bool
,
1207 .set_str
= _set_str
,
1208 .set_int
= _set_int
,
1209 .set_double
= _set_double
,
1210 .set_time
= _set_time
,
1211 .set_bool
= _set_bool
,
1212 .create_section_enumerator
= _create_section_enumerator
,
1213 .create_key_value_enumerator
= _create_key_value_enumerator
,
1214 .load_files
= _load_files
,
1215 .load_files_section
= _load_files_section
,
1216 .destroy
= _destroy
,
1218 .top
= section_create(NULL
),
1219 .contents
= linked_list_create(),
1220 .lock
= rwlock_create(RWLOCK_TYPE_DEFAULT
),
1223 load_files(this, file
, FALSE
);
1225 return &this->public;