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.c2524
1 files changed, 0 insertions, 2524 deletions
diff --git a/src/util/configuration.c b/src/util/configuration.c
deleted file mode 100644
index d9d6721cc..000000000
--- a/src/util/configuration.c
+++ /dev/null
@@ -1,2524 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2006, 2007, 2008, 2009, 2013, 2020, 2021 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file src/util/configuration.c
22 * @brief configuration management
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#include "gnunet_crypto_lib.h"
27#include "gnunet_strings_lib.h"
28#include "gnunet_os_lib.h"
29#include "gnunet_configuration_lib.h"
30#include "gnunet_disk_lib.h"
31#include "gnunet_buffer_lib.h"
32#include "gnunet_container_lib.h"
33
34#define LOG(kind, ...) GNUNET_log_from (kind, "util", __VA_ARGS__)
35
36#define LOG_STRERROR_FILE(kind, syscall, filename) \
37 GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
38
39/**
40 * @brief configuration entry
41 */
42struct ConfigEntry
43{
44 /**
45 * This is a linked list.
46 */
47 struct ConfigEntry *next;
48
49 /**
50 * key for this entry
51 */
52 char *key;
53
54 /**
55 * current, committed value
56 */
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;
68};
69
70
71/**
72 * @brief configuration section
73 */
74struct ConfigSection
75{
76 /**
77 * This is a linked list.
78 */
79 struct ConfigSection *next;
80
81 /**
82 * entries in the section
83 */
84 struct ConfigEntry *entries;
85
86 /**
87 * name of the section
88 */
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;
146};
147
148
149/**
150 * @brief configuration data
151 */
152struct GNUNET_CONFIGURATION_Handle
153{
154 /**
155 * Configuration sections.
156 */
157 struct ConfigSection *sections;
158
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 /**
180 * Modification indication since last save
181 * #GNUNET_NO if clean, #GNUNET_YES if dirty,
182 * #GNUNET_SYSERR on error (i.e. last save failed)
183 */
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;
202};
203
204
205/**
206 * Used for diffing a configuration object against
207 * the default one
208 */
209struct DiffHandle
210{
211 const struct GNUNET_CONFIGURATION_Handle *cfg_default;
212
213 struct GNUNET_CONFIGURATION_Handle *cfgDiff;
214};
215
216
217void
218GNUNET_CONFIGURATION_enable_diagnostics (struct
219 GNUNET_CONFIGURATION_Handle *cfg)
220{
221 cfg->diagnostics = true;
222}
223
224
225struct GNUNET_CONFIGURATION_Handle *
226GNUNET_CONFIGURATION_create ()
227{
228 struct GNUNET_CONFIGURATION_Handle *cfg;
229 char *p;
230
231 cfg = GNUNET_new (struct GNUNET_CONFIGURATION_Handle);
232 /* make certain values from the project data available
233 as PATHS */
234 p = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR);
235 if (NULL != p)
236 {
237 GNUNET_CONFIGURATION_set_value_string (cfg,
238 "PATHS",
239 "DATADIR",
240 p);
241 GNUNET_free (p);
242 }
243 p = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LIBDIR);
244 if (NULL != p)
245 {
246 GNUNET_CONFIGURATION_set_value_string (cfg,
247 "PATHS",
248 "LIBDIR",
249 p);
250 GNUNET_free (p);
251 }
252 p = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_BINDIR);
253 if (NULL != p)
254 {
255 GNUNET_CONFIGURATION_set_value_string (cfg,
256 "PATHS",
257 "BINDIR",
258 p);
259 GNUNET_free (p);
260 }
261 p = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_PREFIX);
262 if (NULL != p)
263 {
264 GNUNET_CONFIGURATION_set_value_string (cfg,
265 "PATHS",
266 "PREFIX",
267 p);
268 GNUNET_free (p);
269 }
270 p = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LOCALEDIR);
271 if (NULL != p)
272 {
273 GNUNET_CONFIGURATION_set_value_string (cfg,
274 "PATHS",
275 "LOCALEDIR",
276 p);
277 GNUNET_free (p);
278 }
279 p = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_ICONDIR);
280 if (NULL != p)
281 {
282 GNUNET_CONFIGURATION_set_value_string (cfg,
283 "PATHS",
284 "ICONDIR",
285 p);
286 GNUNET_free (p);
287 }
288 p = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DOCDIR);
289 if (NULL != p)
290 {
291 GNUNET_CONFIGURATION_set_value_string (cfg,
292 "PATHS",
293 "DOCDIR",
294 p);
295 GNUNET_free (p);
296 }
297 p = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LIBEXECDIR);
298 if (NULL != p)
299 {
300 GNUNET_CONFIGURATION_set_value_string (cfg,
301 "PATHS",
302 "LIBEXECDIR",
303 p);
304 GNUNET_free (p);
305 }
306 return cfg;
307}
308
309
310void
311GNUNET_CONFIGURATION_destroy (struct GNUNET_CONFIGURATION_Handle *cfg)
312{
313 struct ConfigSection *sec;
314 struct ConfigFile *cf;
315
316 while (NULL != (sec = cfg->sections))
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);
328 GNUNET_free (cfg);
329}
330
331
332enum GNUNET_GenericReturnValue
333GNUNET_CONFIGURATION_parse_and_run (const char *filename,
334 GNUNET_CONFIGURATION_Callback cb,
335 void *cb_cls)
336{
337 struct GNUNET_CONFIGURATION_Handle *cfg;
338 enum GNUNET_GenericReturnValue ret;
339
340 cfg = GNUNET_CONFIGURATION_create ();
341 if (GNUNET_OK !=
342 GNUNET_CONFIGURATION_load (cfg,
343 filename))
344 {
345 GNUNET_break (0);
346 GNUNET_CONFIGURATION_destroy (cfg);
347 return GNUNET_SYSERR;
348 }
349 ret = cb (cb_cls, cfg);
350 GNUNET_CONFIGURATION_destroy (cfg);
351 return ret;
352}
353
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
703enum GNUNET_GenericReturnValue
704GNUNET_CONFIGURATION_deserialize (struct GNUNET_CONFIGURATION_Handle *cfg,
705 const char *mem,
706 size_t size,
707 const char *source_filename)
708{
709 size_t line_size;
710 unsigned int nr;
711 size_t r_bytes;
712 size_t to_read;
713 enum GNUNET_GenericReturnValue ret;
714 char *section;
715 char *eq;
716 char *tag;
717 char *value;
718 char *line_orig = NULL;
719
720 ret = GNUNET_OK;
721 section = NULL;
722 nr = 0;
723 r_bytes = 0;
724 while (r_bytes < size)
725 {
726 char *pos;
727 char *line;
728 bool emptyline;
729
730 GNUNET_free (line_orig);
731 /* fgets-like behaviour on buffer */
732 to_read = size - r_bytes;
733 pos = memchr (&mem[r_bytes], '\n', to_read);
734 if (NULL == pos)
735 {
736 line_orig = GNUNET_strndup (&mem[r_bytes],
737 line_size = to_read);
738 r_bytes += line_size;
739 }
740 else
741 {
742 line_orig = GNUNET_strndup (&mem[r_bytes],
743 line_size = (pos - &mem[r_bytes]));
744 r_bytes += line_size + 1;
745 }
746 line = line_orig;
747 /* increment line number */
748 nr++;
749 /* tabs and '\r' are whitespace */
750 emptyline = GNUNET_YES;
751 for (size_t i = 0; i < line_size; i++)
752 {
753 if (line[i] == '\t')
754 line[i] = ' ';
755 if (line[i] == '\r')
756 line[i] = ' ';
757 if (' ' != line[i])
758 emptyline = GNUNET_NO;
759 }
760 /* ignore empty lines */
761 if (GNUNET_YES == emptyline)
762 continue;
763
764 /* remove tailing whitespace */
765 for (size_t i = line_size - 1;
766 (i >= 1) && (isspace ((unsigned char) line[i]));
767 i--)
768 line[i] = '\0';
769
770 /* remove leading whitespace */
771 for (; line[0] != '\0' && (isspace ((unsigned char) line[0])); line++)
772 ;
773
774 /* ignore comments */
775 if ( ('#' == line[0]) ||
776 ('%' == line[0]) )
777 continue;
778
779 /* Handle special directives. */
780 if ('@' == line[0])
781 {
782 char *end = strchr (line + 1, '@');
783 char *directive;
784 enum GNUNET_GenericReturnValue directive_ret;
785
786 if (NULL != cfg->restrict_section)
787 {
788 LOG (GNUNET_ERROR_TYPE_WARNING,
789 _ (
790 "Illegal directive in line %u (parsing restricted section %s)\n"),
791 nr,
792 cfg->restrict_section);
793 ret = GNUNET_SYSERR;
794 break;
795 }
796
797 if (NULL == end)
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)
851 {
852 LOG (GNUNET_ERROR_TYPE_WARNING,
853 _ ("Bad inline-secret directive in line %u\n"),
854 nr);
855 ret = GNUNET_SYSERR;
856 break;
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);
871 }
872 else
873 {
874 LOG (GNUNET_ERROR_TYPE_WARNING,
875 _ ("Unknown or malformed directive '%s' in line %u\n"),
876 directive,
877 nr);
878 ret = GNUNET_SYSERR;
879 break;
880 }
881 if (GNUNET_OK != directive_ret)
882 {
883 ret = directive_ret;
884 break;
885 }
886 continue;
887 }
888 if (('[' == line[0]) && (']' == line[line_size - 1]))
889 {
890 /* [value] */
891 line[line_size - 1] = '\0';
892 value = &line[1];
893 GNUNET_free (section);
894 section = GNUNET_strdup (value);
895 continue;
896 }
897 if (NULL != (eq = strchr (line, '=')))
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
911 /* tag = value */
912 tag = GNUNET_strndup (line, eq - line);
913 /* remove tailing whitespace */
914 for (i = strlen (tag) - 1;
915 (i >= 1) && (isspace ((unsigned char) tag[i]));
916 i--)
917 tag[i] = '\0';
918
919 /* Strip whitespace */
920 value = eq + 1;
921 while (isspace ((unsigned char) value[0]))
922 value++;
923 for (i = strlen (value) - 1;
924 (i >= 1) && (isspace ((unsigned char) value[i]));
925 i--)
926 value[i] = '\0';
927
928 /* remove quotes */
929 i = 0;
930 if (('"' == value[0]) && ('"' == value[strlen (value) - 1]))
931 {
932 value[strlen (value) - 1] = '\0';
933 value++;
934 }
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 }
944 GNUNET_free (tag);
945 continue;
946 }
947 /* parse error */
948 LOG (GNUNET_ERROR_TYPE_WARNING,
949 _ ("Syntax error while deserializing in line %u\n"),
950 nr);
951 ret = GNUNET_SYSERR;
952 break;
953 }
954 GNUNET_free (line_orig);
955 GNUNET_free (section);
956 GNUNET_assert ( (GNUNET_OK != ret) ||
957 (r_bytes == size) );
958 return ret;
959}
960
961
962enum GNUNET_GenericReturnValue
963GNUNET_CONFIGURATION_parse (struct GNUNET_CONFIGURATION_Handle *cfg,
964 const char *filename)
965{
966 uint64_t fs64;
967 size_t fs;
968 char *fn;
969 char *mem;
970 int dirty;
971 enum GNUNET_GenericReturnValue ret;
972 ssize_t sret;
973
974 fn = GNUNET_STRINGS_filename_expand (filename);
975 LOG (GNUNET_ERROR_TYPE_DEBUG, "Asked to parse config file `%s'\n", fn);
976 if (NULL == fn)
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
1028 dirty = cfg->dirty; /* back up value! */
1029 if (GNUNET_SYSERR ==
1030 GNUNET_DISK_file_size (fn, &fs64, GNUNET_YES, GNUNET_YES))
1031 {
1032 LOG (GNUNET_ERROR_TYPE_WARNING,
1033 "Error while determining the file size of `%s'\n",
1034 fn);
1035 GNUNET_free (fn);
1036 return GNUNET_SYSERR;
1037 }
1038 if (fs64 > SIZE_MAX)
1039 {
1040 GNUNET_break (0); /* File size is more than the heap size */
1041 GNUNET_free (fn);
1042 return GNUNET_SYSERR;
1043 }
1044 fs = fs64;
1045 mem = GNUNET_malloc (fs);
1046 sret = GNUNET_DISK_fn_read (fn, mem, fs);
1047 if ((sret < 0) || (fs != (size_t) sret))
1048 {
1049 LOG (GNUNET_ERROR_TYPE_WARNING, _ ("Error while reading file `%s'\n"), fn);
1050 GNUNET_free (fn);
1051 GNUNET_free (mem);
1052 return GNUNET_SYSERR;
1053 }
1054 LOG (GNUNET_ERROR_TYPE_DEBUG, "Deserializing contents of file `%s'\n", fn);
1055 ret = GNUNET_CONFIGURATION_deserialize (cfg,
1056 mem,
1057 fs,
1058 fn);
1059 if (GNUNET_SYSERR == ret)
1060 {
1061 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1062 _ ("Failed to parse configuration file `%s'\n"),
1063 fn);
1064 }
1065 GNUNET_free (fn);
1066 GNUNET_free (mem);
1067 /* restore dirty flag - anything we set in the meantime
1068 * came from disk */
1069 cfg->dirty = dirty;
1070 return ret;
1071}
1072
1073
1074enum GNUNET_GenericReturnValue
1075GNUNET_CONFIGURATION_is_dirty (const struct GNUNET_CONFIGURATION_Handle *cfg)
1076{
1077 return cfg->dirty;
1078}
1079
1080
1081/**
1082 * Should we skip this configuration entry when serializing?
1083 *
1084 * @param sec section name
1085 * @param key key
1086 * @return true if we should skip it
1087 */
1088static bool
1089do_skip (const char *sec,
1090 const char *key)
1091{
1092 if (0 != strcasecmp ("PATHS",
1093 sec))
1094 return false;
1095 return ( (0 == strcasecmp ("DATADIR",
1096 key)) ||
1097 (0 == strcasecmp ("LIBDIR",
1098 key)) ||
1099 (0 == strcasecmp ("BINDIR",
1100 key)) ||
1101 (0 == strcasecmp ("PREFIX",
1102 key)) ||
1103 (0 == strcasecmp ("LOCALEDIR",
1104 key)) ||
1105 (0 == strcasecmp ("ICONDIR",
1106 key)) ||
1107 (0 == strcasecmp ("DOCDIR",
1108 key)) ||
1109 (0 == strcasecmp ("DEFAULTCONFIG",
1110 key)) ||
1111 (0 == strcasecmp ("LIBEXECDIR",
1112 key)) );
1113}
1114
1115
1116char *
1117GNUNET_CONFIGURATION_serialize (const struct GNUNET_CONFIGURATION_Handle *cfg,
1118 size_t *size)
1119{
1120 char *mem;
1121 char *cbuf;
1122 char *val;
1123 char *pos;
1124 size_t m_size;
1125 size_t c_size;
1126
1127 /* Pass1 : calculate the buffer size required */
1128 m_size = 0;
1129 for (struct ConfigSection *sec = cfg->sections;
1130 NULL != sec;
1131 sec = sec->next)
1132 {
1133 if (sec->inaccessible)
1134 continue;
1135 /* For each section we need to add 3 characters: {'[',']','\n'} */
1136 m_size += strlen (sec->name) + 3;
1137 for (struct ConfigEntry *ent = sec->entries;
1138 NULL != ent;
1139 ent = ent->next)
1140 {
1141 if (do_skip (sec->name,
1142 ent->key))
1143 continue;
1144 if (NULL != ent->val)
1145 {
1146 /* if val has any '\n' then they occupy +1 character as '\n'->'\\','n' */
1147 pos = ent->val;
1148 while (NULL != (pos = strstr (pos, "\n")))
1149 {
1150 m_size++;
1151 pos++;
1152 }
1153 /* For each key = value pair we need to add 4 characters (2
1154 spaces and 1 equal-to character and 1 new line) */
1155 m_size += strlen (ent->key) + strlen (ent->val) + 4;
1156 }
1157 }
1158 /* A new line after section end */
1159 m_size++;
1160 }
1161
1162 /* Pass2: Allocate memory and write the configuration to it */
1163 mem = GNUNET_malloc (m_size);
1164 c_size = 0;
1165 *size = c_size;
1166 for (struct ConfigSection *sec = cfg->sections;
1167 NULL != sec;
1168 sec = sec->next)
1169 {
1170 int len;
1171
1172 len = GNUNET_asprintf (&cbuf,
1173 "[%s]\n",
1174 sec->name);
1175 GNUNET_assert (0 < len);
1176 GNUNET_memcpy (mem + c_size,
1177 cbuf,
1178 len);
1179 c_size += len;
1180 GNUNET_free (cbuf);
1181 for (struct ConfigEntry *ent = sec->entries;
1182 NULL != ent;
1183 ent = ent->next)
1184 {
1185 if (do_skip (sec->name,
1186 ent->key))
1187 continue;
1188 if (NULL != ent->val)
1189 {
1190 val = GNUNET_malloc (strlen (ent->val) * 2 + 1);
1191 strcpy (val, ent->val);
1192 while (NULL != (pos = strstr (val, "\n")))
1193 {
1194 memmove (&pos[2], &pos[1], strlen (&pos[1]));
1195 pos[0] = '\\';
1196 pos[1] = 'n';
1197 }
1198 len = GNUNET_asprintf (&cbuf, "%s = %s\n", ent->key, val);
1199 GNUNET_free (val);
1200 GNUNET_memcpy (mem + c_size, cbuf, len);
1201 c_size += len;
1202 GNUNET_free (cbuf);
1203 }
1204 }
1205 GNUNET_memcpy (mem + c_size, "\n", 1);
1206 c_size++;
1207 }
1208 GNUNET_assert (c_size == m_size);
1209 *size = c_size;
1210 return mem;
1211}
1212
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
1325enum GNUNET_GenericReturnValue
1326GNUNET_CONFIGURATION_write (struct GNUNET_CONFIGURATION_Handle *cfg,
1327 const char *filename)
1328{
1329 char *fn;
1330 char *cfg_buf;
1331 size_t size;
1332
1333 fn = GNUNET_STRINGS_filename_expand (filename);
1334 if (fn == NULL)
1335 return GNUNET_SYSERR;
1336 if (GNUNET_OK != GNUNET_DISK_directory_create_for_file (fn))
1337 {
1338 GNUNET_free (fn);
1339 return GNUNET_SYSERR;
1340 }
1341 cfg_buf = GNUNET_CONFIGURATION_serialize (cfg,
1342 &size);
1343 {
1344 struct GNUNET_DISK_FileHandle *h;
1345
1346 h = GNUNET_DISK_file_open (fn,
1347 GNUNET_DISK_OPEN_WRITE
1348 | GNUNET_DISK_OPEN_TRUNCATE
1349 | GNUNET_DISK_OPEN_CREATE,
1350 GNUNET_DISK_PERM_USER_READ
1351 | GNUNET_DISK_PERM_USER_WRITE
1352 | GNUNET_DISK_PERM_GROUP_READ
1353 | GNUNET_DISK_PERM_GROUP_WRITE);
1354 if (NULL == h)
1355 {
1356 GNUNET_free (fn);
1357 GNUNET_free (cfg_buf);
1358 return GNUNET_SYSERR;
1359 }
1360 if (((ssize_t) size) !=
1361 GNUNET_DISK_file_write (h,
1362 cfg_buf,
1363 size))
1364 {
1365 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
1366 "write",
1367 fn);
1368 GNUNET_DISK_file_close (h);
1369 (void) GNUNET_DISK_directory_remove (fn);
1370 GNUNET_free (fn);
1371 GNUNET_free (cfg_buf);
1372 cfg->dirty = GNUNET_SYSERR; /* last write failed */
1373 return GNUNET_SYSERR;
1374 }
1375 GNUNET_assert (GNUNET_OK ==
1376 GNUNET_DISK_file_close (h));
1377 }
1378 GNUNET_free (fn);
1379 GNUNET_free (cfg_buf);
1380 cfg->dirty = GNUNET_NO; /* last write succeeded */
1381 return GNUNET_OK;
1382}
1383
1384
1385void
1386GNUNET_CONFIGURATION_iterate (const struct GNUNET_CONFIGURATION_Handle *cfg,
1387 GNUNET_CONFIGURATION_Iterator iter,
1388 void *iter_cls)
1389{
1390 for (struct ConfigSection *spos = cfg->sections;
1391 NULL != spos;
1392 spos = spos->next)
1393 for (struct ConfigEntry *epos = spos->entries;
1394 NULL != epos;
1395 epos = epos->next)
1396 if (NULL != epos->val)
1397 iter (iter_cls,
1398 spos->name,
1399 epos->key,
1400 epos->val);
1401}
1402
1403
1404void
1405GNUNET_CONFIGURATION_iterate_section_values (
1406 const struct GNUNET_CONFIGURATION_Handle *cfg,
1407 const char *section,
1408 GNUNET_CONFIGURATION_Iterator iter,
1409 void *iter_cls)
1410{
1411 struct ConfigSection *spos;
1412 struct ConfigEntry *epos;
1413
1414 spos = cfg->sections;
1415 while ((spos != NULL) && (0 != strcasecmp (spos->name, section)))
1416 spos = spos->next;
1417 if (NULL == spos)
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 }
1427 for (epos = spos->entries; NULL != epos; epos = epos->next)
1428 if (NULL != epos->val)
1429 iter (iter_cls, spos->name, epos->key, epos->val);
1430}
1431
1432
1433void
1434GNUNET_CONFIGURATION_iterate_sections (
1435 const struct GNUNET_CONFIGURATION_Handle *cfg,
1436 GNUNET_CONFIGURATION_Section_Iterator iter,
1437 void *iter_cls)
1438{
1439 struct ConfigSection *spos;
1440 struct ConfigSection *next;
1441
1442 next = cfg->sections;
1443 while (next != NULL)
1444 {
1445 spos = next;
1446 next = spos->next;
1447 iter (iter_cls, spos->name);
1448 }
1449}
1450
1451
1452void
1453GNUNET_CONFIGURATION_remove_section (struct GNUNET_CONFIGURATION_Handle *cfg,
1454 const char *section)
1455{
1456 struct ConfigSection *spos;
1457 struct ConfigSection *prev;
1458 struct ConfigEntry *ent;
1459
1460 prev = NULL;
1461 spos = cfg->sections;
1462 while (NULL != spos)
1463 {
1464 if (0 == strcasecmp (section, spos->name))
1465 {
1466 if (NULL == prev)
1467 cfg->sections = spos->next;
1468 else
1469 prev->next = spos->next;
1470 while (NULL != (ent = spos->entries))
1471 {
1472 spos->entries = ent->next;
1473 GNUNET_free (ent->key);
1474 GNUNET_free (ent->val);
1475 GNUNET_free (ent->hint_filename);
1476 GNUNET_free (ent);
1477 cfg->dirty = GNUNET_YES;
1478 }
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);
1483 GNUNET_free (spos);
1484 return;
1485 }
1486 prev = spos;
1487 spos = spos->next;
1488 }
1489}
1490
1491
1492/**
1493 * Copy a configuration value to the given target configuration.
1494 * Overwrites existing entries.
1495 *
1496 * @param cls the destination configuration (`struct GNUNET_CONFIGURATION_Handle *`)
1497 * @param section section for the value
1498 * @param option option name of the value
1499 * @param value value to copy
1500 */
1501static void
1502copy_entry (void *cls,
1503 const char *section,
1504 const char *option,
1505 const char *value)
1506{
1507 struct GNUNET_CONFIGURATION_Handle *dst = cls;
1508
1509 GNUNET_CONFIGURATION_set_value_string (dst, section, option, value);
1510}
1511
1512
1513struct GNUNET_CONFIGURATION_Handle *
1514GNUNET_CONFIGURATION_dup (const struct GNUNET_CONFIGURATION_Handle *cfg)
1515{
1516 struct GNUNET_CONFIGURATION_Handle *ret;
1517
1518 ret = GNUNET_CONFIGURATION_create ();
1519 GNUNET_CONFIGURATION_iterate (cfg, &copy_entry, ret);
1520 return ret;
1521}
1522
1523
1524/**
1525 * A callback function, compares entries from two configurations
1526 * (default against a new configuration) and write the diffs in a
1527 * diff-configuration object (the callback object).
1528 *
1529 * @param cls the diff configuration (`struct DiffHandle *`)
1530 * @param section section for the value (of the default conf.)
1531 * @param option option name of the value (of the default conf.)
1532 * @param value value to copy (of the default conf.)
1533 */
1534static void
1535compare_entries (void *cls,
1536 const char *section,
1537 const char *option,
1538 const char *value)
1539{
1540 struct DiffHandle *dh = cls;
1541 struct ConfigEntry *entNew;
1542
1543 entNew = find_entry (dh->cfg_default, section, option);
1544 if ((NULL != entNew) && (NULL != entNew->val) &&
1545 (0 == strcmp (entNew->val, value)))
1546 return;
1547 GNUNET_CONFIGURATION_set_value_string (dh->cfgDiff, section, option, value);
1548}
1549
1550
1551struct GNUNET_CONFIGURATION_Handle *
1552GNUNET_CONFIGURATION_get_diff (
1553 const struct GNUNET_CONFIGURATION_Handle *cfg_default,
1554 const struct GNUNET_CONFIGURATION_Handle *cfg_new)
1555{
1556 struct DiffHandle diffHandle;
1557
1558 diffHandle.cfgDiff = GNUNET_CONFIGURATION_create ();
1559 diffHandle.cfg_default = cfg_default;
1560 GNUNET_CONFIGURATION_iterate (cfg_new, &compare_entries, &diffHandle);
1561 return diffHandle.cfgDiff;
1562}
1563
1564
1565enum GNUNET_GenericReturnValue
1566GNUNET_CONFIGURATION_write_diffs (
1567 const struct GNUNET_CONFIGURATION_Handle *cfg_default,
1568 const struct GNUNET_CONFIGURATION_Handle *cfg_new,
1569 const char *filename)
1570{
1571 int ret;
1572 struct GNUNET_CONFIGURATION_Handle *diff;
1573
1574 diff = GNUNET_CONFIGURATION_get_diff (cfg_default, cfg_new);
1575 ret = GNUNET_CONFIGURATION_write (diff, filename);
1576 GNUNET_CONFIGURATION_destroy (diff);
1577 return ret;
1578}
1579
1580
1581void
1582GNUNET_CONFIGURATION_set_value_string (struct GNUNET_CONFIGURATION_Handle *cfg,
1583 const char *section,
1584 const char *option,
1585 const char *value)
1586{
1587 struct ConfigSection *sec;
1588 struct ConfigEntry *e;
1589 char *nv;
1590
1591 e = find_entry (cfg, section, option);
1592 if (NULL != e)
1593 {
1594 if (NULL == value)
1595 {
1596 GNUNET_free (e->val);
1597 e->val = NULL;
1598 }
1599 else
1600 {
1601 nv = GNUNET_strdup (value);
1602 GNUNET_free (e->val);
1603 e->val = nv;
1604 }
1605 return;
1606 }
1607 sec = find_section (cfg, section);
1608 if (sec == NULL)
1609 {
1610 sec = GNUNET_new (struct ConfigSection);
1611 sec->name = GNUNET_strdup (section);
1612 sec->next = cfg->sections;
1613 cfg->sections = sec;
1614 }
1615 e = GNUNET_new (struct ConfigEntry);
1616 e->key = GNUNET_strdup (option);
1617 e->val = GNUNET_strdup (value);
1618 e->next = sec->entries;
1619 sec->entries = e;
1620}
1621
1622
1623void
1624GNUNET_CONFIGURATION_set_value_number (struct GNUNET_CONFIGURATION_Handle *cfg,
1625 const char *section,
1626 const char *option,
1627 unsigned long long number)
1628{
1629 char s[64];
1630
1631 GNUNET_snprintf (s, 64, "%llu", number);
1632 GNUNET_CONFIGURATION_set_value_string (cfg, section, option, s);
1633}
1634
1635
1636enum GNUNET_GenericReturnValue
1637GNUNET_CONFIGURATION_get_value_number (
1638 const struct GNUNET_CONFIGURATION_Handle *cfg,
1639 const char *section,
1640 const char *option,
1641 unsigned long long *number)
1642{
1643 struct ConfigEntry *e;
1644 char dummy[2];
1645
1646 if (NULL == (e = find_entry (cfg, section, option)))
1647 return GNUNET_SYSERR;
1648 if (NULL == e->val)
1649 return GNUNET_SYSERR;
1650 if (1 != sscanf (e->val, "%llu%1s", number, dummy))
1651 return GNUNET_SYSERR;
1652 return GNUNET_OK;
1653}
1654
1655
1656enum GNUNET_GenericReturnValue
1657GNUNET_CONFIGURATION_get_value_float (
1658 const struct GNUNET_CONFIGURATION_Handle *cfg,
1659 const char *section,
1660 const char *option,
1661 float *number)
1662{
1663 struct ConfigEntry *e;
1664 char dummy[2];
1665
1666 if (NULL == (e = find_entry (cfg, section, option)))
1667 return GNUNET_SYSERR;
1668 if (NULL == e->val)
1669 return GNUNET_SYSERR;
1670 if (1 != sscanf (e->val, "%f%1s", number, dummy))
1671 return GNUNET_SYSERR;
1672 return GNUNET_OK;
1673}
1674
1675
1676enum GNUNET_GenericReturnValue
1677GNUNET_CONFIGURATION_get_value_time (
1678 const struct GNUNET_CONFIGURATION_Handle *cfg,
1679 const char *section,
1680 const char *option,
1681 struct GNUNET_TIME_Relative *time)
1682{
1683 struct ConfigEntry *e;
1684 int ret;
1685
1686 if (NULL == (e = find_entry (cfg, section, option)))
1687 return GNUNET_SYSERR;
1688 if (NULL == e->val)
1689 return GNUNET_SYSERR;
1690 ret = GNUNET_STRINGS_fancy_time_to_relative (e->val, time);
1691 if (GNUNET_OK != ret)
1692 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
1693 section,
1694 option,
1695 _ ("Not a valid relative time specification"));
1696 return ret;
1697}
1698
1699
1700enum GNUNET_GenericReturnValue
1701GNUNET_CONFIGURATION_get_value_size (
1702 const struct GNUNET_CONFIGURATION_Handle *cfg,
1703 const char *section,
1704 const char *option,
1705 unsigned long long *size)
1706{
1707 struct ConfigEntry *e;
1708
1709 if (NULL == (e = find_entry (cfg, section, option)))
1710 return GNUNET_SYSERR;
1711 if (NULL == e->val)
1712 return GNUNET_SYSERR;
1713 return GNUNET_STRINGS_fancy_size_to_bytes (e->val, size);
1714}
1715
1716
1717/**
1718 * Get a configuration value that should be a string.
1719 *
1720 * @param cfg configuration to inspect
1721 * @param section section of interest
1722 * @param option option of interest
1723 * @param value will be set to a freshly allocated configuration
1724 * value, or NULL if option is not specified
1725 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1726 */
1727enum GNUNET_GenericReturnValue
1728GNUNET_CONFIGURATION_get_value_string (
1729 const struct GNUNET_CONFIGURATION_Handle *cfg,
1730 const char *section,
1731 const char *option,
1732 char **value)
1733{
1734 struct ConfigEntry *e;
1735
1736 if ((NULL == (e = find_entry (cfg, section, option))) || (NULL == e->val))
1737 {
1738 *value = NULL;
1739 return GNUNET_SYSERR;
1740 }
1741 *value = GNUNET_strdup (e->val);
1742 return GNUNET_OK;
1743}
1744
1745
1746enum GNUNET_GenericReturnValue
1747GNUNET_CONFIGURATION_get_value_choice (
1748 const struct GNUNET_CONFIGURATION_Handle *cfg,
1749 const char *section,
1750 const char *option,
1751 const char *const *choices,
1752 const char **value)
1753{
1754 struct ConfigEntry *e;
1755 unsigned int i;
1756
1757 if (NULL == (e = find_entry (cfg, section, option)))
1758 return GNUNET_SYSERR;
1759 for (i = 0; NULL != choices[i]; i++)
1760 if (0 == strcasecmp (choices[i], e->val))
1761 break;
1762 if (NULL == choices[i])
1763 {
1764 LOG (GNUNET_ERROR_TYPE_ERROR,
1765 _ ("Configuration value '%s' for '%s'"
1766 " in section '%s' is not in set of legal choices\n"),
1767 e->val,
1768 option,
1769 section);
1770 return GNUNET_SYSERR;
1771 }
1772 *value = choices[i];
1773 return GNUNET_OK;
1774}
1775
1776
1777enum GNUNET_GenericReturnValue
1778GNUNET_CONFIGURATION_get_data (const struct GNUNET_CONFIGURATION_Handle *cfg,
1779 const char *section,
1780 const char *option,
1781 void *buf,
1782 size_t buf_size)
1783{
1784 char *enc;
1785 int res;
1786 size_t data_size;
1787
1788 if (GNUNET_OK !=
1789 (res =
1790 GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &enc)))
1791 return res;
1792 data_size = (strlen (enc) * 5) / 8;
1793 if (data_size != buf_size)
1794 {
1795 GNUNET_free (enc);
1796 return GNUNET_SYSERR;
1797 }
1798 if (GNUNET_OK !=
1799 GNUNET_STRINGS_string_to_data (enc, strlen (enc), buf, buf_size))
1800 {
1801 GNUNET_free (enc);
1802 return GNUNET_SYSERR;
1803 }
1804 GNUNET_free (enc);
1805 return GNUNET_OK;
1806}
1807
1808
1809enum GNUNET_GenericReturnValue
1810GNUNET_CONFIGURATION_have_value (const struct GNUNET_CONFIGURATION_Handle *cfg,
1811 const char *section,
1812 const char *option)
1813{
1814 struct ConfigEntry *e;
1815
1816 if ((NULL == (e = find_entry (cfg, section, option))) || (NULL == e->val))
1817 return GNUNET_NO;
1818 return GNUNET_YES;
1819}
1820
1821
1822/**
1823 * Expand an expression of the form "$FOO/BAR" to "DIRECTORY/BAR"
1824 * where either in the "PATHS" section or the environment "FOO" is
1825 * set to "DIRECTORY". We also support default expansion,
1826 * i.e. ${VARIABLE:-default} will expand to $VARIABLE if VARIABLE is
1827 * set in PATHS or the environment, and otherwise to "default". Note
1828 * that "default" itself can also be a $-expression, thus
1829 * "${VAR1:-{$VAR2}}" will expand to VAR1 and if that is not defined
1830 * to VAR2.
1831 *
1832 * @param cfg configuration to use for path expansion
1833 * @param orig string to $-expand (will be freed!)
1834 * @param depth recursion depth, used to detect recursive expansions
1835 * @return $-expanded string, never NULL unless @a orig was NULL
1836 */
1837static char *
1838expand_dollar (const struct GNUNET_CONFIGURATION_Handle *cfg,
1839 char *orig,
1840 unsigned int depth)
1841{
1842 char *prefix;
1843 char *result;
1844 char *start;
1845 const char *post;
1846 const char *env;
1847 char *def;
1848 char *end;
1849 unsigned int lopen;
1850 char erased_char;
1851 char *erased_pos;
1852 size_t len;
1853
1854 if (NULL == orig)
1855 return NULL;
1856 if (depth > 128)
1857 {
1858 LOG (GNUNET_ERROR_TYPE_WARNING,
1859 _ (
1860 "Recursive expansion suspected, aborting $-expansion for term `%s'\n"),
1861 orig);
1862 return orig;
1863 }
1864 LOG (GNUNET_ERROR_TYPE_DEBUG, "Asked to $-expand %s\n", orig);
1865 if ('$' != orig[0])
1866 {
1867 LOG (GNUNET_ERROR_TYPE_DEBUG, "Doesn't start with $ - not expanding\n");
1868 return orig;
1869 }
1870 erased_char = 0;
1871 erased_pos = NULL;
1872 if ('{' == orig[1])
1873 {
1874 start = &orig[2];
1875 lopen = 1;
1876 end = &orig[1];
1877 while (lopen > 0)
1878 {
1879 end++;
1880 switch (*end)
1881 {
1882 case '}':
1883 lopen--;
1884 break;
1885
1886 case '{':
1887 lopen++;
1888 break;
1889
1890 case '\0':
1891 LOG (GNUNET_ERROR_TYPE_WARNING,
1892 _ ("Missing closing `%s' in option `%s'\n"),
1893 "}",
1894 orig);
1895 return orig;
1896
1897 default:
1898 break;
1899 }
1900 }
1901 erased_char = *end;
1902 erased_pos = end;
1903 *end = '\0';
1904 post = end + 1;
1905 def = strchr (orig, ':');
1906 if (NULL != def)
1907 {
1908 *def = '\0';
1909 def++;
1910 if (('-' == *def) || ('=' == *def))
1911 def++;
1912 def = GNUNET_strdup (def);
1913 }
1914 }
1915 else
1916 {
1917 int i;
1918
1919 start = &orig[1];
1920 def = NULL;
1921 i = 0;
1922 while ((orig[i] != '/') && (orig[i] != '\\') && (orig[i] != '\0') &&
1923 (orig[i] != ' '))
1924 i++;
1925 if (orig[i] == '\0')
1926 {
1927 post = "";
1928 }
1929 else
1930 {
1931 erased_char = orig[i];
1932 erased_pos = &orig[i];
1933 orig[i] = '\0';
1934 post = &orig[i + 1];
1935 }
1936 }
1937 LOG (GNUNET_ERROR_TYPE_DEBUG,
1938 "Split into `%s' and `%s' with default %s\n",
1939 start,
1940 post,
1941 def);
1942 if (GNUNET_OK !=
1943 GNUNET_CONFIGURATION_get_value_string (cfg, "PATHS", start, &prefix))
1944 {
1945 if (NULL == (env = getenv (start)))
1946 {
1947 /* try default */
1948 def = expand_dollar (cfg, def, depth + 1);
1949 env = def;
1950 }
1951 if (NULL == env)
1952 {
1953 start = GNUNET_strdup (start);
1954 if (erased_pos)
1955 *erased_pos = erased_char;
1956 LOG (GNUNET_ERROR_TYPE_WARNING,
1957 _ (
1958 "Failed to expand `%s' in `%s' as it is neither found in [PATHS] nor defined as an environmental variable\n"),
1959 start,
1960 orig);
1961 GNUNET_free (start);
1962 return orig;
1963 }
1964 prefix = GNUNET_strdup (env);
1965 }
1966 prefix = GNUNET_CONFIGURATION_expand_dollar (cfg, prefix);
1967 if ((erased_pos) && ('}' != erased_char))
1968 {
1969 len = strlen (prefix) + 1;
1970 prefix = GNUNET_realloc (prefix, len + 1);
1971 prefix[len - 1] = erased_char;
1972 prefix[len] = '\0';
1973 }
1974 result = GNUNET_malloc (strlen (prefix) + strlen (post) + 1);
1975 strcpy (result, prefix);
1976 strcat (result, post);
1977 GNUNET_free (def);
1978 GNUNET_free (prefix);
1979 GNUNET_free (orig);
1980 return result;
1981}
1982
1983
1984char *
1985GNUNET_CONFIGURATION_expand_dollar (
1986 const struct GNUNET_CONFIGURATION_Handle *cfg,
1987 char *orig)
1988{
1989 char *dup;
1990 size_t i;
1991 size_t len;
1992
1993 for (i = 0; '\0' != orig[i]; i++)
1994 {
1995 if ('$' != orig[i])
1996 continue;
1997 dup = GNUNET_strdup (orig + i);
1998 dup = expand_dollar (cfg, dup, 0);
1999 GNUNET_assert (NULL != dup); /* make compiler happy */
2000 len = strlen (dup) + 1;
2001 orig = GNUNET_realloc (orig, i + len);
2002 GNUNET_memcpy (orig + i, dup, len);
2003 GNUNET_free (dup);
2004 }
2005 return orig;
2006}
2007
2008
2009enum GNUNET_GenericReturnValue
2010GNUNET_CONFIGURATION_get_value_filename (
2011 const struct GNUNET_CONFIGURATION_Handle *cfg,
2012 const char *section,
2013 const char *option,
2014 char **value)
2015{
2016 char *tmp;
2017
2018 if (GNUNET_OK !=
2019 GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &tmp))
2020 {
2021 LOG (GNUNET_ERROR_TYPE_DEBUG, "Failed to retrieve filename\n");
2022 *value = NULL;
2023 return GNUNET_SYSERR;
2024 }
2025 tmp = GNUNET_CONFIGURATION_expand_dollar (cfg, tmp);
2026 *value = GNUNET_STRINGS_filename_expand (tmp);
2027 GNUNET_free (tmp);
2028 if (*value == NULL)
2029 return GNUNET_SYSERR;
2030 return GNUNET_OK;
2031}
2032
2033
2034enum GNUNET_GenericReturnValue
2035GNUNET_CONFIGURATION_get_value_yesno (
2036 const struct GNUNET_CONFIGURATION_Handle *cfg,
2037 const char *section,
2038 const char *option)
2039{
2040 static const char *yesno[] = { "YES", "NO", NULL };
2041 const char *val;
2042 int ret;
2043
2044 ret =
2045 GNUNET_CONFIGURATION_get_value_choice (cfg, section, option, yesno, &val);
2046 if (ret == GNUNET_SYSERR)
2047 return ret;
2048 if (val == yesno[0])
2049 return GNUNET_YES;
2050 return GNUNET_NO;
2051}
2052
2053
2054int
2055GNUNET_CONFIGURATION_iterate_value_filenames (
2056 const struct GNUNET_CONFIGURATION_Handle *cfg,
2057 const char *section,
2058 const char *option,
2059 GNUNET_FileNameCallback cb,
2060 void *cb_cls)
2061{
2062 char *list;
2063 char *pos;
2064 char *end;
2065 char old;
2066 int ret;
2067
2068 if (GNUNET_OK !=
2069 GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &list))
2070 return 0;
2071 GNUNET_assert (list != NULL);
2072 ret = 0;
2073 pos = list;
2074 while (1)
2075 {
2076 while (pos[0] == ' ')
2077 pos++;
2078 if (strlen (pos) == 0)
2079 break;
2080 end = pos + 1;
2081 while ((end[0] != ' ') && (end[0] != '\0'))
2082 {
2083 if (end[0] == '\\')
2084 {
2085 switch (end[1])
2086 {
2087 case '\\':
2088 case ' ':
2089 memmove (end, &end[1], strlen (&end[1]) + 1);
2090
2091 case '\0':
2092 /* illegal, but just keep it */
2093 break;
2094
2095 default:
2096 /* illegal, but just ignore that there was a '/' */
2097 break;
2098 }
2099 }
2100 end++;
2101 }
2102 old = end[0];
2103 end[0] = '\0';
2104 if (strlen (pos) > 0)
2105 {
2106 ret++;
2107 if ((cb != NULL) && (GNUNET_OK != cb (cb_cls, pos)))
2108 {
2109 ret = GNUNET_SYSERR;
2110 break;
2111 }
2112 }
2113 if (old == '\0')
2114 break;
2115 pos = end + 1;
2116 }
2117 GNUNET_free (list);
2118 return ret;
2119}
2120
2121
2122/**
2123 * FIXME.
2124 *
2125 * @param value FIXME
2126 * @return FIXME
2127 */
2128static char *
2129escape_name (const char *value)
2130{
2131 char *escaped;
2132 const char *rpos;
2133 char *wpos;
2134
2135 escaped = GNUNET_malloc (strlen (value) * 2 + 1);
2136 memset (escaped, 0, strlen (value) * 2 + 1);
2137 rpos = value;
2138 wpos = escaped;
2139 while (rpos[0] != '\0')
2140 {
2141 switch (rpos[0])
2142 {
2143 case '\\':
2144 case ' ':
2145 wpos[0] = '\\';
2146 wpos[1] = rpos[0];
2147 wpos += 2;
2148 break;
2149
2150 default:
2151 wpos[0] = rpos[0];
2152 wpos++;
2153 }
2154 rpos++;
2155 }
2156 return escaped;
2157}
2158
2159
2160/**
2161 * FIXME.
2162 *
2163 * @param cls string we compare with (const char*)
2164 * @param fn filename we are currently looking at
2165 * @return #GNUNET_OK if the names do not match, #GNUNET_SYSERR if they do
2166 */
2167static enum GNUNET_GenericReturnValue
2168test_match (void *cls, const char *fn)
2169{
2170 const char *of = cls;
2171
2172 return (0 == strcmp (of, fn)) ? GNUNET_SYSERR : GNUNET_OK;
2173}
2174
2175
2176enum GNUNET_GenericReturnValue
2177GNUNET_CONFIGURATION_append_value_filename (
2178 struct GNUNET_CONFIGURATION_Handle *cfg,
2179 const char *section,
2180 const char *option,
2181 const char *value)
2182{
2183 char *escaped;
2184 char *old;
2185 char *nw;
2186
2187 if (GNUNET_SYSERR ==
2188 GNUNET_CONFIGURATION_iterate_value_filenames (cfg,
2189 section,
2190 option,
2191 &test_match,
2192 (void *) value))
2193 return GNUNET_NO; /* already exists */
2194 if (GNUNET_OK !=
2195 GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &old))
2196 old = GNUNET_strdup ("");
2197 escaped = escape_name (value);
2198 nw = GNUNET_malloc (strlen (old) + strlen (escaped) + 2);
2199 strcpy (nw, old);
2200 if (strlen (old) > 0)
2201 strcat (nw, " ");
2202 strcat (nw, escaped);
2203 GNUNET_CONFIGURATION_set_value_string (cfg, section, option, nw);
2204 GNUNET_free (old);
2205 GNUNET_free (nw);
2206 GNUNET_free (escaped);
2207 return GNUNET_OK;
2208}
2209
2210
2211enum GNUNET_GenericReturnValue
2212GNUNET_CONFIGURATION_remove_value_filename (
2213 struct GNUNET_CONFIGURATION_Handle *cfg,
2214 const char *section,
2215 const char *option,
2216 const char *value)
2217{
2218 char *list;
2219 char *pos;
2220 char *end;
2221 char *match;
2222 char old;
2223
2224 if (GNUNET_OK !=
2225 GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &list))
2226 return GNUNET_NO;
2227 match = escape_name (value);
2228 pos = list;
2229 while (1)
2230 {
2231 while (pos[0] == ' ')
2232 pos++;
2233 if (strlen (pos) == 0)
2234 break;
2235 end = pos + 1;
2236 while ((end[0] != ' ') && (end[0] != '\0'))
2237 {
2238 if (end[0] == '\\')
2239 {
2240 switch (end[1])
2241 {
2242 case '\\':
2243 case ' ':
2244 end++;
2245 break;
2246
2247 case '\0':
2248 /* illegal, but just keep it */
2249 break;
2250
2251 default:
2252 /* illegal, but just ignore that there was a '/' */
2253 break;
2254 }
2255 }
2256 end++;
2257 }
2258 old = end[0];
2259 end[0] = '\0';
2260 if (0 == strcmp (pos, match))
2261 {
2262 if (old != '\0')
2263 memmove (pos, &end[1], strlen (&end[1]) + 1);
2264 else
2265 {
2266 if (pos != list)
2267 pos[-1] = '\0';
2268 else
2269 pos[0] = '\0';
2270 }
2271 GNUNET_CONFIGURATION_set_value_string (cfg, section, option, list);
2272 GNUNET_free (list);
2273 GNUNET_free (match);
2274 return GNUNET_OK;
2275 }
2276 if (old == '\0')
2277 break;
2278 end[0] = old;
2279 pos = end + 1;
2280 }
2281 GNUNET_free (list);
2282 GNUNET_free (match);
2283 return GNUNET_NO;
2284}
2285
2286
2287enum GNUNET_GenericReturnValue
2288GNUNET_CONFIGURATION_load_from (struct GNUNET_CONFIGURATION_Handle *cfg,
2289 const char *defaults_d)
2290{
2291 struct CollectFilesContext files_context = {
2292 .files = NULL,
2293 .files_length = 0,
2294 };
2295 enum GNUNET_GenericReturnValue fun_ret;
2296
2297 if (GNUNET_SYSERR ==
2298 GNUNET_DISK_directory_scan (defaults_d, &collect_files_cb,
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++)
2306 {
2307 char *ext;
2308 const char *filename = files_context.files[i];
2309
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;
2332}
2333
2334
2335char *
2336GNUNET_CONFIGURATION_default_filename (void)
2337{
2338 char *cfg_fn;
2339 const struct GNUNET_OS_ProjectData *pd = GNUNET_OS_project_data_get ();
2340 const char *xdg = getenv ("XDG_CONFIG_HOME");
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;
2374}
2375
2376
2377struct GNUNET_CONFIGURATION_Handle *
2378GNUNET_CONFIGURATION_default (void)
2379{
2380 const struct GNUNET_OS_ProjectData *pd = GNUNET_OS_project_data_get ();
2381 const struct GNUNET_OS_ProjectData *dpd = GNUNET_OS_project_data_default ();
2382 const char *xdg = getenv ("XDG_CONFIG_HOME");
2383 char *cfgname = NULL;
2384 struct GNUNET_CONFIGURATION_Handle *cfg;
2385
2386 /* Makes sure function implicitly looking at the installation directory (for
2387 example GNUNET_CONFIGURATION_load further down) use GNUnet's environment
2388 instead of the caller's. It's done at the start to make sure as many
2389 functions as possible are directed to the proper paths. */
2390 GNUNET_OS_init (dpd);
2391
2392 cfg = GNUNET_CONFIGURATION_create ();
2393
2394 /* First, try user configuration. */
2395 if (NULL != xdg)
2396 GNUNET_asprintf (&cfgname, "%s/%s", xdg, dpd->config_file);
2397 else
2398 cfgname = GNUNET_strdup (dpd->user_config_file);
2399
2400 /* If user config doesn't exist, try in
2401 /etc/<projdir>/<cfgfile> and /etc/<cfgfile> */
2402 if (GNUNET_OK != GNUNET_DISK_file_test (cfgname))
2403 {
2404 GNUNET_free (cfgname);
2405 GNUNET_asprintf (&cfgname, "/etc/%s", dpd->config_file);
2406 }
2407 if (GNUNET_OK != GNUNET_DISK_file_test (cfgname))
2408 {
2409 GNUNET_free (cfgname);
2410 GNUNET_asprintf (&cfgname,
2411 "/etc/%s/%s",
2412 dpd->project_dirname,
2413 dpd->config_file);
2414 }
2415 if (GNUNET_OK != GNUNET_DISK_file_test (cfgname))
2416 {
2417 LOG (GNUNET_ERROR_TYPE_ERROR,
2418 "Unable to top-level configuration file.\n");
2419 GNUNET_OS_init (pd);
2420 GNUNET_CONFIGURATION_destroy (cfg);
2421 GNUNET_free (cfgname);
2422 return NULL;
2423 }
2424
2425 /* We found a configuration file that looks good, try to load it. */
2426
2427 LOG (GNUNET_ERROR_TYPE_DEBUG,
2428 "Loading top-level configuration from '%s'\n",
2429 cfgname);
2430 if (GNUNET_OK !=
2431 GNUNET_CONFIGURATION_load (cfg, cfgname))
2432 {
2433 GNUNET_OS_init (pd);
2434 GNUNET_CONFIGURATION_destroy (cfg);
2435 GNUNET_free (cfgname);
2436 return NULL;
2437 }
2438 GNUNET_free (cfgname);
2439 GNUNET_OS_init (pd);
2440 return cfg;
2441}
2442
2443
2444/**
2445 * Load configuration (starts with defaults, then loads
2446 * system-specific configuration).
2447 *
2448 * @param cfg configuration to update
2449 * @param filename name of the configuration file, NULL to load defaults
2450 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
2451 */
2452int
2453GNUNET_CONFIGURATION_load (struct GNUNET_CONFIGURATION_Handle *cfg,
2454 const char *filename)
2455{
2456 char *baseconfig;
2457 const char *base_config_varname;
2458
2459 if (cfg->load_called)
2460 {
2461 /* FIXME: Make this a GNUNET_assert later */
2462 GNUNET_break (0);
2463 GNUNET_free (cfg->main_filename);
2464 }
2465 cfg->load_called = true;
2466 if (NULL != filename)
2467 {
2468 GNUNET_free (cfg->main_filename);
2469 cfg->main_filename = GNUNET_strdup (filename);
2470 }
2471
2472 base_config_varname = GNUNET_OS_project_data_get ()->base_config_varname;
2473
2474 if ((NULL != base_config_varname)
2475 && (NULL != (baseconfig = getenv (base_config_varname))))
2476 {
2477 baseconfig = GNUNET_strdup (baseconfig);
2478 }
2479 else
2480 {
2481 char *ipath;
2482
2483 ipath = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR);
2484 if (NULL == ipath)
2485 {
2486 GNUNET_break (0);
2487 return GNUNET_SYSERR;
2488 }
2489 GNUNET_asprintf (&baseconfig, "%s%s", ipath, "config.d");
2490 GNUNET_free (ipath);
2491 }
2492
2493 char *dname = GNUNET_STRINGS_filename_expand (baseconfig);
2494 GNUNET_free (baseconfig);
2495
2496 if ((GNUNET_YES == GNUNET_DISK_directory_test (dname, GNUNET_YES)) &&
2497 (GNUNET_SYSERR == GNUNET_CONFIGURATION_load_from (cfg, dname)))
2498 {
2499 LOG (GNUNET_ERROR_TYPE_WARNING,
2500 "Failed to load base configuration from '%s'\n",
2501 filename);
2502 GNUNET_free (dname);
2503 return GNUNET_SYSERR; /* no configuration at all found */
2504 }
2505 GNUNET_free (dname);
2506 if ((NULL != filename) &&
2507 (GNUNET_OK != GNUNET_CONFIGURATION_parse (cfg, filename)))
2508 {
2509 /* specified configuration not found */
2510 LOG (GNUNET_ERROR_TYPE_WARNING,
2511 "Failed to load configuration from file '%s'\n",
2512 filename);
2513 return GNUNET_SYSERR;
2514 }
2515 if (((GNUNET_YES !=
2516 GNUNET_CONFIGURATION_have_value (cfg, "PATHS", "DEFAULTCONFIG"))) &&
2517 (filename != NULL))
2518 GNUNET_CONFIGURATION_set_value_string (cfg, "PATHS", "DEFAULTCONFIG",
2519 filename);
2520 return GNUNET_OK;
2521}
2522
2523
2524/* end of configuration.c */