aboutsummaryrefslogtreecommitdiff
path: root/src/util/configuration.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/util/configuration.c')
-rw-r--r--src/util/configuration.c1096
1 files changed, 973 insertions, 123 deletions
diff --git a/src/util/configuration.c b/src/util/configuration.c
index d0090ae53..09a3a7d93 100644
--- a/src/util/configuration.c
+++ b/src/util/configuration.c
@@ -28,6 +28,8 @@
28#include "gnunet_os_lib.h" 28#include "gnunet_os_lib.h"
29#include "gnunet_configuration_lib.h" 29#include "gnunet_configuration_lib.h"
30#include "gnunet_disk_lib.h" 30#include "gnunet_disk_lib.h"
31#include "gnunet_buffer_lib.h"
32#include "gnunet_container_lib.h"
31 33
32#define LOG(kind, ...) GNUNET_log_from (kind, "util", __VA_ARGS__) 34#define LOG(kind, ...) GNUNET_log_from (kind, "util", __VA_ARGS__)
33 35
@@ -53,6 +55,16 @@ struct ConfigEntry
53 * current, committed value 55 * current, committed value
54 */ 56 */
55 char *val; 57 char *val;
58
59 /**
60 * Diagnostics information for the filename.
61 */
62 char *hint_filename;
63
64 /**
65 * Diagnostics information for the line number.
66 */
67 unsigned int hint_lineno;
56}; 68};
57 69
58 70
@@ -75,6 +87,62 @@ struct ConfigSection
75 * name of the section 87 * name of the section
76 */ 88 */
77 char *name; 89 char *name;
90
91 /**
92 * Is the configuration section marked as inaccessible?
93 *
94 * This can happen if the section name is used in an @inline-secret@
95 * directive, but the referenced file can't be found or accessed.
96 */
97 bool inaccessible;
98
99 /**
100 * Diagnostics hint for the secret file.
101 */
102 char *hint_secret_filename;
103
104 /**
105 * Extra information regarding permissions of the secret file.
106 */
107 char *hint_secret_stat;
108
109 /**
110 * For secret sections: Where was this inlined from?
111 */
112 char *hint_inlined_from_filename;
113
114 /**
115 * For secret sections: Where was this inlined from?
116 */
117 unsigned int hint_inlined_from_line;
118};
119
120struct ConfigFile
121{
122 /**
123 * Source filename.
124 */
125 char *source_filename;
126
127 /**
128 * Level in the tree of loaded config files.
129 */
130 unsigned int level;
131
132 struct ConfigFile *prev;
133
134 struct ConfigFile *next;
135
136 /**
137 * Was this configuration file parsed via
138 * @inline-secret@?
139 */
140 char *hint_restrict_section;
141
142 /**
143 * Was this configuration file inaccessible?
144 */
145 bool hint_inaccessible;
78}; 146};
79 147
80 148
@@ -89,11 +157,48 @@ struct GNUNET_CONFIGURATION_Handle
89 struct ConfigSection *sections; 157 struct ConfigSection *sections;
90 158
91 /** 159 /**
160 * Linked list of loaded files.
161 */
162 struct ConfigFile *loaded_files_head;
163
164 /**
165 * Linked list of loaded files.
166 */
167 struct ConfigFile *loaded_files_tail;
168
169 /**
170 * Current nesting level of file loading.
171 */
172 unsigned int current_nest_level;
173
174 /**
175 * Enable diagnostics.
176 */
177 bool diagnostics;
178
179 /**
92 * Modification indication since last save 180 * Modification indication since last save
93 * #GNUNET_NO if clean, #GNUNET_YES if dirty, 181 * #GNUNET_NO if clean, #GNUNET_YES if dirty,
94 * #GNUNET_SYSERR on error (i.e. last save failed) 182 * #GNUNET_SYSERR on error (i.e. last save failed)
95 */ 183 */
96 enum GNUNET_GenericReturnValue dirty; 184 enum GNUNET_GenericReturnValue dirty;
185
186 /**
187 * Was the configuration ever loaded via GNUNET_CONFIGURATION_load?
188 */
189 bool load_called;
190
191 /**
192 * Name of the entry point configuration file.
193 */
194 char *main_filename;
195
196 /**
197 * When parsing into this configuration, and this value
198 * is non-NULL, only parse sections of the same name,
199 * and ban import statements.
200 */
201 const char *restrict_section;
97}; 202};
98 203
99 204
@@ -109,6 +214,14 @@ struct DiffHandle
109}; 214};
110 215
111 216
217void
218GNUNET_CONFIGURATION_enable_diagnostics (struct
219 GNUNET_CONFIGURATION_Handle *cfg)
220{
221 cfg->diagnostics = true;
222}
223
224
112struct GNUNET_CONFIGURATION_Handle * 225struct GNUNET_CONFIGURATION_Handle *
113GNUNET_CONFIGURATION_create () 226GNUNET_CONFIGURATION_create ()
114{ 227{
@@ -198,9 +311,20 @@ void
198GNUNET_CONFIGURATION_destroy (struct GNUNET_CONFIGURATION_Handle *cfg) 311GNUNET_CONFIGURATION_destroy (struct GNUNET_CONFIGURATION_Handle *cfg)
199{ 312{
200 struct ConfigSection *sec; 313 struct ConfigSection *sec;
314 struct ConfigFile *cf;
201 315
202 while (NULL != (sec = cfg->sections)) 316 while (NULL != (sec = cfg->sections))
203 GNUNET_CONFIGURATION_remove_section (cfg, sec->name); 317 GNUNET_CONFIGURATION_remove_section (cfg, sec->name);
318 while (NULL != (cf = cfg->loaded_files_head))
319 {
320 GNUNET_free (cf->hint_restrict_section);
321 GNUNET_free (cf->source_filename);
322 GNUNET_CONTAINER_DLL_remove (cfg->loaded_files_head,
323 cfg->loaded_files_tail,
324 cf);
325 GNUNET_free (cf);
326 }
327 GNUNET_free (cfg->main_filename);
204 GNUNET_free (cfg); 328 GNUNET_free (cfg);
205} 329}
206 330
@@ -214,7 +338,9 @@ GNUNET_CONFIGURATION_parse_and_run (const char *filename,
214 enum GNUNET_GenericReturnValue ret; 338 enum GNUNET_GenericReturnValue ret;
215 339
216 cfg = GNUNET_CONFIGURATION_create (); 340 cfg = GNUNET_CONFIGURATION_create ();
217 if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfg, filename)) 341 if (GNUNET_OK !=
342 GNUNET_CONFIGURATION_load (cfg,
343 filename))
218 { 344 {
219 GNUNET_break (0); 345 GNUNET_break (0);
220 GNUNET_CONFIGURATION_destroy (cfg); 346 GNUNET_CONFIGURATION_destroy (cfg);
@@ -226,34 +352,381 @@ GNUNET_CONFIGURATION_parse_and_run (const char *filename,
226} 352}
227 353
228 354
355/**
356 * Closure to collect_files_cb.
357 */
358struct CollectFilesContext
359{
360 /**
361 * Collected files from globbing.
362 */
363 char **files;
364
365 /**
366 * Size of the files array.
367 */
368 unsigned int files_length;
369};
370
371
372/**
373 * Function called with a filename.
374 *
375 * @param cls closure
376 * @param filename complete filename (absolute path)
377 * @return #GNUNET_OK to continue to iterate,
378 * #GNUNET_NO to stop iteration with no error,
379 * #GNUNET_SYSERR to abort iteration with error!
380 */
381static int
382collect_files_cb (void *cls,
383 const char *filename)
384{
385 struct CollectFilesContext *igc = cls;
386
387 GNUNET_array_append (igc->files,
388 igc->files_length,
389 GNUNET_strdup (filename));
390 return GNUNET_OK;
391}
392
393
394/**
395 * Find a section entry from a configuration.
396 *
397 * @param cfg configuration to search in
398 * @param section name of the section to look for
399 * @return matching entry, NULL if not found
400 */
401static struct ConfigSection *
402find_section (const struct GNUNET_CONFIGURATION_Handle *cfg,
403 const char *section)
404{
405 struct ConfigSection *pos;
406
407 pos = cfg->sections;
408 while ((pos != NULL) && (0 != strcasecmp (section, pos->name)))
409 pos = pos->next;
410 return pos;
411}
412
413
414static int
415pstrcmp (const void *a, const void *b)
416{
417 return strcmp (*((const char **) a), *((const char **) b));
418}
419
420
421/**
422 * Handle an inline directive.
423 *
424 * @returns #GNUNET_SYSERR on error, #GNUNET_OK otherwise
425 */
426enum GNUNET_GenericReturnValue
427handle_inline (struct GNUNET_CONFIGURATION_Handle *cfg,
428 const char *path_or_glob,
429 bool path_is_glob,
430 const char *restrict_section,
431 const char *source_filename,
432 unsigned int source_lineno)
433{
434 char *inline_path = NULL;
435 struct GNUNET_CONFIGURATION_Handle *other_cfg = NULL;
436 struct CollectFilesContext igc = {
437 .files = NULL,
438 .files_length = 0,
439 };
440 enum GNUNET_GenericReturnValue fun_ret;
441 unsigned int old_nest_level = cfg->current_nest_level++;
442
443 /* We support the section restriction only for non-globs */
444 GNUNET_assert (! (path_is_glob && (NULL != restrict_section)));
445
446 if (NULL == source_filename)
447 {
448 LOG (GNUNET_ERROR_TYPE_DEBUG,
449 "Refusing to parse inline configurations, "
450 "not allowed without source filename!\n");
451 fun_ret = GNUNET_SYSERR;
452 goto cleanup;
453 }
454
455 if ('/' == *path_or_glob)
456 inline_path = GNUNET_strdup (path_or_glob);
457 else
458 {
459 /* We compute the canonical, absolute path first,
460 so that relative imports resolve properly with symlinked
461 config files. */
462 char *source_realpath;
463 char *endsep;
464
465 source_realpath = realpath (source_filename,
466 NULL);
467 if (NULL == source_realpath)
468 {
469 /* Couldn't even resolve path of base dir. */
470 GNUNET_break (0);
471 /* failed to parse included config */
472 fun_ret = GNUNET_SYSERR;
473 goto cleanup;
474 }
475 endsep = strrchr (source_realpath, '/');
476 GNUNET_assert (NULL != endsep);
477 *endsep = '\0';
478 GNUNET_asprintf (&inline_path,
479 "%s/%s",
480 source_realpath,
481 path_or_glob);
482 free (source_realpath);
483 }
484
485 if (path_is_glob)
486 {
487 int nret;
488
489 LOG (GNUNET_ERROR_TYPE_DEBUG,
490 "processing config glob '%s'\n",
491 inline_path);
492
493 nret = GNUNET_DISK_glob (inline_path, collect_files_cb, &igc);
494 if (-1 == nret)
495 {
496 fun_ret = GNUNET_SYSERR;
497 goto cleanup;
498 }
499 GNUNET_assert (nret == igc.files_length);
500 qsort (igc.files, igc.files_length, sizeof (char *), pstrcmp);
501 for (int i = 0; i < nret; i++)
502 {
503 if (GNUNET_OK !=
504 GNUNET_CONFIGURATION_parse (cfg,
505 igc.files[i]))
506 {
507 fun_ret = GNUNET_SYSERR;
508 goto cleanup;
509 }
510 }
511 fun_ret = GNUNET_OK;
512 }
513 else if (NULL != restrict_section)
514 {
515 enum GNUNET_GenericReturnValue inner_ret;
516 struct ConfigSection *cs;
517 struct ConfigFile *cf = GNUNET_new (struct ConfigFile);
518
519 inner_ret = GNUNET_DISK_file_test_read (inline_path);
520
521 cs = find_section (cfg, restrict_section);
522
523 if (NULL == cs)
524 {
525 cs = GNUNET_new (struct ConfigSection);
526 cs->name = GNUNET_strdup (restrict_section);
527 cs->next = cfg->sections;
528 cfg->sections = cs;
529 cs->entries = NULL;
530 }
531 if (cfg->diagnostics)
532 {
533 char *sfn = GNUNET_STRINGS_filename_expand (inline_path);
534 struct stat istat;
535
536 cs->hint_secret_filename = sfn;
537 if (0 == stat (sfn, &istat))
538 {
539 struct passwd *pw = getpwuid (istat.st_uid);
540 struct group *gr = getgrgid (istat.st_gid);
541 char *pwname = (NULL == pw) ? "<unknown>" : pw->pw_name;
542 char *grname = (NULL == gr) ? "<unknown>" : gr->gr_name;
543
544 GNUNET_asprintf (&cs->hint_secret_stat,
545 "%s:%s %o",
546 pwname,
547 grname,
548 istat.st_mode);
549 }
550 else
551 {
552 cs->hint_secret_stat = GNUNET_strdup ("<can't stat file>");
553 }
554 if (source_filename)
555 {
556 /* Possible that this secret section has been inlined before */
557 GNUNET_free (cs->hint_inlined_from_filename);
558 cs->hint_inlined_from_filename = GNUNET_strdup (source_filename);
559 cs->hint_inlined_from_line = source_lineno;
560 }
561 }
562
563 /* Put file in the load list for diagnostics, even if we can't access it. */
564 {
565 cf->level = cfg->current_nest_level;
566 cf->source_filename = GNUNET_strdup (inline_path);
567 cf->hint_restrict_section = GNUNET_strdup (restrict_section);
568 GNUNET_CONTAINER_DLL_insert_tail (cfg->loaded_files_head,
569 cfg->loaded_files_tail,
570 cf);
571 }
572
573 if (GNUNET_OK != inner_ret)
574 {
575 cs->inaccessible = true;
576 cf->hint_inaccessible = true;
577 /* File can't be accessed, but that's okay. */
578 fun_ret = GNUNET_OK;
579 goto cleanup;
580 }
581
582 other_cfg = GNUNET_CONFIGURATION_create ();
583 other_cfg->restrict_section = restrict_section;
584 inner_ret = GNUNET_CONFIGURATION_parse (other_cfg,
585 inline_path);
586 if (GNUNET_OK != inner_ret)
587 {
588 cf->hint_inaccessible = true;
589 fun_ret = inner_ret;
590 goto cleanup;
591 }
592
593 cs = find_section (other_cfg, restrict_section);
594 if (NULL == cs)
595 {
596 LOG (GNUNET_ERROR_TYPE_INFO,
597 "Configuration file '%s' loaded with @inline-secret@ "
598 "does not contain section '%s'.\n",
599 inline_path,
600 restrict_section);
601 /* Inlined onfiguration is accessible but doesn't contain any values.
602 We treat this as if the inlined section was empty, and do not
603 consider it an error. */
604 fun_ret = GNUNET_OK;
605 goto cleanup;
606 }
607 for (struct ConfigEntry *ce = cs->entries;
608 NULL != ce;
609 ce = ce->next)
610 GNUNET_CONFIGURATION_set_value_string (cfg,
611 restrict_section,
612 ce->key,
613 ce->val);
614 fun_ret = GNUNET_OK;
615 }
616 else if (GNUNET_OK !=
617 GNUNET_CONFIGURATION_parse (cfg,
618 inline_path))
619 {
620 fun_ret = GNUNET_SYSERR;
621 goto cleanup;
622 }
623 else
624 {
625 fun_ret = GNUNET_OK;
626 }
627cleanup:
628 cfg->current_nest_level = old_nest_level;
629 if (NULL != other_cfg)
630 GNUNET_CONFIGURATION_destroy (other_cfg);
631 GNUNET_free (inline_path);
632 if (igc.files_length > 0)
633 {
634 for (size_t i = 0; i < igc.files_length; i++)
635 GNUNET_free (igc.files[i]);
636 GNUNET_array_grow (igc.files, igc.files_length, 0);
637 }
638 return fun_ret;
639}
640
641
642/**
643 * Find an entry from a configuration.
644 *
645 * @param cfg handle to the configuration
646 * @param section section the option is in
647 * @param key the option
648 * @return matching entry, NULL if not found
649 */
650static struct ConfigEntry *
651find_entry (const struct GNUNET_CONFIGURATION_Handle *cfg,
652 const char *section,
653 const char *key)
654{
655 struct ConfigSection *sec;
656 struct ConfigEntry *pos;
657
658 if (NULL == (sec = find_section (cfg, section)))
659 return NULL;
660 if (sec->inaccessible)
661 {
662 LOG (GNUNET_ERROR_TYPE_WARNING,
663 "Section '%s' is marked as inaccessible, because the configuration "
664 " file that contains the section can't be read. Attempts to use "
665 "option '%s' will fail.\n",
666 section,
667 key);
668 return NULL;
669 }
670 pos = sec->entries;
671 while ((pos != NULL) && (0 != strcasecmp (key, pos->key)))
672 pos = pos->next;
673 return pos;
674}
675
676
677/**
678 * Set a configuration hint.
679 *
680 * @param cfg configuration handle
681 * @param section section
682 * @param option config option
683 * @param hint_filename
684 * @param hint_line
685 */
686static void
687set_entry_hint (struct GNUNET_CONFIGURATION_Handle *cfg,
688 const char *section,
689 const char *option,
690 const char *hint_filename,
691 unsigned int hint_line)
692{
693 struct ConfigEntry *e = find_entry (cfg, section, option);
694 if (! cfg->diagnostics)
695 return;
696 if (! e)
697 return;
698 e->hint_filename = GNUNET_strdup (hint_filename);
699 e->hint_lineno = hint_line;
700}
701
702
229enum GNUNET_GenericReturnValue 703enum GNUNET_GenericReturnValue
230GNUNET_CONFIGURATION_deserialize (struct GNUNET_CONFIGURATION_Handle *cfg, 704GNUNET_CONFIGURATION_deserialize (struct GNUNET_CONFIGURATION_Handle *cfg,
231 const char *mem, 705 const char *mem,
232 size_t size, 706 size_t size,
233 const char *basedir) 707 const char *source_filename)
234{ 708{
235 char *line;
236 char *line_orig;
237 size_t line_size; 709 size_t line_size;
238 char *pos;
239 unsigned int nr; 710 unsigned int nr;
240 size_t r_bytes; 711 size_t r_bytes;
241 size_t to_read; 712 size_t to_read;
242 size_t i;
243 int emptyline;
244 enum GNUNET_GenericReturnValue ret; 713 enum GNUNET_GenericReturnValue ret;
245 char *section; 714 char *section;
246 char *eq; 715 char *eq;
247 char *tag; 716 char *tag;
248 char *value; 717 char *value;
718 char *line_orig = NULL;
249 719
250 ret = GNUNET_OK; 720 ret = GNUNET_OK;
251 section = GNUNET_strdup (""); 721 section = NULL;
252 nr = 0; 722 nr = 0;
253 r_bytes = 0; 723 r_bytes = 0;
254 line_orig = NULL;
255 while (r_bytes < size) 724 while (r_bytes < size)
256 { 725 {
726 char *pos;
727 char *line;
728 bool emptyline;
729
257 GNUNET_free (line_orig); 730 GNUNET_free (line_orig);
258 /* fgets-like behaviour on buffer */ 731 /* fgets-like behaviour on buffer */
259 to_read = size - r_bytes; 732 to_read = size - r_bytes;
@@ -275,7 +748,7 @@ GNUNET_CONFIGURATION_deserialize (struct GNUNET_CONFIGURATION_Handle *cfg,
275 nr++; 748 nr++;
276 /* tabs and '\r' are whitespace */ 749 /* tabs and '\r' are whitespace */
277 emptyline = GNUNET_YES; 750 emptyline = GNUNET_YES;
278 for (i = 0; i < line_size; i++) 751 for (size_t i = 0; i < line_size; i++)
279 { 752 {
280 if (line[i] == '\t') 753 if (line[i] == '\t')
281 line[i] = ' '; 754 line[i] = ' ';
@@ -289,7 +762,7 @@ GNUNET_CONFIGURATION_deserialize (struct GNUNET_CONFIGURATION_Handle *cfg,
289 continue; 762 continue;
290 763
291 /* remove tailing whitespace */ 764 /* remove tailing whitespace */
292 for (i = line_size - 1; 765 for (size_t i = line_size - 1;
293 (i >= 1) && (isspace ((unsigned char) line[i])); 766 (i >= 1) && (isspace ((unsigned char) line[i]));
294 i--) 767 i--)
295 line[i] = '\0'; 768 line[i] = '\0';
@@ -303,50 +776,113 @@ GNUNET_CONFIGURATION_deserialize (struct GNUNET_CONFIGURATION_Handle *cfg,
303 ('%' == line[0]) ) 776 ('%' == line[0]) )
304 continue; 777 continue;
305 778
306 /* handle special "@INLINE@" directive */ 779 /* Handle special directives. */
307 if (0 == strncasecmp (line, 780 if ('@' == line[0])
308 "@INLINE@ ",
309 strlen ("@INLINE@ ")))
310 { 781 {
311 /* @INLINE@ value */ 782 char *end = strchr (line + 1, '@');
312 value = &line[strlen ("@INLINE@ ")]; 783 char *directive;
313 if (NULL != basedir) 784 enum GNUNET_GenericReturnValue directive_ret;
785
786 if (NULL != cfg->restrict_section)
314 { 787 {
315 if ('/' == *value) 788 LOG (GNUNET_ERROR_TYPE_WARNING,
316 { 789 _ (
317 if (GNUNET_OK != 790 "Illegal directive in line %u (parsing restricted section %s)\n"),
318 GNUNET_CONFIGURATION_parse (cfg, 791 nr,
319 value)) 792 cfg->restrict_section);
320 { 793 ret = GNUNET_SYSERR;
321 ret = GNUNET_SYSERR; /* failed to parse included config */ 794 break;
322 break; 795 }
323 } 796
324 } 797 if (NULL == end)
325 else 798 {
799 LOG (GNUNET_ERROR_TYPE_WARNING,
800 _ ("Bad directive in line %u\n"),
801 nr);
802 ret = GNUNET_SYSERR;
803 break;
804 }
805 *end = '\0';
806 directive = line + 1;
807
808 if (0 == strcasecmp (directive, "INLINE"))
809 {
810 const char *path = end + 1;
811
812 /* Skip space before path */
813 for (; isspace (*path); path++)
814 ;
815
816 directive_ret = handle_inline (cfg,
817 path,
818 false,
819 NULL,
820 source_filename,
821 nr);
822 }
823 else if (0 == strcasecmp (directive, "INLINE-MATCHING"))
824 {
825 const char *path = end + 1;
826
827 /* Skip space before path */
828 for (; isspace (*path); path++)
829 ;
830
831 directive_ret = handle_inline (cfg,
832 path,
833 true,
834 NULL,
835 source_filename,
836 nr);
837 }
838 else if (0 == strcasecmp (directive, "INLINE-SECRET"))
839 {
840 char *secname = end + 1;
841 char *secname_end;
842 const char *path;
843
844 /* Skip space before secname */
845 for (; isspace (*secname); secname++)
846 ;
847
848 secname_end = strchr (secname, ' ');
849
850 if (NULL == secname_end)
326 { 851 {
327 char *fn; 852 LOG (GNUNET_ERROR_TYPE_WARNING,
328 853 _ ("Bad inline-secret directive in line %u\n"),
329 GNUNET_asprintf (&fn, "%s/%s", 854 nr);
330 basedir, 855 ret = GNUNET_SYSERR;
331 value); 856 break;
332 if (GNUNET_OK !=
333 GNUNET_CONFIGURATION_parse (cfg,
334 fn))
335 {
336 GNUNET_free (fn);
337 ret = GNUNET_SYSERR; /* failed to parse included config */
338 break;
339 }
340 GNUNET_free (fn);
341 } 857 }
858 *secname_end = '\0';
859 path = secname_end + 1;
860
861 /* Skip space before path */
862 for (; isspace (*path); path++)
863 ;
864
865 directive_ret = handle_inline (cfg,
866 path,
867 false,
868 secname,
869 source_filename,
870 nr);
342 } 871 }
343 else 872 else
344 { 873 {
345 LOG (GNUNET_ERROR_TYPE_DEBUG, 874 LOG (GNUNET_ERROR_TYPE_WARNING,
346 "Ignoring parsing @INLINE@ configurations, not allowed!\n"); 875 _ ("Unknown or malformed directive '%s' in line %u\n"),
876 directive,
877 nr);
347 ret = GNUNET_SYSERR; 878 ret = GNUNET_SYSERR;
348 break; 879 break;
349 } 880 }
881 if (GNUNET_OK != directive_ret)
882 {
883 ret = directive_ret;
884 break;
885 }
350 continue; 886 continue;
351 } 887 }
352 if (('[' == line[0]) && (']' == line[line_size - 1])) 888 if (('[' == line[0]) && (']' == line[line_size - 1]))
@@ -360,10 +896,23 @@ GNUNET_CONFIGURATION_deserialize (struct GNUNET_CONFIGURATION_Handle *cfg,
360 } 896 }
361 if (NULL != (eq = strchr (line, '='))) 897 if (NULL != (eq = strchr (line, '=')))
362 { 898 {
899 size_t i;
900
901 if (NULL == section)
902 {
903 LOG (GNUNET_ERROR_TYPE_WARNING,
904 _ (
905 "Syntax error while deserializing in line %u (option without section)\n"),
906 nr);
907 ret = GNUNET_SYSERR;
908 break;
909 }
910
363 /* tag = value */ 911 /* tag = value */
364 tag = GNUNET_strndup (line, eq - line); 912 tag = GNUNET_strndup (line, eq - line);
365 /* remove tailing whitespace */ 913 /* remove tailing whitespace */
366 for (i = strlen (tag) - 1; (i >= 1) && (isspace ((unsigned char) tag[i])); 914 for (i = strlen (tag) - 1;
915 (i >= 1) && (isspace ((unsigned char) tag[i]));
367 i--) 916 i--)
368 tag[i] = '\0'; 917 tag[i] = '\0';
369 918
@@ -384,6 +933,14 @@ GNUNET_CONFIGURATION_deserialize (struct GNUNET_CONFIGURATION_Handle *cfg,
384 value++; 933 value++;
385 } 934 }
386 GNUNET_CONFIGURATION_set_value_string (cfg, section, tag, &value[i]); 935 GNUNET_CONFIGURATION_set_value_string (cfg, section, tag, &value[i]);
936 if (cfg->diagnostics)
937 {
938 set_entry_hint (cfg,
939 section,
940 tag,
941 source_filename ? source_filename : "<input>",
942 nr);
943 }
387 GNUNET_free (tag); 944 GNUNET_free (tag);
388 continue; 945 continue;
389 } 946 }
@@ -410,7 +967,6 @@ GNUNET_CONFIGURATION_parse (struct GNUNET_CONFIGURATION_Handle *cfg,
410 size_t fs; 967 size_t fs;
411 char *fn; 968 char *fn;
412 char *mem; 969 char *mem;
413 char *endsep;
414 int dirty; 970 int dirty;
415 enum GNUNET_GenericReturnValue ret; 971 enum GNUNET_GenericReturnValue ret;
416 ssize_t sret; 972 ssize_t sret;
@@ -419,6 +975,56 @@ GNUNET_CONFIGURATION_parse (struct GNUNET_CONFIGURATION_Handle *cfg,
419 LOG (GNUNET_ERROR_TYPE_DEBUG, "Asked to parse config file `%s'\n", fn); 975 LOG (GNUNET_ERROR_TYPE_DEBUG, "Asked to parse config file `%s'\n", fn);
420 if (NULL == fn) 976 if (NULL == fn)
421 return GNUNET_SYSERR; 977 return GNUNET_SYSERR;
978
979
980 /* Check for cycles */
981 {
982 unsigned int lvl = cfg->current_nest_level;
983 struct ConfigFile *cf = cfg->loaded_files_tail;
984 struct ConfigFile *parent = NULL;
985
986
987 for (; NULL != cf; parent = cf, cf = cf->prev)
988 {
989 /* Check parents based on level, skipping children of siblings. */
990 if (cf->level >= lvl)
991 continue;
992 lvl = cf->level;
993 if ( (NULL == cf->source_filename) || (NULL == filename))
994 continue;
995 if (0 == strcmp (cf->source_filename, filename))
996 {
997 if (NULL == parent)
998 {
999 LOG (GNUNET_ERROR_TYPE_ERROR,
1000 "Forbidden direct cyclic configuration import (%s -> %s)\n",
1001 cf->source_filename,
1002 filename);
1003 }
1004 else
1005 LOG (GNUNET_ERROR_TYPE_ERROR,
1006 "Forbidden indirect cyclic configuration import (%s -> ... -> %s -> %s)\n",
1007 cf->source_filename,
1008 parent->source_filename,
1009 filename);
1010 GNUNET_free (fn);
1011 return GNUNET_SYSERR;
1012 }
1013 }
1014
1015 }
1016
1017 /* Keep track of loaded files.*/
1018 {
1019 struct ConfigFile *cf = GNUNET_new (struct ConfigFile);
1020
1021 cf->level = cfg->current_nest_level;
1022 cf->source_filename = GNUNET_strdup (filename ? filename : "<input>");
1023 GNUNET_CONTAINER_DLL_insert_tail (cfg->loaded_files_head,
1024 cfg->loaded_files_tail,
1025 cf);
1026 }
1027
422 dirty = cfg->dirty; /* back up value! */ 1028 dirty = cfg->dirty; /* back up value! */
423 if (GNUNET_SYSERR == 1029 if (GNUNET_SYSERR ==
424 GNUNET_DISK_file_size (fn, &fs64, GNUNET_YES, GNUNET_YES)) 1030 GNUNET_DISK_file_size (fn, &fs64, GNUNET_YES, GNUNET_YES))
@@ -446,14 +1052,11 @@ GNUNET_CONFIGURATION_parse (struct GNUNET_CONFIGURATION_Handle *cfg,
446 return GNUNET_SYSERR; 1052 return GNUNET_SYSERR;
447 } 1053 }
448 LOG (GNUNET_ERROR_TYPE_DEBUG, "Deserializing contents of file `%s'\n", fn); 1054 LOG (GNUNET_ERROR_TYPE_DEBUG, "Deserializing contents of file `%s'\n", fn);
449 endsep = strrchr (fn, (int) '/');
450 if (NULL != endsep)
451 *endsep = '\0';
452 ret = GNUNET_CONFIGURATION_deserialize (cfg, 1055 ret = GNUNET_CONFIGURATION_deserialize (cfg,
453 mem, 1056 mem,
454 fs, 1057 fs,
455 fn); 1058 fn);
456 if (GNUNET_OK != ret) 1059 if (GNUNET_SYSERR == ret)
457 { 1060 {
458 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1061 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
459 _ ("Failed to parse configuration file `%s'\n"), 1062 _ ("Failed to parse configuration file `%s'\n"),
@@ -527,6 +1130,8 @@ GNUNET_CONFIGURATION_serialize (const struct GNUNET_CONFIGURATION_Handle *cfg,
527 NULL != sec; 1130 NULL != sec;
528 sec = sec->next) 1131 sec = sec->next)
529 { 1132 {
1133 if (sec->inaccessible)
1134 continue;
530 /* For each section we need to add 3 characters: {'[',']','\n'} */ 1135 /* For each section we need to add 3 characters: {'[',']','\n'} */
531 m_size += strlen (sec->name) + 3; 1136 m_size += strlen (sec->name) + 3;
532 for (struct ConfigEntry *ent = sec->entries; 1137 for (struct ConfigEntry *ent = sec->entries;
@@ -606,6 +1211,117 @@ GNUNET_CONFIGURATION_serialize (const struct GNUNET_CONFIGURATION_Handle *cfg,
606} 1211}
607 1212
608 1213
1214char *
1215GNUNET_CONFIGURATION_serialize_diagnostics (const struct
1216 GNUNET_CONFIGURATION_Handle *cfg)
1217{
1218 struct GNUNET_Buffer buf = { 0 };
1219
1220 GNUNET_buffer_write_fstr (&buf,
1221 "#\n# Configuration file diagnostics\n#\n");
1222 GNUNET_buffer_write_fstr (&buf,
1223 "# Entry point: %s\n",
1224 cfg->main_filename ? cfg->main_filename :
1225 "<none>");
1226 GNUNET_buffer_write_fstr (&buf,
1227 "#\n# Files Loaded:\n");
1228
1229 for (struct ConfigFile *cfil = cfg->loaded_files_head;
1230 NULL != cfil;
1231 cfil = cfil->next)
1232 {
1233 GNUNET_buffer_write_fstr (&buf,
1234 "# ");
1235 for (unsigned int i = 0; i < cfil->level; i++)
1236 GNUNET_buffer_write_fstr (&buf,
1237 "+");
1238 if (0 != cfil->level)
1239 GNUNET_buffer_write_fstr (&buf,
1240 " ");
1241
1242 GNUNET_buffer_write_fstr (&buf,
1243 "%s",
1244 cfil->source_filename);
1245
1246 if (NULL != cfil->hint_restrict_section)
1247 GNUNET_buffer_write_fstr (&buf,
1248 " (%s secret section %s)",
1249 cfil->hint_inaccessible
1250 ? "inaccessible"
1251 : "loaded",
1252 cfil->hint_restrict_section);
1253
1254 GNUNET_buffer_write_str (&buf,
1255 "\n");
1256 }
1257
1258 GNUNET_buffer_write_fstr (&buf,
1259 "#\n\n");
1260
1261 for (struct ConfigSection *sec = cfg->sections;
1262 NULL != sec;
1263 sec = sec->next)
1264 {
1265 if (sec->hint_secret_filename)
1266 GNUNET_buffer_write_fstr (&buf,
1267 "# secret section from %s\n# secret file stat %s\n",
1268 sec->hint_secret_filename,
1269 sec->hint_secret_stat);
1270 if (sec->hint_inlined_from_filename)
1271 {
1272 GNUNET_buffer_write_fstr (&buf,
1273 "# inlined from %s:%u\n",
1274 sec->hint_inlined_from_filename,
1275 sec->hint_inlined_from_line);
1276 }
1277 GNUNET_buffer_write_fstr (&buf,
1278 "[%s]\n\n",
1279 sec->name);
1280 if (sec->inaccessible)
1281 {
1282 GNUNET_buffer_write_fstr (&buf,
1283 "# <section contents inaccessible>\n\n\n");
1284 continue;
1285 }
1286 for (struct ConfigEntry *ent = sec->entries;
1287 NULL != ent;
1288 ent = ent->next)
1289 {
1290 if (do_skip (sec->name,
1291 ent->key))
1292 continue;
1293 if (NULL != ent->val)
1294 {
1295 char *pos;
1296 char *val = GNUNET_malloc (strlen (ent->val) * 2 + 1);
1297 strcpy (val, ent->val);
1298 while (NULL != (pos = strstr (val, "\n")))
1299 {
1300 memmove (&pos[2], &pos[1], strlen (&pos[1]));
1301 pos[0] = '\\';
1302 pos[1] = 'n';
1303 }
1304 if (NULL != ent->hint_filename)
1305 {
1306 GNUNET_buffer_write_fstr (&buf,
1307 "# %s:%u\n",
1308 ent->hint_filename,
1309 ent->hint_lineno);
1310 }
1311 GNUNET_buffer_write_fstr (&buf,
1312 "%s = %s\n",
1313 ent->key,
1314 val);
1315 GNUNET_free (val);
1316 }
1317 GNUNET_buffer_write_str (&buf, "\n");
1318 }
1319 GNUNET_buffer_write_str (&buf, "\n");
1320 }
1321 return GNUNET_buffer_reap_str (&buf);
1322}
1323
1324
609enum GNUNET_GenericReturnValue 1325enum GNUNET_GenericReturnValue
610GNUNET_CONFIGURATION_write (struct GNUNET_CONFIGURATION_Handle *cfg, 1326GNUNET_CONFIGURATION_write (struct GNUNET_CONFIGURATION_Handle *cfg,
611 const char *filename) 1327 const char *filename)
@@ -700,6 +1416,14 @@ GNUNET_CONFIGURATION_iterate_section_values (
700 spos = spos->next; 1416 spos = spos->next;
701 if (NULL == spos) 1417 if (NULL == spos)
702 return; 1418 return;
1419 if (spos->inaccessible)
1420 {
1421 LOG (GNUNET_ERROR_TYPE_WARNING,
1422 "Section '%s' is marked as inaccessible, because the configuration "
1423 " file that contains the section can't be read.\n",
1424 section);
1425 return;
1426 }
703 for (epos = spos->entries; NULL != epos; epos = epos->next) 1427 for (epos = spos->entries; NULL != epos; epos = epos->next)
704 if (NULL != epos->val) 1428 if (NULL != epos->val)
705 iter (iter_cls, spos->name, epos->key, epos->val); 1429 iter (iter_cls, spos->name, epos->key, epos->val);
@@ -748,10 +1472,14 @@ GNUNET_CONFIGURATION_remove_section (struct GNUNET_CONFIGURATION_Handle *cfg,
748 spos->entries = ent->next; 1472 spos->entries = ent->next;
749 GNUNET_free (ent->key); 1473 GNUNET_free (ent->key);
750 GNUNET_free (ent->val); 1474 GNUNET_free (ent->val);
1475 GNUNET_free (ent->hint_filename);
751 GNUNET_free (ent); 1476 GNUNET_free (ent);
752 cfg->dirty = GNUNET_YES; 1477 cfg->dirty = GNUNET_YES;
753 } 1478 }
754 GNUNET_free (spos->name); 1479 GNUNET_free (spos->name);
1480 GNUNET_free (spos->hint_secret_filename);
1481 GNUNET_free (spos->hint_secret_stat);
1482 GNUNET_free (spos->hint_inlined_from_filename);
755 GNUNET_free (spos); 1483 GNUNET_free (spos);
756 return; 1484 return;
757 } 1485 }
@@ -794,51 +1522,6 @@ GNUNET_CONFIGURATION_dup (const struct GNUNET_CONFIGURATION_Handle *cfg)
794 1522
795 1523
796/** 1524/**
797 * Find a section entry from a configuration.
798 *
799 * @param cfg configuration to search in
800 * @param section name of the section to look for
801 * @return matching entry, NULL if not found
802 */
803static struct ConfigSection *
804find_section (const struct GNUNET_CONFIGURATION_Handle *cfg,
805 const char *section)
806{
807 struct ConfigSection *pos;
808
809 pos = cfg->sections;
810 while ((pos != NULL) && (0 != strcasecmp (section, pos->name)))
811 pos = pos->next;
812 return pos;
813}
814
815
816/**
817 * Find an entry from a configuration.
818 *
819 * @param cfg handle to the configuration
820 * @param section section the option is in
821 * @param key the option
822 * @return matching entry, NULL if not found
823 */
824static struct ConfigEntry *
825find_entry (const struct GNUNET_CONFIGURATION_Handle *cfg,
826 const char *section,
827 const char *key)
828{
829 struct ConfigSection *sec;
830 struct ConfigEntry *pos;
831
832 if (NULL == (sec = find_section (cfg, section)))
833 return NULL;
834 pos = sec->entries;
835 while ((pos != NULL) && (0 != strcasecmp (key, pos->key)))
836 pos = pos->next;
837 return pos;
838}
839
840
841/**
842 * A callback function, compares entries from two configurations 1525 * A callback function, compares entries from two configurations
843 * (default against a new configuration) and write the diffs in a 1526 * (default against a new configuration) and write the diffs in a
844 * diff-configuration object (the callback object). 1527 * diff-configuration object (the callback object).
@@ -1601,41 +2284,93 @@ GNUNET_CONFIGURATION_remove_value_filename (
1601} 2284}
1602 2285
1603 2286
1604/** 2287enum GNUNET_GenericReturnValue
1605 * Wrapper around #GNUNET_CONFIGURATION_parse. Called on each 2288GNUNET_CONFIGURATION_load_from (struct GNUNET_CONFIGURATION_Handle *cfg,
1606 * file in a directory, we trigger parsing on those files that 2289 const char *defaults_d)
1607 * end with ".conf".
1608 *
1609 * @param cls the cfg
1610 * @param filename file to parse
1611 * @return #GNUNET_OK on success
1612 */
1613static enum GNUNET_GenericReturnValue
1614parse_configuration_file (void *cls, const char *filename)
1615{ 2290{
1616 struct GNUNET_CONFIGURATION_Handle *cfg = cls; 2291 struct CollectFilesContext files_context = {
1617 char *ext; 2292 .files = NULL,
2293 .files_length = 0,
2294 };
2295 enum GNUNET_GenericReturnValue fun_ret;
1618 2296
1619 /* Examine file extension */ 2297 if (GNUNET_SYSERR ==
1620 ext = strrchr (filename, '.'); 2298 GNUNET_DISK_directory_scan (defaults_d, &collect_files_cb,
1621 if ((NULL == ext) || (0 != strcmp (ext, ".conf"))) 2299 &files_context))
2300 return GNUNET_SYSERR; /* no configuration at all found */
2301 qsort (files_context.files,
2302 files_context.files_length,
2303 sizeof (char *),
2304 pstrcmp);
2305 for (unsigned int i = 0; i < files_context.files_length; i++)
1622 { 2306 {
1623 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Skipping file `%s'\n", filename); 2307 char *ext;
1624 return GNUNET_OK; 2308 const char *filename = files_context.files[i];
1625 }
1626 2309
1627 return GNUNET_CONFIGURATION_parse (cfg, filename); 2310 /* Examine file extension */
2311 ext = strrchr (filename, '.');
2312 if ((NULL == ext) || (0 != strcmp (ext, ".conf")))
2313 {
2314 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Skipping file `%s'\n", filename);
2315 fun_ret = GNUNET_OK;
2316 goto cleanup;
2317 }
2318 fun_ret = GNUNET_CONFIGURATION_parse (cfg, filename);
2319 if (fun_ret != GNUNET_OK)
2320 break;
2321 }
2322cleanup:
2323 if (files_context.files_length > 0)
2324 {
2325 for (size_t i = 0; i < files_context.files_length; i++)
2326 GNUNET_free (files_context.files[i]);
2327 GNUNET_array_grow (files_context.files,
2328 files_context.files_length,
2329 0);
2330 }
2331 return fun_ret;
1628} 2332}
1629 2333
1630 2334
1631enum GNUNET_GenericReturnValue 2335char *
1632GNUNET_CONFIGURATION_load_from (struct GNUNET_CONFIGURATION_Handle *cfg, 2336GNUNET_CONFIGURATION_default_filename (void)
1633 const char *defaults_d)
1634{ 2337{
1635 if (GNUNET_SYSERR == 2338 char *cfg_fn;
1636 GNUNET_DISK_directory_scan (defaults_d, &parse_configuration_file, cfg)) 2339 const struct GNUNET_OS_ProjectData *pd = GNUNET_OS_project_data_get ();
1637 return GNUNET_SYSERR; /* no configuration at all found */ 2340 const char *xdg = getenv ("XDG_CONFIG_HOME");
1638 return GNUNET_OK; 2341
2342 if (NULL != xdg)
2343 GNUNET_asprintf (&cfg_fn,
2344 "%s%s%s",
2345 xdg,
2346 DIR_SEPARATOR_STR,
2347 pd->config_file);
2348 else
2349 cfg_fn = GNUNET_strdup (pd->user_config_file);
2350
2351 if (GNUNET_OK == GNUNET_DISK_file_test_read (cfg_fn))
2352 return cfg_fn;
2353 GNUNET_free (cfg_fn);
2354
2355 /* Fall back to /etc/ for the default configuration.
2356 Should be okay to use forward slashes here. */
2357
2358 GNUNET_asprintf (&cfg_fn,
2359 "/etc/%s",
2360 pd->config_file);
2361 if (GNUNET_OK == GNUNET_DISK_file_test_read (cfg_fn))
2362 return cfg_fn;
2363 GNUNET_free (cfg_fn);
2364
2365 GNUNET_asprintf (&cfg_fn,
2366 "/etc/%s/%s",
2367 pd->project_dirname,
2368 pd->config_file);
2369 if (GNUNET_OK == GNUNET_DISK_file_test_read (cfg_fn))
2370 return cfg_fn;
2371
2372 GNUNET_free (cfg_fn);
2373 return NULL;
1639} 2374}
1640 2375
1641 2376
@@ -1648,12 +2383,47 @@ GNUNET_CONFIGURATION_default (void)
1648 char *cfgname = NULL; 2383 char *cfgname = NULL;
1649 struct GNUNET_CONFIGURATION_Handle *cfg; 2384 struct GNUNET_CONFIGURATION_Handle *cfg;
1650 2385
2386 /* FIXME: Why are we doing this? Needs some commentary! */
1651 GNUNET_OS_init (dpd); 2387 GNUNET_OS_init (dpd);
2388
1652 cfg = GNUNET_CONFIGURATION_create (); 2389 cfg = GNUNET_CONFIGURATION_create ();
2390
2391 /* First, try user configuration. */
1653 if (NULL != xdg) 2392 if (NULL != xdg)
1654 GNUNET_asprintf (&cfgname, "%s/%s", xdg, pd->config_file); 2393 GNUNET_asprintf (&cfgname, "%s/%s", xdg, pd->config_file);
1655 else 2394 else
1656 cfgname = GNUNET_strdup (pd->user_config_file); 2395 cfgname = GNUNET_strdup (pd->user_config_file);
2396
2397 /* If user config doesn't exist, try in
2398 /etc/<projdir>/<cfgfile> and /etc/<cfgfile> */
2399 if (GNUNET_OK != GNUNET_DISK_file_test (cfgname))
2400 {
2401 GNUNET_free (cfgname);
2402 GNUNET_asprintf (&cfgname, "/etc/%s", pd->config_file);
2403 }
2404 if (GNUNET_OK != GNUNET_DISK_file_test (cfgname))
2405 {
2406 GNUNET_free (cfgname);
2407 GNUNET_asprintf (&cfgname,
2408 "/etc/%s/%s",
2409 pd->project_dirname,
2410 pd->config_file);
2411 }
2412 if (GNUNET_OK != GNUNET_DISK_file_test (cfgname))
2413 {
2414 LOG (GNUNET_ERROR_TYPE_ERROR,
2415 "Unable to top-level configuration file.\n");
2416 GNUNET_OS_init (pd);
2417 GNUNET_CONFIGURATION_destroy (cfg);
2418 GNUNET_free (cfgname);
2419 return NULL;
2420 }
2421
2422 /* We found a configuration file that looks good, try to load it. */
2423
2424 LOG (GNUNET_ERROR_TYPE_DEBUG,
2425 "Loading top-level configuration from '%s'\n",
2426 cfgname);
1657 if (GNUNET_OK != 2427 if (GNUNET_OK !=
1658 GNUNET_CONFIGURATION_load (cfg, cfgname)) 2428 GNUNET_CONFIGURATION_load (cfg, cfgname))
1659 { 2429 {
@@ -1668,4 +2438,84 @@ GNUNET_CONFIGURATION_default (void)
1668} 2438}
1669 2439
1670 2440
2441/**
2442 * Load configuration (starts with defaults, then loads
2443 * system-specific configuration).
2444 *
2445 * @param cfg configuration to update
2446 * @param filename name of the configuration file, NULL to load defaults
2447 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
2448 */
2449int
2450GNUNET_CONFIGURATION_load (struct GNUNET_CONFIGURATION_Handle *cfg,
2451 const char *filename)
2452{
2453 char *baseconfig;
2454 const char *base_config_varname;
2455
2456 if (cfg->load_called)
2457 {
2458 /* FIXME: Make this a GNUNET_assert later */
2459 GNUNET_break (0);
2460 GNUNET_free (cfg->main_filename);
2461 }
2462 cfg->load_called = true;
2463 if (NULL != filename)
2464 {
2465 GNUNET_free (cfg->main_filename);
2466 cfg->main_filename = GNUNET_strdup (filename);
2467 }
2468
2469 base_config_varname = GNUNET_OS_project_data_get ()->base_config_varname;
2470
2471 if ((NULL != base_config_varname)
2472 && (NULL != (baseconfig = getenv (base_config_varname))))
2473 {
2474 baseconfig = GNUNET_strdup (baseconfig);
2475 }
2476 else
2477 {
2478 char *ipath;
2479
2480 ipath = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR);
2481 if (NULL == ipath)
2482 {
2483 GNUNET_break (0);
2484 return GNUNET_SYSERR;
2485 }
2486 GNUNET_asprintf (&baseconfig, "%s%s", ipath, "config.d");
2487 GNUNET_free (ipath);
2488 }
2489
2490 char *dname = GNUNET_STRINGS_filename_expand (baseconfig);
2491 GNUNET_free (baseconfig);
2492
2493 if ((GNUNET_YES == GNUNET_DISK_directory_test (dname, GNUNET_YES)) &&
2494 (GNUNET_SYSERR == GNUNET_CONFIGURATION_load_from (cfg, dname)))
2495 {
2496 LOG (GNUNET_ERROR_TYPE_WARNING,
2497 "Failed to load base configuration from '%s'\n",
2498 filename);
2499 GNUNET_free (dname);
2500 return GNUNET_SYSERR; /* no configuration at all found */
2501 }
2502 GNUNET_free (dname);
2503 if ((NULL != filename) &&
2504 (GNUNET_OK != GNUNET_CONFIGURATION_parse (cfg, filename)))
2505 {
2506 /* specified configuration not found */
2507 LOG (GNUNET_ERROR_TYPE_WARNING,
2508 "Failed to load configuration from file '%s'\n",
2509 filename);
2510 return GNUNET_SYSERR;
2511 }
2512 if (((GNUNET_YES !=
2513 GNUNET_CONFIGURATION_have_value (cfg, "PATHS", "DEFAULTCONFIG"))) &&
2514 (filename != NULL))
2515 GNUNET_CONFIGURATION_set_value_string (cfg, "PATHS", "DEFAULTCONFIG",
2516 filename);
2517 return GNUNET_OK;
2518}
2519
2520
1671/* end of configuration.c */ 2521/* end of configuration.c */