Skip values and sections without key.
[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 <glob.h>
24 #include <libgen.h>
25
26 #include "settings.h"
27
28 #include "debug.h"
29 #include "utils/linked_list.h"
30 #include "threading/rwlock.h"
31
32 #define MAX_INCLUSION_LEVEL 10
33
34 typedef struct private_settings_t private_settings_t;
35 typedef struct section_t section_t;
36 typedef struct kv_t kv_t;
37
38 /**
39 * private data of settings
40 */
41 struct private_settings_t {
42
43 /**
44 * public functions
45 */
46 settings_t public;
47
48 /**
49 * top level section
50 */
51 section_t *top;
52
53 /**
54 * contents of loaded files
55 */
56 linked_list_t *files;
57
58 /**
59 * lock to safely access the settings
60 */
61 rwlock_t *lock;
62 };
63
64 /**
65 * section containing subsections and key value pairs
66 */
67 struct section_t {
68
69 /**
70 * name of the section
71 */
72 char *name;
73
74 /**
75 * subsections, as section_t
76 */
77 linked_list_t *sections;
78
79 /**
80 * key value pairs, as kv_t
81 */
82 linked_list_t *kv;
83 };
84
85 /**
86 * Key value pair
87 */
88 struct kv_t {
89
90 /**
91 * key string, relative
92 */
93 char *key;
94
95 /**
96 * value as string
97 */
98 char *value;
99 };
100
101 /**
102 * create a section with the given name
103 */
104 static section_t *section_create(char *name)
105 {
106 section_t *this;
107 INIT(this,
108 .name = name,
109 .sections = linked_list_create(),
110 .kv = linked_list_create(),
111 );
112 return this;
113 }
114
115 /**
116 * destroy a section
117 */
118 static void section_destroy(section_t *this)
119 {
120 this->kv->destroy_function(this->kv, free);
121 this->sections->destroy_function(this->sections, (void*)section_destroy);
122 free(this);
123 }
124
125 /**
126 * callback to find a section by name
127 */
128 static bool section_find(section_t *this, char *name)
129 {
130 return streq(this->name, name);
131 }
132
133 /**
134 * callback to find a kv pair by key
135 */
136 static bool kv_find(kv_t *this, char *key)
137 {
138 return streq(this->key, key);
139 }
140
141 /**
142 * Print a format key, but consume already processed arguments
143 */
144 static bool print_key(char *buf, int len, char *start, char *key, va_list args)
145 {
146 va_list copy;
147 bool res;
148 char *pos;
149
150 va_copy(copy, args);
151 while (start < key)
152 {
153 pos = strchr(start, '%');
154 if (!pos)
155 {
156 start += strlen(start) + 1;
157 continue;
158 }
159 pos++;
160 switch (*pos)
161 {
162 case 'd':
163 va_arg(copy, int);
164 break;
165 case 's':
166 va_arg(copy, char*);
167 break;
168 case 'N':
169 va_arg(copy, enum_name_t*);
170 va_arg(copy, int);
171 break;
172 case '%':
173 break;
174 default:
175 DBG1(DBG_CFG, "settings with %%%c not supported!", *pos);
176 break;
177 }
178 start = pos;
179 if (*start)
180 {
181 start++;
182 }
183 }
184 res = vsnprintf(buf, len, key, copy) < len;
185 va_end(copy);
186 return res;
187 }
188
189 /**
190 * find a section by a given key, using buffered key, reusable buffer
191 */
192 static section_t *find_section_buffered(section_t *section,
193 char *start, char *key, va_list args, char *buf, int len)
194 {
195 char *pos;
196 section_t *found = NULL;
197
198 if (section == NULL)
199 {
200 return NULL;
201 }
202 pos = strchr(key, '.');
203 if (pos)
204 {
205 *pos = '\0';
206 pos++;
207 }
208 if (!print_key(buf, len, start, key, args))
209 {
210 return NULL;
211 }
212 if (section->sections->find_first(section->sections,
213 (linked_list_match_t)section_find,
214 (void**)&found, buf) == SUCCESS)
215 {
216 if (pos)
217 {
218 return find_section_buffered(found, start, pos, args, buf, len);
219 }
220 }
221 return found;
222 }
223
224 /**
225 * Find a section by a given key (thread-safe).
226 */
227 static section_t *find_section(private_settings_t *this, section_t *section,
228 char *key, va_list args)
229 {
230 char buf[128], keybuf[512];
231 section_t *found;
232
233 if (snprintf(keybuf, sizeof(keybuf), "%s", key) >= sizeof(keybuf))
234 {
235 return NULL;
236 }
237 this->lock->read_lock(this->lock);
238 found = find_section_buffered(section, keybuf, keybuf, args, buf,
239 sizeof(buf));
240 this->lock->unlock(this->lock);
241 return found;
242 }
243
244 /**
245 * Find the string value for a key, using buffered key, reusable buffer
246 */
247 static char *find_value_buffered(section_t *section,
248 char *start, char *key, va_list args, char *buf, int len)
249 {
250 char *pos, *value = NULL;
251 kv_t *kv;
252 section_t *found = NULL;
253
254 if (section == NULL)
255 {
256 return NULL;
257 }
258
259 pos = strchr(key, '.');
260 if (pos)
261 {
262 *pos = '\0';
263 pos++;
264
265 if (!print_key(buf, len, start, key, args))
266 {
267 return NULL;
268 }
269 if (section->sections->find_first(section->sections,
270 (linked_list_match_t)section_find,
271 (void**)&found, buf) == SUCCESS)
272 {
273 return find_value_buffered(found, start, pos, args, buf, len);
274 }
275 }
276 else
277 {
278 if (!print_key(buf, len, start, key, args))
279 {
280 return NULL;
281 }
282 if (section->kv->find_first(section->kv, (linked_list_match_t)kv_find,
283 (void**)&kv, buf) == SUCCESS)
284 {
285 value = kv->value;
286 }
287 }
288 return value;
289 }
290
291 /**
292 * Find the string value for a key (thread-safe).
293 */
294 static char *find_value(private_settings_t *this, section_t *section,
295 char *key, va_list args)
296 {
297 char buf[128], keybuf[512], *value;
298
299 if (snprintf(keybuf, sizeof(keybuf), "%s", key) >= sizeof(keybuf))
300 {
301 return NULL;
302 }
303 this->lock->read_lock(this->lock);
304 value = find_value_buffered(section, keybuf, keybuf, args, buf,
305 sizeof(buf));
306 this->lock->unlock(this->lock);
307 return value;
308 }
309
310 METHOD(settings_t, get_str, char*,
311 private_settings_t *this, char *key, char *def, ...)
312 {
313 char *value;
314 va_list args;
315
316 va_start(args, def);
317 value = find_value(this, this->top, key, args);
318 va_end(args);
319 if (value)
320 {
321 return value;
322 }
323 return def;
324 }
325
326 METHOD(settings_t, get_bool, bool,
327 private_settings_t *this, char *key, bool def, ...)
328 {
329 char *value;
330 va_list args;
331
332 va_start(args, def);
333 value = find_value(this, this->top, key, args);
334 va_end(args);
335 if (value)
336 {
337 if (strcaseeq(value, "true") ||
338 strcaseeq(value, "enabled") ||
339 strcaseeq(value, "yes") ||
340 strcaseeq(value, "1"))
341 {
342 return TRUE;
343 }
344 else if (strcaseeq(value, "false") ||
345 strcaseeq(value, "disabled") ||
346 strcaseeq(value, "no") ||
347 strcaseeq(value, "0"))
348 {
349 return FALSE;
350 }
351 }
352 return def;
353 }
354
355 METHOD(settings_t, get_int, int,
356 private_settings_t *this, char *key, int def, ...)
357 {
358 char *value;
359 int intval;
360 va_list args;
361
362 va_start(args, def);
363 value = find_value(this, this->top, key, args);
364 va_end(args);
365 if (value)
366 {
367 errno = 0;
368 intval = strtol(value, NULL, 10);
369 if (errno == 0)
370 {
371 return intval;
372 }
373 }
374 return def;
375 }
376
377 METHOD(settings_t, get_double, double,
378 private_settings_t *this, char *key, double def, ...)
379 {
380 char *value;
381 double dval;
382 va_list args;
383
384 va_start(args, def);
385 value = find_value(this, this->top, key, args);
386 va_end(args);
387 if (value)
388 {
389 errno = 0;
390 dval = strtod(value, NULL);
391 if (errno == 0)
392 {
393 return dval;
394 }
395 }
396 return def;
397 }
398
399 METHOD(settings_t, get_time, u_int32_t,
400 private_settings_t *this, char *key, u_int32_t def, ...)
401 {
402 char *value, *endptr;
403 u_int32_t timeval;
404 va_list args;
405
406 va_start(args, def);
407 value = find_value(this, this->top, key, args);
408 va_end(args);
409 if (value)
410 {
411 errno = 0;
412 timeval = strtoul(value, &endptr, 10);
413 if (errno == 0)
414 {
415 switch (*endptr)
416 {
417 case 'd': /* time in days */
418 timeval *= 24 * 3600;
419 break;
420 case 'h': /* time in hours */
421 timeval *= 3600;
422 break;
423 case 'm': /* time in minutes */
424 timeval *= 60;
425 break;
426 case 's': /* time in seconds */
427 default:
428 break;
429 }
430 return timeval;
431 }
432 }
433 return def;
434 }
435
436 /**
437 * Enumerate section names, not sections
438 */
439 static bool section_filter(void *null, section_t **in, char **out)
440 {
441 *out = (*in)->name;
442 return TRUE;
443 }
444
445 METHOD(settings_t, create_section_enumerator, enumerator_t*,
446 private_settings_t *this, char *key, ...)
447 {
448 section_t *section;
449 va_list args;
450
451 va_start(args, key);
452 section = find_section(this, this->top, key, args);
453 va_end(args);
454
455 if (!section)
456 {
457 return enumerator_create_empty();
458 }
459 this->lock->read_lock(this->lock);
460 return enumerator_create_filter(
461 section->sections->create_enumerator(section->sections),
462 (void*)section_filter, this->lock, (void*)this->lock->unlock);
463 }
464
465 /**
466 * Enumerate key and values, not kv_t entries
467 */
468 static bool kv_filter(void *null, kv_t **in, char **key,
469 void *none, char **value)
470 {
471 *key = (*in)->key;
472 *value = (*in)->value;
473 return TRUE;
474 }
475
476 METHOD(settings_t, create_key_value_enumerator, enumerator_t*,
477 private_settings_t *this, char *key, ...)
478 {
479 section_t *section;
480 va_list args;
481
482 va_start(args, key);
483 section = find_section(this, this->top, key, args);
484 va_end(args);
485
486 if (!section)
487 {
488 return enumerator_create_empty();
489 }
490 this->lock->read_lock(this->lock);
491 return enumerator_create_filter(
492 section->kv->create_enumerator(section->kv),
493 (void*)kv_filter, this->lock, (void*)this->lock->unlock);
494 }
495
496 /**
497 * parse text, truncate "skip" chars, delimited by term respecting brackets.
498 *
499 * Chars in "skip" are truncated at the beginning and the end of the resulting
500 * token. "term" contains a list of characters to read up to (first match),
501 * while "br" contains bracket counterparts found in "term" to skip.
502 */
503 static char parse(char **text, char *skip, char *term, char *br, char **token)
504 {
505 char *best = NULL;
506 char best_term = '\0';
507
508 /* skip leading chars */
509 while (strchr(skip, **text))
510 {
511 (*text)++;
512 if (!**text)
513 {
514 return 0;
515 }
516 }
517 /* mark begin of subtext */
518 *token = *text;
519 while (*term)
520 {
521 char *pos = *text;
522 int level = 1;
523
524 /* find terminator */
525 while (*pos)
526 {
527 if (*pos == *term)
528 {
529 level--;
530 }
531 else if (br && *pos == *br)
532 {
533 level++;
534 }
535 if (level == 0)
536 {
537 if (best == NULL || best > pos)
538 {
539 best = pos;
540 best_term = *term;
541 }
542 break;
543 }
544 pos++;
545 }
546 /* try next terminator */
547 term++;
548 if (br)
549 {
550 br++;
551 }
552 }
553 if (best)
554 {
555 /* update input */
556 *text = best;
557 /* null trailing bytes */
558 do
559 {
560 *best = '\0';
561 best--;
562 }
563 while (best >= *token && strchr(skip, *best));
564 /* return found terminator */
565 return best_term;
566 }
567 return 0;
568 }
569
570 /**
571 * Check if "text" starts with "pattern".
572 * Characters in "skip" are skipped first. If found, TRUE is returned and "text"
573 * is modified to point to the character right after "pattern".
574 */
575 static bool starts_with(char **text, char *skip, char *pattern)
576 {
577 char *pos = *text;
578 int len = strlen(pattern);
579 while (strchr(skip, *pos))
580 {
581 pos++;
582 if (!*pos)
583 {
584 return FALSE;
585 }
586 }
587 if (strlen(pos) < len || !strneq(pos, pattern, len))
588 {
589 return FALSE;
590 }
591 *text = pos + len;
592 return TRUE;
593 }
594
595 /**
596 * Check if what follows in "text" is an include statement.
597 * If this function returns TRUE, "text" will point to the character right after
598 * the include pattern, which is returned in "pattern".
599 */
600 static bool parse_include(char **text, char **pattern)
601 {
602 char *pos = *text;
603 if (!starts_with(&pos, "\n\t ", "include"))
604 {
605 return FALSE;
606 }
607 if (starts_with(&pos, "\t ", "="))
608 { /* ignore "include = value" */
609 return FALSE;
610 }
611 *text = pos;
612 return parse(text, "\t ", "\n", NULL, pattern) != 0;
613 }
614
615 /**
616 * Forward declaration.
617 */
618 static bool parse_files(linked_list_t *files, char *file, int level,
619 char *pattern, section_t *section);
620
621 /**
622 * Parse a section
623 */
624 static bool parse_section(linked_list_t *files, char *file, int level,
625 char **text, section_t *section)
626 {
627 bool finished = FALSE;
628 char *key, *value, *inner;
629
630 while (!finished)
631 {
632 if (parse_include(text, &value))
633 {
634 if (!parse_files(files, file, level, value, section))
635 {
636 DBG1(DBG_LIB, "failed to include '%s'", value);
637 return FALSE;
638 }
639 continue;
640 }
641 switch (parse(text, "\t\n ", "{=#", NULL, &key))
642 {
643 case '{':
644 if (parse(text, "\t ", "}", "{", &inner))
645 {
646 section_t *sub;
647 if (!strlen(key))
648 {
649 DBG1(DBG_LIB, "skipping section without name in '%s'",
650 section->name);
651 continue;
652 }
653 if (section->sections->find_first(section->sections,
654 (linked_list_match_t)section_find,
655 (void**)&sub, key) != SUCCESS)
656 {
657 sub = section_create(key);
658 if (parse_section(files, file, level, &inner, sub))
659 {
660 section->sections->insert_last(section->sections,
661 sub);
662 continue;
663 }
664 section_destroy(sub);
665 }
666 else
667 { /* extend the existing section */
668 if (parse_section(files, file, level, &inner, sub))
669 {
670 continue;
671 }
672 }
673 DBG1(DBG_LIB, "parsing subsection '%s' failed", key);
674 break;
675 }
676 DBG1(DBG_LIB, "matching '}' not found near %s", *text);
677 break;
678 case '=':
679 if (parse(text, "\t ", "\n", NULL, &value))
680 {
681 kv_t *kv;
682 if (!strlen(key))
683 {
684 DBG1(DBG_LIB, "skipping value without key in '%s'",
685 section->name);
686 continue;
687 }
688 if (section->kv->find_first(section->kv,
689 (linked_list_match_t)kv_find,
690 (void**)&kv, key) != SUCCESS)
691 {
692 INIT(kv,
693 .key = key,
694 .value = value,
695 );
696 section->kv->insert_last(section->kv, kv);
697 }
698 else
699 { /* replace with the most recently read value */
700 kv->value = value;
701 }
702 continue;
703 }
704 DBG1(DBG_LIB, "parsing value failed near %s", *text);
705 break;
706 case '#':
707 parse(text, "", "\n", NULL, &value);
708 continue;
709 default:
710 finished = TRUE;
711 continue;
712 }
713 return FALSE;
714 }
715 return TRUE;
716 }
717
718 /**
719 * Parse a file and add the settings to the given section.
720 */
721 static bool parse_file(linked_list_t *files, char *file, int level,
722 section_t *section)
723 {
724 bool success;
725 char *text, *pos;
726 FILE *fd;
727 int len;
728
729 DBG2(DBG_LIB, "loading config file '%s'", file);
730 fd = fopen(file, "r");
731 if (fd == NULL)
732 {
733 DBG1(DBG_LIB, "'%s' does not exist or is not readable", file);
734 return FALSE;
735 }
736 fseek(fd, 0, SEEK_END);
737 len = ftell(fd);
738 rewind(fd);
739 text = malloc(len + 1);
740 text[len] = '\0';
741 if (fread(text, 1, len, fd) != len)
742 {
743 free(text);
744 return FALSE;
745 }
746 fclose(fd);
747
748 pos = text;
749 success = parse_section(files, file, level, &pos, section);
750 if (!success)
751 {
752 free(text);
753 }
754 else
755 {
756 files->insert_last(files, text);
757 }
758 return success;
759 }
760
761 /**
762 * Load the files matching "pattern", which is resolved with glob(3).
763 * If the pattern is relative, the directory of "file" is used as base.
764 */
765 static bool parse_files(linked_list_t *files, char *file, int level,
766 char *pattern, section_t *section)
767 {
768 bool success = TRUE;
769 int status;
770 glob_t buf;
771 char **expanded, pat[PATH_MAX];
772
773 if (level > MAX_INCLUSION_LEVEL)
774 {
775 DBG1(DBG_LIB, "maximum level of %d includes reached, ignored",
776 MAX_INCLUSION_LEVEL);
777 return TRUE;
778 }
779
780 if (!strlen(pattern))
781 {
782 DBG2(DBG_LIB, "empty include pattern, ignored");
783 return TRUE;
784 }
785
786 if (!file || pattern[0] == '/')
787 { /* absolute path */
788 if (snprintf(pat, sizeof(pat), "%s", pattern) >= sizeof(pat))
789 {
790 DBG1(DBG_LIB, "include pattern too long, ignored");
791 return TRUE;
792 }
793 }
794 else
795 { /* base relative paths to the directory of the current file */
796 char *dir = strdup(file);
797 dir = dirname(dir);
798 if (snprintf(pat, sizeof(pat), "%s/%s", dir, pattern) >= sizeof(pat))
799 {
800 DBG1(DBG_LIB, "include pattern too long, ignored");
801 free(dir);
802 return TRUE;
803 }
804 free(dir);
805 }
806 status = glob(pat, GLOB_ERR, NULL, &buf);
807 if (status == GLOB_NOMATCH)
808 {
809 DBG2(DBG_LIB, "no files found matching '%s', ignored", pat);
810 }
811 else if (status != 0)
812 {
813 DBG1(DBG_LIB, "expanding file pattern '%s' failed", pat);
814 success = FALSE;
815 }
816 else
817 {
818 for (expanded = buf.gl_pathv; *expanded != NULL; expanded++)
819 {
820 success &= parse_file(files, *expanded, level + 1, section);
821 if (!success)
822 {
823 break;
824 }
825 }
826 }
827 globfree(&buf);
828 return success;
829 }
830
831 /**
832 * Recursivly extends "base" with "extension".
833 */
834 static void section_extend(section_t *base, section_t *extension)
835 {
836 enumerator_t *enumerator;
837 section_t *sec;
838 kv_t *kv;
839
840 enumerator = extension->sections->create_enumerator(extension->sections);
841 while (enumerator->enumerate(enumerator, (void**)&sec))
842 {
843 section_t *found;
844 if (base->sections->find_first(base->sections,
845 (linked_list_match_t)section_find, (void**)&found,
846 sec->name) == SUCCESS)
847 {
848 section_extend(found, sec);
849 }
850 else
851 {
852 extension->sections->remove_at(extension->sections, enumerator);
853 base->sections->insert_last(base->sections, sec);
854 }
855 }
856 enumerator->destroy(enumerator);
857
858 enumerator = extension->kv->create_enumerator(extension->kv);
859 while (enumerator->enumerate(enumerator, (void**)&kv))
860 {
861 kv_t *found;
862 if (base->kv->find_first(base->kv, (linked_list_match_t)kv_find,
863 (void**)&found, kv->key) == SUCCESS)
864 {
865 found->value = kv->value;
866 }
867 else
868 {
869 extension->kv->remove_at(extension->kv, enumerator);
870 base->kv->insert_last(base->kv, kv);
871 }
872 }
873 enumerator->destroy(enumerator);
874 }
875
876 /**
877 * Load settings from files matching the given file pattern.
878 * All sections and values are added relative to "parent".
879 * All files (even included ones) have to be loaded successfully.
880 */
881 static bool load_files_internal(private_settings_t *this, section_t *parent,
882 char *pattern)
883 {
884 char *text;
885 linked_list_t *files = linked_list_create();
886 section_t *section = section_create(NULL);
887
888 if (!parse_files(files, NULL, 0, pattern, section))
889 {
890 files->destroy_function(files, (void*)free);
891 section_destroy(section);
892 return FALSE;
893 }
894
895 this->lock->write_lock(this->lock);
896 /* extend parent section */
897 section_extend(parent, section);
898 /* move contents of loaded files to main store */
899 while (files->remove_first(files, (void**)&text) == SUCCESS)
900 {
901 this->files->insert_last(this->files, text);
902 }
903 this->lock->unlock(this->lock);
904
905 section_destroy(section);
906 files->destroy(files);
907 return TRUE;
908 }
909
910 METHOD(settings_t, load_files, bool,
911 private_settings_t *this, char *pattern)
912 {
913 return load_files_internal(this, this->top, pattern);
914 }
915
916 METHOD(settings_t, load_files_section, bool,
917 private_settings_t *this, char *pattern, char *key, ...)
918 {
919 section_t *section;
920 va_list args;
921
922 va_start(args, key);
923 section = find_section(this, this->top, key, args);
924 va_end(args);
925
926 if (!section)
927 {
928 return FALSE;
929 }
930 return load_files_internal(this, section, pattern);
931 }
932
933 METHOD(settings_t, destroy, void,
934 private_settings_t *this)
935 {
936 section_destroy(this->top);
937 this->files->destroy_function(this->files, (void*)free);
938 this->lock->destroy(this->lock);
939 free(this);
940 }
941
942 /*
943 * see header file
944 */
945 settings_t *settings_create(char *file)
946 {
947 private_settings_t *this;
948
949 INIT(this,
950 .public = {
951 .get_str = _get_str,
952 .get_int = _get_int,
953 .get_double = _get_double,
954 .get_time = _get_time,
955 .get_bool = _get_bool,
956 .create_section_enumerator = _create_section_enumerator,
957 .create_key_value_enumerator = _create_key_value_enumerator,
958 .load_files = _load_files,
959 .load_files_section = _load_files_section,
960 .destroy = _destroy,
961 },
962 .top = section_create(NULL),
963 .files = linked_list_create(),
964 .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
965 );
966
967 if (file == NULL)
968 {
969 file = STRONGSWAN_CONF;
970 }
971
972 load_files(this, file);
973
974 return &this->public;
975 }
976