Coverage Report

Created: 2024-02-29 06:05

/src/strongswan/src/libstrongswan/settings/settings.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2010-2018 Tobias Brunner
3
 * Copyright (C) 2008 Martin Willi
4
 *
5
 * Copyright (C) secunet Security Networks AG
6
 *
7
 * This program is free software; you can redistribute it and/or modify it
8
 * under the terms of the GNU General Public License as published by the
9
 * Free Software Foundation; either version 2 of the License, or (at your
10
 * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
11
 *
12
 * This program is distributed in the hope that it will be useful, but
13
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15
 * for more details.
16
 */
17
18
#define _GNU_SOURCE
19
#include <string.h>
20
#include <stdarg.h>
21
#include <stdio.h>
22
#include <errno.h>
23
#include <limits.h>
24
#include <sys/types.h>
25
#include <sys/stat.h>
26
#include <unistd.h>
27
#include <ctype.h>
28
29
#include "settings.h"
30
#include "settings_types.h"
31
32
#include "collections/array.h"
33
#include "collections/hashtable.h"
34
#include "collections/linked_list.h"
35
#include "threading/rwlock.h"
36
#include "utils/debug.h"
37
38
typedef struct private_settings_t private_settings_t;
39
40
/**
41
 * Parse functions provided by the generated parser.
42
 */
43
bool settings_parser_parse_file(section_t *root, char *name);
44
bool settings_parser_parse_string(section_t *root, char *settings);
45
46
/**
47
 * Private data of settings
48
 */
49
struct private_settings_t {
50
51
  /**
52
   * Public interface
53
   */
54
  settings_t public;
55
56
  /**
57
   * Top level section
58
   */
59
  section_t *top;
60
61
  /**
62
   * Contents of replaced settings (char*)
63
   *
64
   * FIXME: This is required because the pointer returned by get_str()
65
   * is not refcounted.  Might cause ever increasing usage stats.
66
   */
67
  array_t *contents;
68
69
  /**
70
   * Lock to safely access the settings
71
   */
72
  rwlock_t *lock;
73
};
74
75
/**
76
 * Print a format key, but consume already processed arguments
77
 * Note that key and start point into the same string
78
 */
79
static bool print_key(char *buf, int len, char *start, char *key, va_list args)
80
2.50M
{
81
2.50M
  va_list copy;
82
2.50M
  char *pos = start;
83
2.50M
  bool res;
84
85
2.50M
  va_copy(copy, args);
86
2.50M
  while (TRUE)
87
3.33M
  {
88
3.33M
    pos = memchr(pos, '%', key - pos);
89
3.33M
    if (!pos)
90
2.50M
    {
91
2.50M
      break;
92
2.50M
    }
93
830k
    pos++;
94
830k
    switch (*pos)
95
830k
    {
96
0
      case 'd':
97
0
        va_arg(copy, int);
98
0
        break;
99
830k
      case 's':
100
830k
        va_arg(copy, char*);
101
830k
        break;
102
0
      case 'N':
103
0
        va_arg(copy, enum_name_t*);
104
0
        va_arg(copy, int);
105
0
        break;
106
0
      case '%':
107
0
        break;
108
0
      default:
109
0
        DBG1(DBG_CFG, "settings with %%%c not supported!", *pos);
110
0
        break;
111
830k
    }
112
830k
    pos++;
113
830k
  }
114
2.50M
  res = vsnprintf(buf, len, key, copy) < len;
115
2.50M
  va_end(copy);
116
2.50M
  return res;
117
2.50M
}
118
119
/**
120
 * Check if the given section is contained in the given array.
121
 */
122
static bool has_section(array_t *array, section_t *section)
123
0
{
124
0
  section_t *current;
125
0
  int i;
126
127
0
  for (i = 0; i < array_count(array); i++)
128
0
  {
129
0
    array_get(array, i, &current);
130
0
    if (current == section)
131
0
    {
132
0
      return TRUE;
133
0
    }
134
0
  }
135
0
  return FALSE;
136
0
}
137
138
/**
139
 * Find a section by a given key, using buffered key, reusable buffer.
140
 * If "ensure" is TRUE, the sections are created if they don't exist.
141
 */
142
static section_t *find_section_buffered(section_t *section,
143
          char *start, char *key, va_list args, char *buf, int len,
144
          bool ensure)
145
60.9k
{
146
60.9k
  char *pos;
147
60.9k
  section_t *found = NULL;
148
149
60.9k
  if (section == NULL)
150
0
  {
151
0
    return NULL;
152
0
  }
153
60.9k
  pos = strchr(key, '.');
154
60.9k
  if (pos)
155
16.7k
  {
156
16.7k
    *pos = '\0';
157
16.7k
    pos++;
158
16.7k
  }
159
60.9k
  if (!print_key(buf, len, start, key, args))
160
0
  {
161
0
    return NULL;
162
0
  }
163
60.9k
  if (!strlen(buf))
164
0
  {
165
0
    found = section;
166
0
  }
167
60.9k
  else if (array_bsearch(section->sections, buf, settings_section_find,
168
60.9k
               &found) == -1)
169
44.1k
  {
170
44.1k
    if (ensure)
171
44.1k
    {
172
44.1k
      found = settings_section_create(strdup(buf));
173
44.1k
      settings_section_add(section, found, NULL);
174
44.1k
    }
175
44.1k
  }
176
60.9k
  if (found && pos)
177
16.7k
  {
178
16.7k
    return find_section_buffered(found, start, pos, args, buf, len, ensure);
179
16.7k
  }
180
44.1k
  return found;
181
60.9k
}
182
183
/**
184
 * Forward declaration
185
 */
186
static array_t *find_sections(private_settings_t *this, section_t *section,
187
                char *key, va_list args, array_t **sections);
188
189
/**
190
 * Resolve the given reference. Not thread-safe.
191
 * Only a vararg function to get an empty va_list.
192
 */
193
static void resolve_reference(private_settings_t *this, section_ref_t *ref,
194
            array_t **sections, ...)
195
814k
{
196
814k
  va_list args;
197
198
814k
  va_start(args, sections);
199
814k
  find_sections(this, this->top, ref->name, args, sections);
200
814k
  va_end(args);
201
814k
}
202
203
/**
204
 * Find all sections via a given key considering references, using buffered key,
205
 * reusable buffer.
206
 */
207
static void find_sections_buffered(private_settings_t *this, section_t *section,
208
                   char *start, char *key, va_list args,
209
                   char *buf, int len, bool ignore_refs,
210
                   array_t **sections)
211
814k
{
212
814k
  section_t *found = NULL, *reference;
213
814k
  array_t *references;
214
814k
  section_ref_t *ref;
215
814k
  char *pos;
216
814k
  int i, j;
217
218
814k
  if (!section)
219
0
  {
220
0
    return;
221
0
  }
222
814k
  pos = strchr(key, '.');
223
814k
  if (pos)
224
0
  {
225
0
    *pos = '\0';
226
0
  }
227
814k
  if (!print_key(buf, len, start, key, args))
228
0
  {
229
0
    return;
230
0
  }
231
814k
  if (pos)
232
0
  { /* restore so we can follow references */
233
0
    *pos = '.';
234
0
  }
235
814k
  if (!strlen(buf))
236
0
  {
237
0
    found = section;
238
0
  }
239
814k
  else
240
814k
  {
241
814k
    array_bsearch(section->sections, buf, settings_section_find, &found);
242
814k
  }
243
814k
  if (found)
244
0
  {
245
0
    if (pos)
246
0
    {
247
0
      find_sections_buffered(this, found, start, pos+1, args, buf, len,
248
0
                   FALSE, sections);
249
0
    }
250
0
    else if (!has_section(*sections, found))
251
0
    {
252
      /* ignore if already added to avoid loops */
253
0
      array_insert_create(sections, ARRAY_TAIL, found);
254
      /* add all sections that are referenced here (also resolves
255
       * references in parent sections of the referenced section) */
256
0
      for (i = 0; i < array_count(found->references); i++)
257
0
      {
258
0
        array_get(found->references, i, &ref);
259
0
        resolve_reference(this, ref, sections);
260
0
      }
261
0
    }
262
0
  }
263
814k
  if (!ignore_refs && section != found && section->references)
264
0
  {
265
    /* find matching sub-sections relative to the referenced sections */
266
0
    for (i = 0; i < array_count(section->references); i++)
267
0
    {
268
0
      array_get(section->references, i, &ref);
269
0
      references = NULL;
270
0
      resolve_reference(this, ref, &references);
271
0
      for (j = 0; j < array_count(references); j++)
272
0
      {
273
0
        array_get(references, j, &reference);
274
        /* ignore references in this referenced section, they were
275
         * resolved via resolve_reference() */
276
0
        find_sections_buffered(this, reference, start, key, args,
277
0
                     buf, len, TRUE, sections);
278
0
      }
279
0
      array_destroy(references);
280
0
    }
281
0
  }
282
814k
}
283
284
/**
285
 * Ensure that the section with the given key exists (not thread-safe).
286
 */
287
static section_t *ensure_section(private_settings_t *this, section_t *section,
288
                 const char *key, va_list args)
289
44.1k
{
290
44.1k
  char buf[128], keybuf[512];
291
292
44.1k
  if (snprintf(keybuf, sizeof(keybuf), "%s", key) >= sizeof(keybuf))
293
0
  {
294
0
    return NULL;
295
0
  }
296
44.1k
  return find_section_buffered(section, keybuf, keybuf, args, buf,
297
44.1k
                 sizeof(buf), TRUE);
298
44.1k
}
299
300
/**
301
 * Find a section by a given key with resolved references (not thread-safe!).
302
 * The array is allocated. NULL is returned if no sections are found.
303
 */
304
static array_t *find_sections(private_settings_t *this, section_t *section,
305
                char *key, va_list args, array_t **sections)
306
814k
{
307
814k
  char buf[128], keybuf[512];
308
309
814k
  if (snprintf(keybuf, sizeof(keybuf), "%s", key) >= sizeof(keybuf))
310
0
  {
311
0
    return NULL;
312
0
  }
313
814k
  find_sections_buffered(this, section, keybuf, keybuf, args, buf,
314
814k
               sizeof(buf), FALSE, sections);
315
814k
  return *sections;
316
814k
}
317
318
/**
319
 * Find the key/value pair for a key, using buffered key, reusable buffer
320
 * There are two modes: 1. To find a key at an exact location and create the
321
 * sections (and key/value pair) if necessary, don't pass an array for sections.
322
 * 2. To find a key and follow references pass a pointer to an array to store
323
 * visited sections. NULL is returned in this case if the key is not found.
324
 */
325
static kv_t *find_value_buffered(private_settings_t *this, section_t *section,
326
                 char *start, char *key, va_list args,
327
                 char *buf, int len, bool ignore_refs,
328
                 array_t **sections)
329
1.62M
{
330
1.62M
  section_t *found = NULL;
331
1.62M
  kv_t *kv = NULL;
332
1.62M
  section_ref_t *ref;
333
1.62M
  array_t *references;
334
1.62M
  char *pos;
335
1.62M
  int i, j;
336
337
1.62M
  if (!section)
338
0
  {
339
0
    return NULL;
340
0
  }
341
1.62M
  pos = strchr(key, '.');
342
1.62M
  if (pos)
343
1.38M
  {
344
1.38M
    *pos = '\0';
345
1.38M
    if (!print_key(buf, len, start, key, args))
346
0
    {
347
0
      return NULL;
348
0
    }
349
    /* restore so we can follow references */
350
1.38M
    *pos = '.';
351
1.38M
    if (!strlen(buf))
352
0
    {
353
0
      found = section;
354
0
    }
355
1.38M
    else if (array_bsearch(section->sections, buf, settings_section_find,
356
1.38M
                 &found) == -1)
357
574k
    {
358
574k
      if (!sections)
359
0
      {
360
0
        found = settings_section_create(strdup(buf));
361
0
        settings_section_add(section, found, NULL);
362
0
      }
363
574k
    }
364
1.38M
    if (found)
365
814k
    {
366
814k
      kv = find_value_buffered(this, found, start, pos+1, args, buf, len,
367
814k
                   FALSE, sections);
368
814k
    }
369
1.38M
  }
370
239k
  else
371
239k
  {
372
239k
    if (sections)
373
239k
    {
374
239k
      array_insert_create(sections, ARRAY_TAIL, section);
375
239k
    }
376
239k
    if (!print_key(buf, len, start, key, args))
377
0
    {
378
0
      return NULL;
379
0
    }
380
239k
    if (array_bsearch(section->kv, buf, settings_kv_find, &kv) == -1)
381
239k
    {
382
239k
      if (!sections)
383
0
      {
384
0
        kv = settings_kv_create(strdup(buf), NULL);
385
0
        settings_kv_add(section, kv, NULL);
386
0
      }
387
239k
    }
388
239k
  }
389
1.62M
  if (!kv && !ignore_refs && sections && section->references)
390
814k
  {
391
    /* find key relative to the referenced sections */
392
1.62M
    for (i = 0; !kv && i < array_count(section->references); i++)
393
814k
    {
394
814k
      array_get(section->references, i, &ref);
395
814k
      references = NULL;
396
814k
      resolve_reference(this, ref, &references);
397
814k
      for (j = 0; !kv && j < array_count(references); j++)
398
0
      {
399
0
        array_get(references, j, &found);
400
        /* ignore if already added to avoid loops */
401
0
        if (!has_section(*sections, found))
402
0
        {
403
          /* ignore references in this referenced section, they were
404
           * resolved via resolve_reference() */
405
0
          kv = find_value_buffered(this, found, start, key, args,
406
0
                       buf, len, TRUE, sections);
407
0
        }
408
0
      }
409
814k
      array_destroy(references);
410
814k
    }
411
814k
  }
412
1.62M
  return kv;
413
1.62M
}
414
415
/**
416
 * Remove the key/value pair for a key, using buffered key, reusable buffer
417
 */
418
static void remove_value_buffered(private_settings_t *this, section_t *section,
419
                  char *start, char *key, va_list args,
420
                  char *buf, int len)
421
0
{
422
0
  section_t *found = NULL;
423
0
  kv_t *kv = NULL, *ordered = NULL;
424
0
  char *pos;
425
0
  int idx, i;
426
427
0
  if (!section)
428
0
  {
429
0
    return;
430
0
  }
431
0
  pos = strchr(key, '.');
432
0
  if (pos)
433
0
  {
434
0
    *pos = '\0';
435
0
    pos++;
436
0
  }
437
0
  if (!print_key(buf, len, start, key, args))
438
0
  {
439
0
    return;
440
0
  }
441
0
  if (!strlen(buf))
442
0
  {
443
0
    found = section;
444
0
  }
445
0
  if (pos)
446
0
  {
447
0
    if (array_bsearch(section->sections, buf, settings_section_find,
448
0
              &found) != -1)
449
0
    {
450
0
      remove_value_buffered(this, found, start, pos, args, buf, len);
451
0
    }
452
0
  }
453
0
  else
454
0
  {
455
0
    idx = array_bsearch(section->kv, buf, settings_kv_find, &kv);
456
0
    if (idx != -1)
457
0
    {
458
0
      array_remove(section->kv, idx, NULL);
459
0
      for (i = 0; i < array_count(section->kv_order); i++)
460
0
      {
461
0
        array_get(section->kv_order, i, &ordered);
462
0
        if (kv == ordered)
463
0
        {
464
0
          array_remove(section->kv_order, i, NULL);
465
0
          settings_kv_destroy(kv, this->contents);
466
0
          break;
467
0
        }
468
0
      }
469
0
    }
470
0
  }
471
0
}
472
473
/*
474
 * Described in header
475
 */
476
void settings_remove_value(settings_t *settings, char *key, ...)
477
0
{
478
0
  private_settings_t *this = (private_settings_t*)settings;
479
0
  char buf[128], keybuf[512];
480
0
  va_list args;
481
482
0
  if (snprintf(keybuf, sizeof(keybuf), "%s", key) >= sizeof(keybuf))
483
0
  {
484
0
    return;
485
0
  }
486
0
  va_start(args, key);
487
488
0
  this->lock->read_lock(this->lock);
489
0
  remove_value_buffered(this, this->top, keybuf, keybuf, args, buf,
490
0
              sizeof(buf));
491
0
  this->lock->unlock(this->lock);
492
493
0
  va_end(args);
494
0
}
495
496
/**
497
 * Find the string value for a key (thread-safe).
498
 */
499
static char *find_value(private_settings_t *this, section_t *section,
500
            char *key, va_list args)
501
814k
{
502
814k
  char buf[128], keybuf[512], *value = NULL;
503
814k
  array_t *sections = NULL;
504
814k
  kv_t *kv;
505
506
814k
  if (snprintf(keybuf, sizeof(keybuf), "%s", key) >= sizeof(keybuf))
507
0
  {
508
0
    return NULL;
509
0
  }
510
814k
  this->lock->read_lock(this->lock);
511
814k
  kv = find_value_buffered(this, section, keybuf, keybuf, args,
512
814k
               buf, sizeof(buf), FALSE, &sections);
513
814k
  if (kv)
514
0
  {
515
0
    value = kv->value;
516
0
  }
517
814k
  this->lock->unlock(this->lock);
518
814k
  array_destroy(sections);
519
814k
  return value;
520
814k
}
521
522
/**
523
 * Set a value to a copy of the given string (thread-safe).
524
 */
525
static void set_value(private_settings_t *this, section_t *section,
526
            char *key, va_list args, char *value)
527
0
{
528
0
  char buf[128], keybuf[512];
529
0
  kv_t *kv;
530
531
0
  if (snprintf(keybuf, sizeof(keybuf), "%s", key) >= sizeof(keybuf))
532
0
  {
533
0
    return;
534
0
  }
535
0
  this->lock->write_lock(this->lock);
536
0
  kv = find_value_buffered(this, section, keybuf, keybuf, args,
537
0
               buf, sizeof(buf), FALSE, NULL);
538
0
  if (kv)
539
0
  {
540
0
    settings_kv_set(kv, strdupnull(value), this->contents);
541
0
  }
542
0
  this->lock->unlock(this->lock);
543
0
}
544
545
METHOD(settings_t, get_str, char*,
546
  private_settings_t *this, char *key, char *def, ...)
547
104k
{
548
104k
  char *value;
549
104k
  va_list args;
550
551
104k
  va_start(args, def);
552
104k
  value = find_value(this, this->top, key, args);
553
104k
  va_end(args);
554
104k
  if (value)
555
0
  {
556
0
    return value;
557
0
  }
558
104k
  return def;
559
104k
}
560
561
/**
562
 * Described in header
563
 */
564
inline bool settings_value_as_bool(char *value, bool def)
565
449k
{
566
449k
  if (value)
567
0
  {
568
0
    if (strcaseeq(value, "1") ||
569
0
      strcaseeq(value, "yes") ||
570
0
      strcaseeq(value, "true") ||
571
0
      strcaseeq(value, "enabled"))
572
0
    {
573
0
      return TRUE;
574
0
    }
575
0
    else if (strcaseeq(value, "0") ||
576
0
         strcaseeq(value, "no") ||
577
0
         strcaseeq(value, "false") ||
578
0
         strcaseeq(value, "disabled"))
579
0
    {
580
0
      return FALSE;
581
0
    }
582
0
  }
583
449k
  return def;
584
449k
}
585
586
METHOD(settings_t, get_bool, bool,
587
  private_settings_t *this, char *key, int def, ...)
588
449k
{
589
449k
  char *value;
590
449k
  va_list args;
591
592
  /* we can't use bool for def due to this call */
593
449k
  va_start(args, def);
594
449k
  value = find_value(this, this->top, key, args);
595
449k
  va_end(args);
596
449k
  return settings_value_as_bool(value, def);
597
449k
}
598
599
/**
600
 * Described in header
601
 */
602
inline int settings_value_as_int(char *value, int def)
603
260k
{
604
260k
  int intval;
605
260k
  char *end;
606
260k
  int base = 10;
607
608
260k
  if (value)
609
0
  {
610
0
    errno = 0;
611
0
    if (value[0] == '0' && value[1] == 'x')
612
0
    { /* manually detect 0x prefix as we want to avoid octal encoding */
613
0
      base = 16;
614
0
    }
615
0
    intval = strtoul(value, &end, base);
616
0
    if (errno == 0 && *end == 0 && end != value)
617
0
    {
618
0
      return intval;
619
0
    }
620
0
  }
621
260k
  return def;
622
260k
}
623
624
METHOD(settings_t, get_int, int,
625
  private_settings_t *this, char *key, int def, ...)
626
260k
{
627
260k
  char *value;
628
260k
  va_list args;
629
630
260k
  va_start(args, def);
631
260k
  value = find_value(this, this->top, key, args);
632
260k
  va_end(args);
633
260k
  return settings_value_as_int(value, def);
634
260k
}
635
636
/**
637
 * Described in header
638
 */
639
inline uint64_t settings_value_as_uint64(char *value, uint64_t def)
640
0
{
641
0
  uint64_t intval;
642
0
  char *end;
643
0
  int base = 10;
644
645
0
  if (value)
646
0
  {
647
0
    errno = 0;
648
0
    if (value[0] == '0' && value[1] == 'x')
649
0
    { /* manually detect 0x prefix as we want to avoid octal encoding */
650
0
      base = 16;
651
0
    }
652
0
    intval = strtoull(value, &end, base);
653
0
    if (errno == 0 && *end == 0 && end != value)
654
0
    {
655
0
      return intval;
656
0
    }
657
0
  }
658
0
  return def;
659
0
}
660
661
/**
662
 * Described in header
663
 */
664
inline double settings_value_as_double(char *value, double def)
665
0
{
666
0
  double dval;
667
0
  char *end;
668
669
0
  if (value)
670
0
  {
671
0
    errno = 0;
672
0
    dval = strtod(value, &end);
673
0
    if (errno == 0 && *end == 0 && end != value)
674
0
    {
675
0
      return dval;
676
0
    }
677
0
  }
678
0
  return def;
679
0
}
680
681
METHOD(settings_t, get_double, double,
682
  private_settings_t *this, char *key, double def, ...)
683
0
{
684
0
  char *value;
685
0
  va_list args;
686
687
0
  va_start(args, def);
688
0
  value = find_value(this, this->top, key, args);
689
0
  va_end(args);
690
0
  return settings_value_as_double(value, def);
691
0
}
692
693
/**
694
 * Described in header
695
 */
696
inline uint32_t settings_value_as_time(char *value, uint32_t def)
697
0
{
698
0
  time_t val;
699
700
0
  if (timespan_from_string(value, NULL, &val))
701
0
  {
702
0
    return val;
703
0
  }
704
0
  return def;
705
0
}
706
707
METHOD(settings_t, get_time, uint32_t,
708
  private_settings_t *this, char *key, uint32_t def, ...)
709
0
{
710
0
  char *value;
711
0
  va_list args;
712
713
0
  va_start(args, def);
714
0
  value = find_value(this, this->top, key, args);
715
0
  va_end(args);
716
0
  return settings_value_as_time(value, def);
717
0
}
718
719
METHOD(settings_t, set_str, void,
720
  private_settings_t *this, char *key, char *value, ...)
721
0
{
722
0
  va_list args;
723
0
  va_start(args, value);
724
0
  set_value(this, this->top, key, args, value);
725
0
  va_end(args);
726
0
}
727
728
METHOD(settings_t, set_bool, void,
729
  private_settings_t *this, char *key, int value, ...)
730
0
{
731
0
  va_list args;
732
  /* we can't use bool for value due to this call */
733
0
  va_start(args, value);
734
0
  set_value(this, this->top, key, args, value ? "1" : "0");
735
0
  va_end(args);
736
0
}
737
738
METHOD(settings_t, set_int, void,
739
  private_settings_t *this, char *key, int value, ...)
740
0
{
741
0
  char val[16];
742
0
  va_list args;
743
0
  va_start(args, value);
744
0
  if (snprintf(val, sizeof(val), "%d", value) < sizeof(val))
745
0
  {
746
0
    set_value(this, this->top, key, args, val);
747
0
  }
748
0
  va_end(args);
749
0
}
750
751
METHOD(settings_t, set_double, void,
752
  private_settings_t *this, char *key, double value, ...)
753
0
{
754
0
  char val[64];
755
0
  va_list args;
756
0
  va_start(args, value);
757
0
  if (snprintf(val, sizeof(val), "%f", value) < sizeof(val))
758
0
  {
759
0
    set_value(this, this->top, key, args, val);
760
0
  }
761
0
  va_end(args);
762
0
}
763
764
METHOD(settings_t, set_time, void,
765
  private_settings_t *this, char *key, uint32_t value, ...)
766
0
{
767
0
  char val[16];
768
0
  va_list args;
769
0
  va_start(args, value);
770
0
  if (snprintf(val, sizeof(val), "%u", value) < sizeof(val))
771
0
  {
772
0
    set_value(this, this->top, key, args, val);
773
0
  }
774
0
  va_end(args);
775
0
}
776
777
METHOD(settings_t, set_default_str, bool,
778
  private_settings_t *this, char *key, char *value, ...)
779
0
{
780
0
  char *old;
781
0
  va_list args;
782
783
0
  va_start(args, value);
784
0
  old = find_value(this, this->top, key, args);
785
0
  va_end(args);
786
787
0
  if (!old)
788
0
  {
789
0
    va_start(args, value);
790
0
    set_value(this, this->top, key, args, value);
791
0
    va_end(args);
792
0
    return TRUE;
793
0
  }
794
0
  return FALSE;
795
0
}
796
797
/**
798
 * Data for enumerators
799
 */
800
typedef struct {
801
  /** settings_t instance */
802
  private_settings_t *settings;
803
  /** sections to enumerate */
804
  array_t *sections;
805
  /** sections/keys that were already enumerated */
806
  hashtable_t *seen;
807
} enumerator_data_t;
808
809
CALLBACK(enumerator_destroy, void,
810
  enumerator_data_t *this)
811
0
{
812
0
  this->settings->lock->unlock(this->settings->lock);
813
0
  this->seen->destroy(this->seen);
814
0
  array_destroy(this->sections);
815
0
  free(this);
816
0
}
817
818
CALLBACK(section_filter, bool,
819
  hashtable_t *seen, enumerator_t *orig, va_list args)
820
0
{
821
0
  section_t *section;
822
0
  char **out;
823
824
0
  VA_ARGS_VGET(args, out);
825
826
0
  while (orig->enumerate(orig, &section))
827
0
  {
828
0
    if (seen->get(seen, section->name))
829
0
    {
830
0
      continue;
831
0
    }
832
0
    *out = section->name;
833
0
    seen->put(seen, section->name, section->name);
834
0
    return TRUE;
835
0
  }
836
0
  return FALSE;
837
0
}
838
839
/**
840
 * Enumerate sections of the given section
841
 */
842
static enumerator_t *section_enumerator(section_t *section,
843
                    enumerator_data_t *data)
844
0
{
845
0
  return enumerator_create_filter(
846
0
              array_create_enumerator(section->sections_order),
847
0
              section_filter, data->seen, NULL);
848
0
}
849
850
METHOD(settings_t, create_section_enumerator, enumerator_t*,
851
  private_settings_t *this, char *key, ...)
852
0
{
853
0
  enumerator_data_t *data;
854
0
  array_t *sections = NULL;
855
0
  va_list args;
856
857
0
  this->lock->read_lock(this->lock);
858
0
  va_start(args, key);
859
0
  sections = find_sections(this, this->top, key, args, &sections);
860
0
  va_end(args);
861
862
0
  if (!sections)
863
0
  {
864
0
    this->lock->unlock(this->lock);
865
0
    return enumerator_create_empty();
866
0
  }
867
0
  INIT(data,
868
0
    .settings = this,
869
0
    .sections = sections,
870
0
    .seen = hashtable_create(hashtable_hash_str, hashtable_equals_str, 8),
871
0
  );
872
0
  return enumerator_create_nested(array_create_enumerator(sections),
873
0
            (void*)section_enumerator, data, enumerator_destroy);
874
0
}
875
876
CALLBACK(kv_filter, bool,
877
  hashtable_t *seen, enumerator_t *orig, va_list args)
878
0
{
879
0
  kv_t *kv;
880
0
  char **key, **value;
881
882
0
  VA_ARGS_VGET(args, key, value);
883
884
0
  while (orig->enumerate(orig, &kv))
885
0
  {
886
0
    if (seen->get(seen, kv->key))
887
0
    {
888
0
      continue;
889
0
    }
890
0
    seen->put(seen, kv->key, kv->key);
891
0
    if (!kv->value)
892
0
    {
893
0
      continue;
894
0
    }
895
0
    *key = kv->key;
896
0
    *value = kv->value;
897
0
    return TRUE;
898
0
  }
899
0
  return FALSE;
900
0
}
901
902
/**
903
 * Enumerate key/value pairs of the given section
904
 */
905
static enumerator_t *kv_enumerator(section_t *section, enumerator_data_t *data)
906
0
{
907
0
  return enumerator_create_filter(array_create_enumerator(section->kv_order),
908
0
                  kv_filter, data->seen, NULL);
909
0
}
910
911
METHOD(settings_t, create_key_value_enumerator, enumerator_t*,
912
  private_settings_t *this, char *key, ...)
913
0
{
914
0
  enumerator_data_t *data;
915
0
  array_t *sections = NULL;
916
0
  va_list args;
917
918
0
  this->lock->read_lock(this->lock);
919
0
  va_start(args, key);
920
0
  sections = find_sections(this, this->top, key, args, &sections);
921
0
  va_end(args);
922
923
0
  if (!sections)
924
0
  {
925
0
    this->lock->unlock(this->lock);
926
0
    return enumerator_create_empty();
927
0
  }
928
0
  INIT(data,
929
0
    .settings = this,
930
0
    .sections = sections,
931
0
    .seen = hashtable_create(hashtable_hash_str, hashtable_equals_str, 8),
932
0
  );
933
0
  return enumerator_create_nested(array_create_enumerator(sections),
934
0
          (void*)kv_enumerator, data, (void*)enumerator_destroy);
935
0
}
936
937
METHOD(settings_t, add_fallback, void,
938
  private_settings_t *this, const char *key, const char *fallback, ...)
939
44.1k
{
940
44.1k
  section_t *section;
941
44.1k
  va_list args;
942
44.1k
  char buf[512];
943
944
44.1k
  this->lock->write_lock(this->lock);
945
44.1k
  va_start(args, fallback);
946
44.1k
  section = ensure_section(this, this->top, key, args);
947
44.1k
  va_end(args);
948
949
44.1k
  va_start(args, fallback);
950
44.1k
  if (section && vsnprintf(buf, sizeof(buf), fallback, args) < sizeof(buf))
951
44.1k
  {
952
44.1k
    settings_reference_add(section, strdup(buf), TRUE);
953
44.1k
  }
954
44.1k
  va_end(args);
955
44.1k
  this->lock->unlock(this->lock);
956
44.1k
}
957
958
/**
959
 * Load settings from files matching the given file pattern or from a string.
960
 * All files (even included ones) have to be loaded successfully.
961
 */
962
static section_t *load_internal(char *pattern, bool string)
963
54.6k
{
964
54.6k
  section_t *section;
965
54.6k
  bool loaded;
966
967
54.6k
  if (pattern == NULL || !pattern[0])
968
27.3k
  {
969
27.3k
    return settings_section_create(NULL);
970
27.3k
  }
971
972
27.3k
  section = settings_section_create(NULL);
973
27.3k
  loaded = string ? settings_parser_parse_string(section, pattern) :
974
27.3k
            settings_parser_parse_file(section, pattern);
975
27.3k
  if (!loaded)
976
27.3k
  {
977
27.3k
    settings_section_destroy(section, NULL);
978
27.3k
    section = NULL;
979
27.3k
  }
980
27.3k
  return section;
981
54.6k
}
982
983
/**
984
 * Add sections and values in "section" relative to "parent".
985
 * If merge is FALSE the contents of parent are replaced with the parsed
986
 * contents, otherwise they are merged together.
987
 *
988
 * Releases the write lock and destroys the given section.
989
 * If parent is NULL this is all that happens.
990
 */
991
static bool extend_section(private_settings_t *this, section_t *parent,
992
               section_t *section, bool merge)
993
27.3k
{
994
27.3k
  if (parent)
995
27.3k
  {
996
27.3k
    settings_section_extend(parent, section, this->contents, !merge);
997
27.3k
  }
998
27.3k
  this->lock->unlock(this->lock);
999
27.3k
  settings_section_destroy(section, NULL);
1000
27.3k
  return parent != NULL;
1001
27.3k
}
1002
1003
METHOD(settings_t, load_files, bool,
1004
  private_settings_t *this, char *pattern, bool merge)
1005
54.6k
{
1006
54.6k
  section_t *section;
1007
1008
54.6k
  section = load_internal(pattern, FALSE);
1009
54.6k
  if (!section)
1010
27.3k
  {
1011
27.3k
    return FALSE;
1012
27.3k
  }
1013
1014
27.3k
  this->lock->write_lock(this->lock);
1015
27.3k
  return extend_section(this, this->top, section, merge);
1016
54.6k
}
1017
1018
METHOD(settings_t, load_files_section, bool,
1019
  private_settings_t *this, char *pattern, bool merge, char *key, ...)
1020
0
{
1021
0
  section_t *section, *parent;
1022
0
  va_list args;
1023
1024
0
  section = load_internal(pattern, FALSE);
1025
0
  if (!section)
1026
0
  {
1027
0
    return FALSE;
1028
0
  }
1029
1030
0
  this->lock->write_lock(this->lock);
1031
1032
0
  va_start(args, key);
1033
0
  parent = ensure_section(this, this->top, key, args);
1034
0
  va_end(args);
1035
1036
0
  return extend_section(this, parent, section, merge);
1037
0
}
1038
1039
METHOD(settings_t, load_string, bool,
1040
  private_settings_t *this, char *settings, bool merge)
1041
0
{
1042
0
  section_t *section;
1043
1044
0
  section = load_internal(settings, TRUE);
1045
0
  if (!section)
1046
0
  {
1047
0
    return FALSE;
1048
0
  }
1049
1050
0
  this->lock->write_lock(this->lock);
1051
0
  return extend_section(this, this->top, section, merge);
1052
0
}
1053
1054
METHOD(settings_t, load_string_section, bool,
1055
  private_settings_t *this, char *settings, bool merge, char *key, ...)
1056
0
{
1057
0
  section_t *section, *parent;
1058
0
  va_list args;
1059
1060
0
  section = load_internal(settings, TRUE);
1061
0
  if (!section)
1062
0
  {
1063
0
    return FALSE;
1064
0
  }
1065
1066
0
  this->lock->write_lock(this->lock);
1067
1068
0
  va_start(args, key);
1069
0
  parent = ensure_section(this, this->top, key, args);
1070
0
  va_end(args);
1071
1072
0
  return extend_section(this, parent, section, merge);
1073
0
}
1074
1075
CALLBACK(clear_content, void,
1076
  char *str, int idx, void *clear)
1077
0
{
1078
0
  if (*(bool*)clear)
1079
0
  {
1080
0
    memwipe(str, strlen(str));
1081
0
  }
1082
0
  free(str);
1083
0
}
1084
1085
/**
1086
 * Destroy the settings object and optionally clear content memory
1087
 */
1088
static void destroy_settings(private_settings_t *this, bool clear)
1089
27.3k
{
1090
27.3k
  settings_section_destroy(this->top, clear ? this->contents : NULL);
1091
27.3k
  array_destroy_function(this->contents, clear_content, &clear);
1092
27.3k
  this->lock->destroy(this->lock);
1093
27.3k
  free(this);
1094
27.3k
}
1095
1096
METHOD(settings_t, destroy, void,
1097
  private_settings_t *this)
1098
27.3k
{
1099
27.3k
  destroy_settings(this, FALSE);
1100
27.3k
}
1101
1102
METHOD(settings_t, destroy_clear, void,
1103
  private_settings_t *this)
1104
0
{
1105
0
  destroy_settings(this, TRUE);
1106
0
}
1107
1108
static private_settings_t *settings_create_base()
1109
27.3k
{
1110
27.3k
  private_settings_t *this;
1111
1112
27.3k
  INIT(this,
1113
27.3k
    .public = {
1114
27.3k
      .get_str = _get_str,
1115
27.3k
      .get_int = _get_int,
1116
27.3k
      .get_double = _get_double,
1117
27.3k
      .get_time = _get_time,
1118
27.3k
      .get_bool = _get_bool,
1119
27.3k
      .set_str = _set_str,
1120
27.3k
      .set_int = _set_int,
1121
27.3k
      .set_double = _set_double,
1122
27.3k
      .set_time = _set_time,
1123
27.3k
      .set_bool = _set_bool,
1124
27.3k
      .set_default_str = _set_default_str,
1125
27.3k
      .create_section_enumerator = _create_section_enumerator,
1126
27.3k
      .create_key_value_enumerator = _create_key_value_enumerator,
1127
27.3k
      .add_fallback = _add_fallback,
1128
27.3k
      .load_files = _load_files,
1129
27.3k
      .load_files_section = _load_files_section,
1130
27.3k
      .load_string = _load_string,
1131
27.3k
      .load_string_section = _load_string_section,
1132
27.3k
      .destroy = _destroy,
1133
27.3k
      .destroy_clear = _destroy_clear,
1134
27.3k
    },
1135
27.3k
    .top = settings_section_create(NULL),
1136
27.3k
    .contents = array_create(0, 0),
1137
27.3k
    .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
1138
27.3k
  );
1139
27.3k
  return this;
1140
27.3k
}
1141
1142
/*
1143
 * see header file
1144
 */
1145
settings_t *settings_create(char *file)
1146
27.3k
{
1147
27.3k
  private_settings_t *this = settings_create_base();
1148
1149
27.3k
  load_files(this, file, FALSE);
1150
1151
27.3k
  return &this->public;
1152
27.3k
}
1153
1154
/*
1155
 * see header file
1156
 */
1157
settings_t *settings_create_string(char *settings)
1158
0
{
1159
0
  private_settings_t *this = settings_create_base();
1160
1161
0
  load_string(this, settings, FALSE);
1162
1163
0
  return &this->public;
1164
0
}