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