settings: Make print_key() not rely on null-terminated beginning of key buffer
[strongswan.git] / src / libstrongswan / utils / settings.c
1 /*
2 * Copyright (C) 2010-2014 Tobias Brunner
3 * Copyright (C) 2008 Martin Willi
4 * Hochschule fuer Technik Rapperswil
5 *
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>.
10 *
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
14 * for more details.
15 */
16
17 #define _GNU_SOURCE
18 #include <string.h>
19 #include <stdarg.h>
20 #include <stdio.h>
21 #include <errno.h>
22 #include <limits.h>
23 #include <libgen.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <unistd.h>
27
28 #ifdef HAVE_GLOB_H
29 #include <glob.h>
30 #endif /* HAVE_GLOB_H */
31
32 #include "settings.h"
33
34 #include "collections/linked_list.h"
35 #include "threading/rwlock.h"
36 #include "utils/debug.h"
37
38 #define MAX_INCLUSION_LEVEL 10
39
40 typedef struct private_settings_t private_settings_t;
41 typedef struct section_t section_t;
42 typedef struct kv_t kv_t;
43
44 /**
45 * private data of settings
46 */
47 struct private_settings_t {
48
49 /**
50 * public functions
51 */
52 settings_t public;
53
54 /**
55 * top level section
56 */
57 section_t *top;
58
59 /**
60 * contents of loaded files and in-memory settings (char*)
61 */
62 linked_list_t *contents;
63
64 /**
65 * lock to safely access the settings
66 */
67 rwlock_t *lock;
68 };
69
70 /**
71 * section containing subsections and key value pairs
72 */
73 struct section_t {
74
75 /**
76 * name of the section
77 */
78 char *name;
79
80 /**
81 * subsections, as section_t
82 */
83 linked_list_t *sections;
84
85 /**
86 * key value pairs, as kv_t
87 */
88 linked_list_t *kv;
89 };
90
91 /**
92 * Key value pair
93 */
94 struct kv_t {
95
96 /**
97 * key string, relative
98 */
99 char *key;
100
101 /**
102 * value as string
103 */
104 char *value;
105 };
106
107 /**
108 * create a key/value pair
109 */
110 static kv_t *kv_create(char *key, char *value)
111 {
112 kv_t *this;
113 INIT(this,
114 .key = strdup(key),
115 .value = value,
116 );
117 return this;
118 }
119
120 /**
121 * destroy a key/value pair
122 */
123 static void kv_destroy(kv_t *this)
124 {
125 free(this->key);
126 free(this);
127 }
128
129 /**
130 * create a section with the given name
131 */
132 static section_t *section_create(char *name)
133 {
134 section_t *this;
135 INIT(this,
136 .name = strdupnull(name),
137 .sections = linked_list_create(),
138 .kv = linked_list_create(),
139 );
140 return this;
141 }
142
143 /**
144 * destroy a section
145 */
146 static void section_destroy(section_t *this)
147 {
148 this->kv->destroy_function(this->kv, (void*)kv_destroy);
149 this->sections->destroy_function(this->sections, (void*)section_destroy);
150 free(this->name);
151 free(this);
152 }
153
154 /**
155 * Purge contents of a section
156 */
157 static void section_purge(section_t *this)
158 {
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();
163 }
164
165 /**
166 * callback to find a section by name
167 */
168 static bool section_find(section_t *this, char *name)
169 {
170 return streq(this->name, name);
171 }
172
173 /**
174 * callback to find a kv pair by key
175 */
176 static bool kv_find(kv_t *this, char *key)
177 {
178 return streq(this->key, key);
179 }
180
181 /**
182 * Print a format key, but consume already processed arguments
183 */
184 static bool print_key(char *buf, int len, char *start, char *key, va_list args)
185 {
186 va_list copy;
187 char *pos = start;
188 bool res;
189
190 va_copy(copy, args);
191 while (TRUE)
192 {
193 pos = memchr(pos, '%', key - pos);
194 if (!pos)
195 {
196 break;
197 }
198 pos++;
199 switch (*pos)
200 {
201 case 'd':
202 va_arg(copy, int);
203 break;
204 case 's':
205 va_arg(copy, char*);
206 break;
207 case 'N':
208 va_arg(copy, enum_name_t*);
209 va_arg(copy, int);
210 break;
211 case '%':
212 break;
213 default:
214 DBG1(DBG_CFG, "settings with %%%c not supported!", *pos);
215 break;
216 }
217 pos++;
218 }
219 res = vsnprintf(buf, len, key, copy) < len;
220 va_end(copy);
221 return res;
222 }
223
224 /**
225 * Find a section by a given key, using buffered key, reusable buffer.
226 * If "ensure" is TRUE, the sections are created if they don't exist.
227 */
228 static section_t *find_section_buffered(section_t *section,
229 char *start, char *key, va_list args, char *buf, int len,
230 bool ensure)
231 {
232 char *pos;
233 section_t *found = NULL;
234
235 if (section == NULL)
236 {
237 return NULL;
238 }
239 pos = strchr(key, '.');
240 if (pos)
241 {
242 *pos = '\0';
243 pos++;
244 }
245 if (!print_key(buf, len, start, key, args))
246 {
247 return NULL;
248 }
249 if (!strlen(buf))
250 {
251 found = section;
252 }
253 else if (section->sections->find_first(section->sections,
254 (linked_list_match_t)section_find,
255 (void**)&found, buf) != SUCCESS)
256 {
257 if (ensure)
258 {
259 found = section_create(buf);
260 section->sections->insert_last(section->sections, found);
261 }
262 }
263 if (found && pos)
264 {
265 return find_section_buffered(found, start, pos, args, buf, len, ensure);
266 }
267 return found;
268 }
269
270 /**
271 * Find a section by a given key (thread-safe).
272 */
273 static section_t *find_section(private_settings_t *this, section_t *section,
274 char *key, va_list args)
275 {
276 char buf[128], keybuf[512];
277 section_t *found;
278
279 if (snprintf(keybuf, sizeof(keybuf), "%s", key) >= sizeof(keybuf))
280 {
281 return NULL;
282 }
283 this->lock->read_lock(this->lock);
284 found = find_section_buffered(section, keybuf, keybuf, args, buf,
285 sizeof(buf), FALSE);
286 this->lock->unlock(this->lock);
287 return found;
288 }
289
290 /**
291 * Ensure that the section with the given key exists (thread-safe).
292 */
293 static section_t *ensure_section(private_settings_t *this, section_t *section,
294 char *key, va_list args)
295 {
296 char buf[128], keybuf[512];
297 section_t *found;
298
299 if (snprintf(keybuf, sizeof(keybuf), "%s", key) >= sizeof(keybuf))
300 {
301 return NULL;
302 }
303 /* we might have to change the tree */
304 this->lock->write_lock(this->lock);
305 found = find_section_buffered(section, keybuf, keybuf, args, buf,
306 sizeof(buf), TRUE);
307 this->lock->unlock(this->lock);
308 return found;
309 }
310
311 /**
312 * Find the key/value pair for a key, using buffered key, reusable buffer
313 * If "ensure" is TRUE, the sections (and key/value pair) are created if they
314 * don't exist.
315 */
316 static kv_t *find_value_buffered(section_t *section, char *start, char *key,
317 va_list args, char *buf, int len, bool ensure)
318 {
319 char *pos;
320 kv_t *kv = NULL;
321 section_t *found = NULL;
322
323 if (section == NULL)
324 {
325 return NULL;
326 }
327
328 pos = strchr(key, '.');
329 if (pos)
330 {
331 *pos = '\0';
332 pos++;
333
334 if (!print_key(buf, len, start, key, args))
335 {
336 return NULL;
337 }
338 if (!strlen(buf))
339 {
340 found = section;
341 }
342 else if (section->sections->find_first(section->sections,
343 (linked_list_match_t)section_find,
344 (void**)&found, buf) != SUCCESS)
345 {
346 if (!ensure)
347 {
348 return NULL;
349 }
350 found = section_create(buf);
351 section->sections->insert_last(section->sections, found);
352 }
353 return find_value_buffered(found, start, pos, args, buf, len,
354 ensure);
355 }
356 else
357 {
358 if (!print_key(buf, len, start, key, args))
359 {
360 return NULL;
361 }
362 if (section->kv->find_first(section->kv, (linked_list_match_t)kv_find,
363 (void**)&kv, buf) != SUCCESS)
364 {
365 if (ensure)
366 {
367 kv = kv_create(buf, NULL);
368 section->kv->insert_last(section->kv, kv);
369 }
370 }
371 }
372 return kv;
373 }
374
375 /**
376 * Find the string value for a key (thread-safe).
377 */
378 static char *find_value(private_settings_t *this, section_t *section,
379 char *key, va_list args)
380 {
381 char buf[128], keybuf[512], *value = NULL;
382 kv_t *kv;
383
384 if (snprintf(keybuf, sizeof(keybuf), "%s", key) >= sizeof(keybuf))
385 {
386 return NULL;
387 }
388 this->lock->read_lock(this->lock);
389 kv = find_value_buffered(section, keybuf, keybuf, args, buf, sizeof(buf),
390 FALSE);
391 if (kv)
392 {
393 value = kv->value;
394 }
395 this->lock->unlock(this->lock);
396 return value;
397 }
398
399 /**
400 * Set a value to a copy of the given string (thread-safe).
401 */
402 static void set_value(private_settings_t *this, section_t *section,
403 char *key, va_list args, char *value)
404 {
405 char buf[128], keybuf[512];
406 kv_t *kv;
407
408 if (snprintf(keybuf, sizeof(keybuf), "%s", key) >= sizeof(keybuf))
409 {
410 return;
411 }
412 this->lock->write_lock(this->lock);
413 kv = find_value_buffered(section, keybuf, keybuf, args, buf, sizeof(buf),
414 TRUE);
415 if (kv)
416 {
417 if (!value)
418 {
419 kv->value = NULL;
420 }
421 else if (kv->value && (strlen(value) <= strlen(kv->value)))
422 { /* overwrite in-place, if possible */
423 strcpy(kv->value, value);
424 }
425 else
426 { /* otherwise clone the string and store it in the cache */
427 kv->value = strdup(value);
428 this->contents->insert_last(this->contents, kv->value);
429 }
430 }
431 this->lock->unlock(this->lock);
432 }
433
434 METHOD(settings_t, get_str, char*,
435 private_settings_t *this, char *key, char *def, ...)
436 {
437 char *value;
438 va_list args;
439
440 va_start(args, def);
441 value = find_value(this, this->top, key, args);
442 va_end(args);
443 if (value)
444 {
445 return value;
446 }
447 return def;
448 }
449
450 /**
451 * Described in header
452 */
453 inline bool settings_value_as_bool(char *value, bool def)
454 {
455 if (value)
456 {
457 if (strcaseeq(value, "1") ||
458 strcaseeq(value, "yes") ||
459 strcaseeq(value, "true") ||
460 strcaseeq(value, "enabled"))
461 {
462 return TRUE;
463 }
464 else if (strcaseeq(value, "0") ||
465 strcaseeq(value, "no") ||
466 strcaseeq(value, "false") ||
467 strcaseeq(value, "disabled"))
468 {
469 return FALSE;
470 }
471 }
472 return def;
473 }
474
475 METHOD(settings_t, get_bool, bool,
476 private_settings_t *this, char *key, bool def, ...)
477 {
478 char *value;
479 va_list args;
480
481 va_start(args, def);
482 value = find_value(this, this->top, key, args);
483 va_end(args);
484 return settings_value_as_bool(value, def);
485 }
486
487 /**
488 * Described in header
489 */
490 inline int settings_value_as_int(char *value, int def)
491 {
492 int intval;
493 if (value)
494 {
495 errno = 0;
496 intval = strtol(value, NULL, 10);
497 if (errno == 0)
498 {
499 return intval;
500 }
501 }
502 return def;
503 }
504
505 METHOD(settings_t, get_int, int,
506 private_settings_t *this, char *key, int def, ...)
507 {
508 char *value;
509 va_list args;
510
511 va_start(args, def);
512 value = find_value(this, this->top, key, args);
513 va_end(args);
514 return settings_value_as_int(value, def);
515 }
516
517 /**
518 * Described in header
519 */
520 inline double settings_value_as_double(char *value, double def)
521 {
522 double dval;
523 if (value)
524 {
525 errno = 0;
526 dval = strtod(value, NULL);
527 if (errno == 0)
528 {
529 return dval;
530 }
531 }
532 return def;
533 }
534
535 METHOD(settings_t, get_double, double,
536 private_settings_t *this, char *key, double def, ...)
537 {
538 char *value;
539 va_list args;
540
541 va_start(args, def);
542 value = find_value(this, this->top, key, args);
543 va_end(args);
544 return settings_value_as_double(value, def);
545 }
546
547 /**
548 * Described in header
549 */
550 inline u_int32_t settings_value_as_time(char *value, u_int32_t def)
551 {
552 char *endptr;
553 u_int32_t timeval;
554 if (value)
555 {
556 errno = 0;
557 timeval = strtoul(value, &endptr, 10);
558 if (errno == 0)
559 {
560 switch (*endptr)
561 {
562 case 'd': /* time in days */
563 timeval *= 24 * 3600;
564 break;
565 case 'h': /* time in hours */
566 timeval *= 3600;
567 break;
568 case 'm': /* time in minutes */
569 timeval *= 60;
570 break;
571 case 's': /* time in seconds */
572 default:
573 break;
574 }
575 return timeval;
576 }
577 }
578 return def;
579 }
580
581 METHOD(settings_t, get_time, u_int32_t,
582 private_settings_t *this, char *key, u_int32_t def, ...)
583 {
584 char *value;
585 va_list args;
586
587 va_start(args, def);
588 value = find_value(this, this->top, key, args);
589 va_end(args);
590 return settings_value_as_time(value, def);
591 }
592
593 METHOD(settings_t, set_str, void,
594 private_settings_t *this, char *key, char *value, ...)
595 {
596 va_list args;
597 va_start(args, value);
598 set_value(this, this->top, key, args, value);
599 va_end(args);
600 }
601
602 METHOD(settings_t, set_bool, void,
603 private_settings_t *this, char *key, bool value, ...)
604 {
605 va_list args;
606 va_start(args, value);
607 set_value(this, this->top, key, args, value ? "1" : "0");
608 va_end(args);
609 }
610
611 METHOD(settings_t, set_int, void,
612 private_settings_t *this, char *key, int value, ...)
613 {
614 char val[16];
615 va_list args;
616 va_start(args, value);
617 if (snprintf(val, sizeof(val), "%d", value) < sizeof(val))
618 {
619 set_value(this, this->top, key, args, val);
620 }
621 va_end(args);
622 }
623
624 METHOD(settings_t, set_double, void,
625 private_settings_t *this, char *key, double value, ...)
626 {
627 char val[64];
628 va_list args;
629 va_start(args, value);
630 if (snprintf(val, sizeof(val), "%f", value) < sizeof(val))
631 {
632 set_value(this, this->top, key, args, val);
633 }
634 va_end(args);
635 }
636
637 METHOD(settings_t, set_time, void,
638 private_settings_t *this, char *key, u_int32_t value, ...)
639 {
640 char val[16];
641 va_list args;
642 va_start(args, value);
643 if (snprintf(val, sizeof(val), "%u", value) < sizeof(val))
644 {
645 set_value(this, this->top, key, args, val);
646 }
647 va_end(args);
648 }
649
650 METHOD(settings_t, set_default_str, bool,
651 private_settings_t *this, char *key, char *value, ...)
652 {
653 char *old;
654 va_list args;
655
656 va_start(args, value);
657 old = find_value(this, this->top, key, args);
658 va_end(args);
659
660 if (!old)
661 {
662 va_start(args, value);
663 set_value(this, this->top, key, args, value);
664 va_end(args);
665 return TRUE;
666 }
667 return FALSE;
668 }
669
670 /**
671 * Enumerate section names, not sections
672 */
673 static bool section_filter(void *null, section_t **in, char **out)
674 {
675 *out = (*in)->name;
676 return TRUE;
677 }
678
679 METHOD(settings_t, create_section_enumerator, enumerator_t*,
680 private_settings_t *this, char *key, ...)
681 {
682 section_t *section;
683 va_list args;
684
685 va_start(args, key);
686 section = find_section(this, this->top, key, args);
687 va_end(args);
688
689 if (!section)
690 {
691 return enumerator_create_empty();
692 }
693 this->lock->read_lock(this->lock);
694 return enumerator_create_filter(
695 section->sections->create_enumerator(section->sections),
696 (void*)section_filter, this->lock, (void*)this->lock->unlock);
697 }
698
699 /**
700 * Enumerate key and values, not kv_t entries
701 */
702 static bool kv_filter(void *null, kv_t **in, char **key,
703 void *none, char **value)
704 {
705 *key = (*in)->key;
706 *value = (*in)->value;
707 return TRUE;
708 }
709
710 METHOD(settings_t, create_key_value_enumerator, enumerator_t*,
711 private_settings_t *this, char *key, ...)
712 {
713 section_t *section;
714 va_list args;
715
716 va_start(args, key);
717 section = find_section(this, this->top, key, args);
718 va_end(args);
719
720 if (!section)
721 {
722 return enumerator_create_empty();
723 }
724 this->lock->read_lock(this->lock);
725 return enumerator_create_filter(
726 section->kv->create_enumerator(section->kv),
727 (void*)kv_filter, this->lock, (void*)this->lock->unlock);
728 }
729
730 /**
731 * parse text, truncate "skip" chars, delimited by term respecting brackets.
732 *
733 * Chars in "skip" are truncated at the beginning and the end of the resulting
734 * token. "term" contains a list of characters to read up to (first match),
735 * while "br" contains bracket counterparts found in "term" to skip.
736 */
737 static char parse(char **text, char *skip, char *term, char *br, char **token)
738 {
739 char *best = NULL;
740 char best_term = '\0';
741
742 /* skip leading chars */
743 while (strchr(skip, **text))
744 {
745 (*text)++;
746 if (!**text)
747 {
748 return 0;
749 }
750 }
751 /* mark begin of subtext */
752 *token = *text;
753 while (*term)
754 {
755 char *pos = *text;
756 int level = 1;
757
758 /* find terminator */
759 while (*pos)
760 {
761 if (*pos == *term)
762 {
763 level--;
764 }
765 else if (br && *pos == *br)
766 {
767 level++;
768 }
769 if (level == 0)
770 {
771 if (best == NULL || best > pos)
772 {
773 best = pos;
774 best_term = *term;
775 }
776 break;
777 }
778 pos++;
779 }
780 /* try next terminator */
781 term++;
782 if (br)
783 {
784 br++;
785 }
786 }
787 if (best)
788 {
789 /* update input */
790 *text = best;
791 /* null trailing bytes */
792 do
793 {
794 *best = '\0';
795 best--;
796 }
797 while (best >= *token && strchr(skip, *best));
798 /* return found terminator */
799 return best_term;
800 }
801 return 0;
802 }
803
804 /**
805 * Check if "text" starts with "pattern".
806 * Characters in "skip" are skipped first. If found, TRUE is returned and "text"
807 * is modified to point to the character right after "pattern".
808 */
809 static bool starts_with(char **text, char *skip, char *pattern)
810 {
811 char *pos = *text;
812 int len = strlen(pattern);
813 while (strchr(skip, *pos))
814 {
815 pos++;
816 if (!*pos)
817 {
818 return FALSE;
819 }
820 }
821 if (strlen(pos) < len || !strneq(pos, pattern, len))
822 {
823 return FALSE;
824 }
825 *text = pos + len;
826 return TRUE;
827 }
828
829 /**
830 * Check if what follows in "text" is an include statement.
831 * If this function returns TRUE, "text" will point to the character right after
832 * the include pattern, which is returned in "pattern".
833 */
834 static bool parse_include(char **text, char **pattern)
835 {
836 char *pos = *text;
837 if (!starts_with(&pos, "\n\t ", "include"))
838 {
839 return FALSE;
840 }
841 if (starts_with(&pos, "\t ", "="))
842 { /* ignore "include = value" */
843 return FALSE;
844 }
845 *text = pos;
846 return parse(text, "\t ", "\n", NULL, pattern) != 0;
847 }
848
849 /**
850 * Forward declaration.
851 */
852 static bool parse_files(linked_list_t *contents, char *file, int level,
853 char *pattern, section_t *section);
854
855 /**
856 * Parse a section
857 */
858 static bool parse_section(linked_list_t *contents, char *file, int level,
859 char **text, section_t *section)
860 {
861 bool finished = FALSE;
862 char *key, *value, *inner;
863
864 while (!finished)
865 {
866 if (parse_include(text, &value))
867 {
868 if (!parse_files(contents, file, level, value, section))
869 {
870 DBG1(DBG_LIB, "failed to include '%s'", value);
871 return FALSE;
872 }
873 continue;
874 }
875 switch (parse(text, "\t\n ", "{=#", NULL, &key))
876 {
877 case '{':
878 if (parse(text, "\t ", "}", "{", &inner))
879 {
880 section_t *sub;
881 if (!strlen(key))
882 {
883 DBG1(DBG_LIB, "skipping section without name in '%s'",
884 section->name);
885 continue;
886 }
887 if (section->sections->find_first(section->sections,
888 (linked_list_match_t)section_find,
889 (void**)&sub, key) != SUCCESS)
890 {
891 sub = section_create(key);
892 if (parse_section(contents, file, level, &inner, sub))
893 {
894 section->sections->insert_last(section->sections,
895 sub);
896 continue;
897 }
898 section_destroy(sub);
899 }
900 else
901 { /* extend the existing section */
902 if (parse_section(contents, file, level, &inner, sub))
903 {
904 continue;
905 }
906 }
907 DBG1(DBG_LIB, "parsing subsection '%s' failed", key);
908 break;
909 }
910 DBG1(DBG_LIB, "matching '}' not found near %s", *text);
911 break;
912 case '=':
913 if (parse(text, "\t ", "\n", NULL, &value))
914 {
915 kv_t *kv;
916 if (!strlen(key))
917 {
918 DBG1(DBG_LIB, "skipping value without key in '%s'",
919 section->name);
920 continue;
921 }
922 if (section->kv->find_first(section->kv,
923 (linked_list_match_t)kv_find,
924 (void**)&kv, key) != SUCCESS)
925 {
926 kv = kv_create(key, value);
927 section->kv->insert_last(section->kv, kv);
928 }
929 else
930 { /* replace with the most recently read value */
931 kv->value = value;
932 }
933 continue;
934 }
935 DBG1(DBG_LIB, "parsing value failed near %s", *text);
936 break;
937 case '#':
938 parse(text, "", "\n", NULL, &value);
939 continue;
940 default:
941 finished = TRUE;
942 continue;
943 }
944 return FALSE;
945 }
946 return TRUE;
947 }
948
949 /**
950 * Parse a file and add the settings to the given section.
951 */
952 static bool parse_file(linked_list_t *contents, char *file, int level,
953 section_t *section)
954 {
955 bool success;
956 char *text, *pos;
957 struct stat st;
958 FILE *fd;
959 int len;
960
961 DBG2(DBG_LIB, "loading config file '%s'", file);
962 if (stat(file, &st) == -1)
963 {
964 if (errno == ENOENT)
965 {
966 DBG2(DBG_LIB, "'%s' does not exist, ignored", file);
967 return TRUE;
968 }
969 DBG1(DBG_LIB, "failed to stat '%s': %s", file, strerror(errno));
970 return FALSE;
971 }
972 else if (!S_ISREG(st.st_mode))
973 {
974 DBG1(DBG_LIB, "'%s' is not a regular file", file);
975 return FALSE;
976 }
977 fd = fopen(file, "r");
978 if (fd == NULL)
979 {
980 DBG1(DBG_LIB, "'%s' is not readable", file);
981 return FALSE;
982 }
983 fseek(fd, 0, SEEK_END);
984 len = ftell(fd);
985 rewind(fd);
986 text = malloc(len + 1);
987 text[len] = '\0';
988 if (fread(text, 1, len, fd) != len)
989 {
990 free(text);
991 fclose(fd);
992 return FALSE;
993 }
994 fclose(fd);
995
996 pos = text;
997 success = parse_section(contents, file, level, &pos, section);
998 if (!success)
999 {
1000 free(text);
1001 }
1002 else
1003 {
1004 contents->insert_last(contents, text);
1005 }
1006 return success;
1007 }
1008
1009 /**
1010 * Load the files matching "pattern", which is resolved with glob(3), if
1011 * available.
1012 * If the pattern is relative, the directory of "file" is used as base.
1013 */
1014 static bool parse_files(linked_list_t *contents, char *file, int level,
1015 char *pattern, section_t *section)
1016 {
1017 bool success = TRUE;
1018 char pat[PATH_MAX];
1019
1020 if (level > MAX_INCLUSION_LEVEL)
1021 {
1022 DBG1(DBG_LIB, "maximum level of %d includes reached, ignored",
1023 MAX_INCLUSION_LEVEL);
1024 return TRUE;
1025 }
1026
1027 if (!strlen(pattern))
1028 {
1029 DBG2(DBG_LIB, "empty include pattern, ignored");
1030 return TRUE;
1031 }
1032
1033 if (!file || pattern[0] == '/')
1034 { /* absolute path */
1035 if (snprintf(pat, sizeof(pat), "%s", pattern) >= sizeof(pat))
1036 {
1037 DBG1(DBG_LIB, "include pattern too long, ignored");
1038 return TRUE;
1039 }
1040 }
1041 else
1042 { /* base relative paths to the directory of the current file */
1043 char *dir = strdup(file);
1044 dir = dirname(dir);
1045 if (snprintf(pat, sizeof(pat), "%s/%s", dir, pattern) >= sizeof(pat))
1046 {
1047 DBG1(DBG_LIB, "include pattern too long, ignored");
1048 free(dir);
1049 return TRUE;
1050 }
1051 free(dir);
1052 }
1053 #ifdef HAVE_GLOB_H
1054 {
1055 int status;
1056 glob_t buf;
1057
1058 status = glob(pat, GLOB_ERR, NULL, &buf);
1059 if (status == GLOB_NOMATCH)
1060 {
1061 DBG2(DBG_LIB, "no files found matching '%s', ignored", pat);
1062 }
1063 else if (status != 0)
1064 {
1065 DBG1(DBG_LIB, "expanding file pattern '%s' failed", pat);
1066 success = FALSE;
1067 }
1068 else
1069 {
1070 char **expanded;
1071 for (expanded = buf.gl_pathv; *expanded != NULL; expanded++)
1072 {
1073 success &= parse_file(contents, *expanded, level + 1, section);
1074 if (!success)
1075 {
1076 break;
1077 }
1078 }
1079 }
1080 globfree(&buf);
1081 }
1082 #else /* HAVE_GLOB_H */
1083 /* if glob(3) is not available, try to load pattern directly */
1084 success = parse_file(contents, pat, level + 1, section);
1085 #endif /* HAVE_GLOB_H */
1086 return success;
1087 }
1088
1089 /**
1090 * Recursivly extends "base" with "extension".
1091 */
1092 static void section_extend(section_t *base, section_t *extension)
1093 {
1094 enumerator_t *enumerator;
1095 section_t *sec;
1096 kv_t *kv;
1097
1098 enumerator = extension->sections->create_enumerator(extension->sections);
1099 while (enumerator->enumerate(enumerator, (void**)&sec))
1100 {
1101 section_t *found;
1102 if (base->sections->find_first(base->sections,
1103 (linked_list_match_t)section_find, (void**)&found,
1104 sec->name) == SUCCESS)
1105 {
1106 section_extend(found, sec);
1107 }
1108 else
1109 {
1110 extension->sections->remove_at(extension->sections, enumerator);
1111 base->sections->insert_last(base->sections, sec);
1112 }
1113 }
1114 enumerator->destroy(enumerator);
1115
1116 enumerator = extension->kv->create_enumerator(extension->kv);
1117 while (enumerator->enumerate(enumerator, (void**)&kv))
1118 {
1119 kv_t *found;
1120 if (base->kv->find_first(base->kv, (linked_list_match_t)kv_find,
1121 (void**)&found, kv->key) == SUCCESS)
1122 {
1123 found->value = kv->value;
1124 }
1125 else
1126 {
1127 extension->kv->remove_at(extension->kv, enumerator);
1128 base->kv->insert_last(base->kv, kv);
1129 }
1130 }
1131 enumerator->destroy(enumerator);
1132 }
1133
1134 /**
1135 * Load settings from files matching the given file pattern.
1136 * All sections and values are added relative to "parent".
1137 * All files (even included ones) have to be loaded successfully.
1138 */
1139 static bool load_files_internal(private_settings_t *this, section_t *parent,
1140 char *pattern, bool merge)
1141 {
1142 char *text;
1143 linked_list_t *contents;
1144 section_t *section;
1145
1146 if (pattern == NULL)
1147 {
1148 #ifdef STRONGSWAN_CONF
1149 pattern = STRONGSWAN_CONF;
1150 #else
1151 return FALSE;
1152 #endif
1153 }
1154
1155 contents = linked_list_create();
1156 section = section_create(NULL);
1157
1158 if (!parse_files(contents, NULL, 0, pattern, section))
1159 {
1160 contents->destroy_function(contents, (void*)free);
1161 section_destroy(section);
1162 return FALSE;
1163 }
1164
1165 this->lock->write_lock(this->lock);
1166 if (!merge)
1167 {
1168 section_purge(parent);
1169 }
1170 /* extend parent section */
1171 section_extend(parent, section);
1172 /* move contents of loaded files to main store */
1173 while (contents->remove_first(contents, (void**)&text) == SUCCESS)
1174 {
1175 this->contents->insert_last(this->contents, text);
1176 }
1177 this->lock->unlock(this->lock);
1178
1179 section_destroy(section);
1180 contents->destroy(contents);
1181 return TRUE;
1182 }
1183
1184 METHOD(settings_t, load_files, bool,
1185 private_settings_t *this, char *pattern, bool merge)
1186 {
1187 return load_files_internal(this, this->top, pattern, merge);
1188 }
1189
1190 METHOD(settings_t, load_files_section, bool,
1191 private_settings_t *this, char *pattern, bool merge, char *key, ...)
1192 {
1193 section_t *section;
1194 va_list args;
1195
1196 va_start(args, key);
1197 section = ensure_section(this, this->top, key, args);
1198 va_end(args);
1199
1200 if (!section)
1201 {
1202 return FALSE;
1203 }
1204 return load_files_internal(this, section, pattern, merge);
1205 }
1206
1207 METHOD(settings_t, destroy, void,
1208 private_settings_t *this)
1209 {
1210 section_destroy(this->top);
1211 this->contents->destroy_function(this->contents, (void*)free);
1212 this->lock->destroy(this->lock);
1213 free(this);
1214 }
1215
1216 /*
1217 * see header file
1218 */
1219 settings_t *settings_create(char *file)
1220 {
1221 private_settings_t *this;
1222
1223 INIT(this,
1224 .public = {
1225 .get_str = _get_str,
1226 .get_int = _get_int,
1227 .get_double = _get_double,
1228 .get_time = _get_time,
1229 .get_bool = _get_bool,
1230 .set_str = _set_str,
1231 .set_int = _set_int,
1232 .set_double = _set_double,
1233 .set_time = _set_time,
1234 .set_bool = _set_bool,
1235 .set_default_str = _set_default_str,
1236 .create_section_enumerator = _create_section_enumerator,
1237 .create_key_value_enumerator = _create_key_value_enumerator,
1238 .load_files = _load_files,
1239 .load_files_section = _load_files_section,
1240 .destroy = _destroy,
1241 },
1242 .top = section_create(NULL),
1243 .contents = linked_list_create(),
1244 .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
1245 );
1246
1247 load_files(this, file, FALSE);
1248
1249 return &this->public;
1250 }
1251