reduce scope
[oweals/gnunet.git] / src / util / configuration.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2006, 2007, 2008, 2009, 2013 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 /**
22  * @file src/util/configuration.c
23  * @brief configuration management
24  * @author Christian Grothoff
25  */
26
27 #include "platform.h"
28 #include "gnunet_crypto_lib.h"
29 #include "gnunet_strings_lib.h"
30 #include "gnunet_configuration_lib.h"
31 #include "gnunet_disk_lib.h"
32
33 #define LOG(kind, ...) GNUNET_log_from(kind, "util", __VA_ARGS__)
34
35 #define LOG_STRERROR_FILE(kind, syscall, filename) \
36   GNUNET_log_from_strerror_file(kind, "util", syscall, filename)
37
38 /**
39  * @brief configuration entry
40  */
41 struct ConfigEntry {
42   /**
43    * This is a linked list.
44    */
45   struct ConfigEntry *next;
46
47   /**
48    * key for this entry
49    */
50   char *key;
51
52   /**
53    * current, commited value
54    */
55   char *val;
56 };
57
58
59 /**
60  * @brief configuration section
61  */
62 struct ConfigSection {
63   /**
64    * This is a linked list.
65    */
66   struct ConfigSection *next;
67
68   /**
69    * entries in the section
70    */
71   struct ConfigEntry *entries;
72
73   /**
74    * name of the section
75    */
76   char *name;
77 };
78
79
80 /**
81  * @brief configuration data
82  */
83 struct GNUNET_CONFIGURATION_Handle {
84   /**
85    * Configuration sections.
86    */
87   struct ConfigSection *sections;
88
89   /**
90    * Modification indication since last save
91    * #GNUNET_NO if clean, #GNUNET_YES if dirty,
92    * #GNUNET_SYSERR on error (i.e. last save failed)
93    */
94   int dirty;
95 };
96
97
98 /**
99  * Used for diffing a configuration object against
100  * the default one
101  */
102 struct DiffHandle {
103   const struct GNUNET_CONFIGURATION_Handle *cfg_default;
104
105   struct GNUNET_CONFIGURATION_Handle *cfgDiff;
106 };
107
108
109 /**
110  * Create a GNUNET_CONFIGURATION_Handle.
111  *
112  * @return fresh configuration object
113  */
114 struct GNUNET_CONFIGURATION_Handle *
115 GNUNET_CONFIGURATION_create()
116 {
117   return GNUNET_new(struct GNUNET_CONFIGURATION_Handle);
118 }
119
120
121 /**
122  * Destroy configuration object.
123  *
124  * @param cfg configuration to destroy
125  */
126 void
127 GNUNET_CONFIGURATION_destroy(struct GNUNET_CONFIGURATION_Handle *cfg)
128 {
129   struct ConfigSection *sec;
130
131   while (NULL != (sec = cfg->sections))
132     GNUNET_CONFIGURATION_remove_section(cfg, sec->name);
133   GNUNET_free(cfg);
134 }
135
136
137 /**
138  * Parse a configuration file @a filename and run the function
139  * @a cb with the resulting configuration object. Then free the
140  * configuration object and return the status value from @a cb.
141  *
142  * @param filename configuration to parse, NULL for "default"
143  * @param cb function to run
144  * @param cb_cls closure for @a cb
145  * @return #GNUNET_SYSERR if parsing the configuration failed,
146  *   otherwise return value from @a cb.
147  */
148 int
149 GNUNET_CONFIGURATION_parse_and_run(const char *filename,
150                                    GNUNET_CONFIGURATION_Callback cb,
151                                    void *cb_cls)
152 {
153   struct GNUNET_CONFIGURATION_Handle *cfg;
154   int ret;
155
156   cfg = GNUNET_CONFIGURATION_create();
157   if (GNUNET_OK != GNUNET_CONFIGURATION_load(cfg, filename))
158     {
159       GNUNET_break(0);
160       GNUNET_CONFIGURATION_destroy(cfg);
161       return GNUNET_SYSERR;
162     }
163   ret = cb(cb_cls, cfg);
164   GNUNET_CONFIGURATION_destroy(cfg);
165   return ret;
166 }
167
168
169 /**
170  * De-serializes configuration
171  *
172  * @param cfg configuration to update
173  * @param mem the memory block of serialized configuration
174  * @param size the size of the memory block
175  * @param basedir set to path from which we recursively load configuration
176  *          from inlined configurations; NULL if not and raise warnings
177  *          when we come across them
178  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
179  */
180 int
181 GNUNET_CONFIGURATION_deserialize(struct GNUNET_CONFIGURATION_Handle *cfg,
182                                  const char *mem,
183                                  size_t size,
184                                  const char *basedir)
185 {
186   char *line;
187   char *line_orig;
188   size_t line_size;
189   char *pos;
190   unsigned int nr;
191   size_t r_bytes;
192   size_t to_read;
193   size_t i;
194   int emptyline;
195   int ret;
196   char *section;
197   char *eq;
198   char *tag;
199   char *value;
200
201   ret = GNUNET_OK;
202   section = GNUNET_strdup("");
203   nr = 0;
204   r_bytes = 0;
205   line_orig = NULL;
206   while (r_bytes < size)
207     {
208       GNUNET_free_non_null(line_orig);
209       /* fgets-like behaviour on buffer */
210       to_read = size - r_bytes;
211       pos = memchr(&mem[r_bytes], '\n', to_read);
212       if (NULL == pos)
213         {
214           line_orig = GNUNET_strndup(&mem[r_bytes], line_size = to_read);
215           r_bytes += line_size;
216         }
217       else
218         {
219           line_orig =
220             GNUNET_strndup(&mem[r_bytes], line_size = (pos - &mem[r_bytes]));
221           r_bytes += line_size + 1;
222         }
223       line = line_orig;
224       /* increment line number */
225       nr++;
226       /* tabs and '\r' are whitespace */
227       emptyline = GNUNET_YES;
228       for (i = 0; i < line_size; i++)
229         {
230           if (line[i] == '\t')
231             line[i] = ' ';
232           if (line[i] == '\r')
233             line[i] = ' ';
234           if (' ' != line[i])
235             emptyline = GNUNET_NO;
236         }
237       /* ignore empty lines */
238       if (GNUNET_YES == emptyline)
239         continue;
240
241       /* remove tailing whitespace */
242       for (i = line_size - 1; (i >= 1) && (isspace((unsigned char)line[i]));
243            i--)
244         line[i] = '\0';
245
246       /* remove leading whitespace */
247       for (; line[0] != '\0' && (isspace((unsigned char)line[0])); line++)
248         ;
249
250       /* ignore comments */
251       if (('#' == line[0]) || ('%' == line[0]))
252         continue;
253
254       /* handle special "@INLINE@" directive */
255       if (0 == strncasecmp(line, "@INLINE@ ", strlen("@INLINE@ ")))
256         {
257           /* @INLINE@ value */
258           value = &line[strlen("@INLINE@ ")];
259           if (NULL != basedir)
260             {
261               char *fn;
262
263               GNUNET_asprintf(&fn, "%s/%s", basedir, value);
264               if (GNUNET_OK != GNUNET_CONFIGURATION_parse(cfg, fn))
265                 {
266                   GNUNET_free(fn);
267                   ret = GNUNET_SYSERR; /* failed to parse included config */
268                   break;
269                 }
270               GNUNET_free(fn);
271             }
272           else
273             {
274               LOG(GNUNET_ERROR_TYPE_DEBUG,
275                   "Ignoring parsing @INLINE@ configurations, not allowed!\n");
276               ret = GNUNET_SYSERR;
277               break;
278             }
279           continue;
280         }
281       if (('[' == line[0]) && (']' == line[line_size - 1]))
282         {
283           /* [value] */
284           line[line_size - 1] = '\0';
285           value = &line[1];
286           GNUNET_free(section);
287           section = GNUNET_strdup(value);
288           continue;
289         }
290       if (NULL != (eq = strchr(line, '=')))
291         {
292           /* tag = value */
293           tag = GNUNET_strndup(line, eq - line);
294           /* remove tailing whitespace */
295           for (i = strlen(tag) - 1; (i >= 1) && (isspace((unsigned char)tag[i]));
296                i--)
297             tag[i] = '\0';
298
299           /* Strip whitespace */
300           value = eq + 1;
301           while (isspace((unsigned char)value[0]))
302             value++;
303           for (i = strlen(value) - 1;
304                (i >= 1) && (isspace((unsigned char)value[i]));
305                i--)
306             value[i] = '\0';
307
308           /* remove quotes */
309           i = 0;
310           if (('"' == value[0]) && ('"' == value[strlen(value) - 1]))
311             {
312               value[strlen(value) - 1] = '\0';
313               value++;
314             }
315           GNUNET_CONFIGURATION_set_value_string(cfg, section, tag, &value[i]);
316           GNUNET_free(tag);
317           continue;
318         }
319       /* parse error */
320       LOG(GNUNET_ERROR_TYPE_WARNING,
321           _("Syntax error while deserializing in line %u\n"),
322           nr);
323       ret = GNUNET_SYSERR;
324       break;
325     }
326   GNUNET_free_non_null(line_orig);
327   GNUNET_free(section);
328   GNUNET_assert((GNUNET_OK != ret) || (r_bytes == size));
329   return ret;
330 }
331
332
333 /**
334  * Parse a configuration file, add all of the options in the
335  * file to the configuration environment.
336  *
337  * @param cfg configuration to update
338  * @param filename name of the configuration file
339  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
340  */
341 int
342 GNUNET_CONFIGURATION_parse(struct GNUNET_CONFIGURATION_Handle *cfg,
343                            const char *filename)
344 {
345   uint64_t fs64;
346   size_t fs;
347   char *fn;
348   char *mem;
349   char *endsep;
350   int dirty;
351   int ret;
352   ssize_t sret;
353
354   fn = GNUNET_STRINGS_filename_expand(filename);
355   LOG(GNUNET_ERROR_TYPE_DEBUG, "Asked to parse config file `%s'\n", fn);
356   if (NULL == fn)
357     return GNUNET_SYSERR;
358   dirty = cfg->dirty; /* back up value! */
359   if (GNUNET_SYSERR ==
360       GNUNET_DISK_file_size(fn, &fs64, GNUNET_YES, GNUNET_YES))
361     {
362       LOG(GNUNET_ERROR_TYPE_WARNING,
363           "Error while determining the file size of `%s'\n",
364           fn);
365       GNUNET_free(fn);
366       return GNUNET_SYSERR;
367     }
368   if (fs64 > SIZE_MAX)
369     {
370       GNUNET_break(0); /* File size is more than the heap size */
371       GNUNET_free(fn);
372       return GNUNET_SYSERR;
373     }
374   fs = fs64;
375   mem = GNUNET_malloc(fs);
376   sret = GNUNET_DISK_fn_read(fn, mem, fs);
377   if ((sret < 0) || (fs != (size_t)sret))
378     {
379       LOG(GNUNET_ERROR_TYPE_WARNING, _("Error while reading file `%s'\n"), fn);
380       GNUNET_free(fn);
381       GNUNET_free(mem);
382       return GNUNET_SYSERR;
383     }
384   LOG(GNUNET_ERROR_TYPE_DEBUG, "Deserializing contents of file `%s'\n", fn);
385   endsep = strrchr(fn, (int)'/');
386   if (NULL != endsep)
387     *endsep = '\0';
388   ret = GNUNET_CONFIGURATION_deserialize(cfg, mem, fs, fn);
389   GNUNET_free(fn);
390   GNUNET_free(mem);
391   /* restore dirty flag - anything we set in the meantime
392    * came from disk */
393   cfg->dirty = dirty;
394   return ret;
395 }
396
397
398 /**
399  * Test if there are configuration options that were
400  * changed since the last save.
401  *
402  * @param cfg configuration to inspect
403  * @return #GNUNET_NO if clean, #GNUNET_YES if dirty, #GNUNET_SYSERR on error (i.e. last save failed)
404  */
405 int
406 GNUNET_CONFIGURATION_is_dirty(const struct GNUNET_CONFIGURATION_Handle *cfg)
407 {
408   return cfg->dirty;
409 }
410
411
412 /**
413  * Serializes the given configuration.
414  *
415  * @param cfg configuration to serialize
416  * @param size will be set to the size of the serialized memory block
417  * @return the memory block where the serialized configuration is
418  *           present. This memory should be freed by the caller
419  */
420 char *
421 GNUNET_CONFIGURATION_serialize(const struct GNUNET_CONFIGURATION_Handle *cfg,
422                                size_t *size)
423 {
424   struct ConfigSection *sec;
425   struct ConfigEntry *ent;
426   char *mem;
427   char *cbuf;
428   char *val;
429   char *pos;
430   int len;
431   size_t m_size;
432   size_t c_size;
433
434   /* Pass1 : calculate the buffer size required */
435   m_size = 0;
436   for (sec = cfg->sections; NULL != sec; sec = sec->next)
437     {
438       /* For each section we need to add 3 charaters: {'[',']','\n'} */
439       m_size += strlen(sec->name) + 3;
440       for (ent = sec->entries; NULL != ent; ent = ent->next)
441         {
442           if (NULL != ent->val)
443             {
444               /* if val has any '\n' then they occupy +1 character as '\n'->'\\','n' */
445               pos = ent->val;
446               while (NULL != (pos = strstr(pos, "\n")))
447                 {
448                   m_size++;
449                   pos++;
450                 }
451               /* For each key = value pair we need to add 4 characters (2
452                  spaces and 1 equal-to character and 1 new line) */
453               m_size += strlen(ent->key) + strlen(ent->val) + 4;
454             }
455         }
456       /* A new line after section end */
457       m_size++;
458     }
459
460   /* Pass2: Allocate memory and write the configuration to it */
461   mem = GNUNET_malloc(m_size);
462   sec = cfg->sections;
463   c_size = 0;
464   *size = c_size;
465   while (NULL != sec)
466     {
467       len = GNUNET_asprintf(&cbuf, "[%s]\n", sec->name);
468       GNUNET_assert(0 < len);
469       GNUNET_memcpy(mem + c_size, cbuf, len);
470       c_size += len;
471       GNUNET_free(cbuf);
472       for (ent = sec->entries; NULL != ent; ent = ent->next)
473         {
474           if (NULL != ent->val)
475             {
476               val = GNUNET_malloc(strlen(ent->val) * 2 + 1);
477               strcpy(val, ent->val);
478               while (NULL != (pos = strstr(val, "\n")))
479                 {
480                   memmove(&pos[2], &pos[1], strlen(&pos[1]));
481                   pos[0] = '\\';
482                   pos[1] = 'n';
483                 }
484               len = GNUNET_asprintf(&cbuf, "%s = %s\n", ent->key, val);
485               GNUNET_free(val);
486               GNUNET_memcpy(mem + c_size, cbuf, len);
487               c_size += len;
488               GNUNET_free(cbuf);
489             }
490         }
491       GNUNET_memcpy(mem + c_size, "\n", 1);
492       c_size++;
493       sec = sec->next;
494     }
495   GNUNET_assert(c_size == m_size);
496   *size = c_size;
497   return mem;
498 }
499
500
501 /**
502  * Write configuration file.
503  *
504  * @param cfg configuration to write
505  * @param filename where to write the configuration
506  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
507  */
508 int
509 GNUNET_CONFIGURATION_write(struct GNUNET_CONFIGURATION_Handle *cfg,
510                            const char *filename)
511 {
512   char *fn;
513   char *cfg_buf;
514   size_t size;
515   ssize_t sret;
516
517   fn = GNUNET_STRINGS_filename_expand(filename);
518   if (fn == NULL)
519     return GNUNET_SYSERR;
520   if (GNUNET_OK != GNUNET_DISK_directory_create_for_file(fn))
521     {
522       GNUNET_free(fn);
523       return GNUNET_SYSERR;
524     }
525   cfg_buf = GNUNET_CONFIGURATION_serialize(cfg, &size);
526   sret = GNUNET_DISK_fn_write(fn,
527                               cfg_buf,
528                               size,
529                               GNUNET_DISK_PERM_USER_READ |
530                               GNUNET_DISK_PERM_USER_WRITE |
531                               GNUNET_DISK_PERM_GROUP_READ |
532                               GNUNET_DISK_PERM_GROUP_WRITE);
533   if ((sret < 0) || (size != (size_t)sret))
534     {
535       GNUNET_free(fn);
536       GNUNET_free(cfg_buf);
537       LOG(GNUNET_ERROR_TYPE_WARNING,
538           "Writing configuration to file `%s' failed\n",
539           filename);
540       cfg->dirty = GNUNET_SYSERR; /* last write failed */
541       return GNUNET_SYSERR;
542     }
543   GNUNET_free(fn);
544   GNUNET_free(cfg_buf);
545   cfg->dirty = GNUNET_NO; /* last write succeeded */
546   return GNUNET_OK;
547 }
548
549
550 /**
551  * Iterate over all options in the configuration.
552  *
553  * @param cfg configuration to inspect
554  * @param iter function to call on each option
555  * @param iter_cls closure for @a iter
556  */
557 void
558 GNUNET_CONFIGURATION_iterate(const struct GNUNET_CONFIGURATION_Handle *cfg,
559                              GNUNET_CONFIGURATION_Iterator iter,
560                              void *iter_cls)
561 {
562   struct ConfigSection *spos;
563   struct ConfigEntry *epos;
564
565   for (spos = cfg->sections; NULL != spos; spos = spos->next)
566     for (epos = spos->entries; NULL != epos; epos = epos->next)
567       if (NULL != epos->val)
568         iter(iter_cls, spos->name, epos->key, epos->val);
569 }
570
571
572 /**
573  * Iterate over values of a section in the configuration.
574  *
575  * @param cfg configuration to inspect
576  * @param section the section
577  * @param iter function to call on each option
578  * @param iter_cls closure for @a iter
579  */
580 void
581 GNUNET_CONFIGURATION_iterate_section_values(
582   const struct GNUNET_CONFIGURATION_Handle *cfg,
583   const char *section,
584   GNUNET_CONFIGURATION_Iterator iter,
585   void *iter_cls)
586 {
587   struct ConfigSection *spos;
588   struct ConfigEntry *epos;
589
590   spos = cfg->sections;
591   while ((spos != NULL) && (0 != strcasecmp(spos->name, section)))
592     spos = spos->next;
593   if (NULL == spos)
594     return;
595   for (epos = spos->entries; NULL != epos; epos = epos->next)
596     if (NULL != epos->val)
597       iter(iter_cls, spos->name, epos->key, epos->val);
598 }
599
600
601 /**
602  * Iterate over all sections in the configuration.
603  *
604  * @param cfg configuration to inspect
605  * @param iter function to call on each section
606  * @param iter_cls closure for @a iter
607  */
608 void
609 GNUNET_CONFIGURATION_iterate_sections(
610   const struct GNUNET_CONFIGURATION_Handle *cfg,
611   GNUNET_CONFIGURATION_Section_Iterator iter,
612   void *iter_cls)
613 {
614   struct ConfigSection *spos;
615   struct ConfigSection *next;
616
617   next = cfg->sections;
618   while (next != NULL)
619     {
620       spos = next;
621       next = spos->next;
622       iter(iter_cls, spos->name);
623     }
624 }
625
626
627 /**
628  * Remove the given section and all options in it.
629  *
630  * @param cfg configuration to inspect
631  * @param section name of the section to remove
632  */
633 void
634 GNUNET_CONFIGURATION_remove_section(struct GNUNET_CONFIGURATION_Handle *cfg,
635                                     const char *section)
636 {
637   struct ConfigSection *spos;
638   struct ConfigSection *prev;
639   struct ConfigEntry *ent;
640
641   prev = NULL;
642   spos = cfg->sections;
643   while (NULL != spos)
644     {
645       if (0 == strcasecmp(section, spos->name))
646         {
647           if (NULL == prev)
648             cfg->sections = spos->next;
649           else
650             prev->next = spos->next;
651           while (NULL != (ent = spos->entries))
652             {
653               spos->entries = ent->next;
654               GNUNET_free(ent->key);
655               GNUNET_free_non_null(ent->val);
656               GNUNET_free(ent);
657               cfg->dirty = GNUNET_YES;
658             }
659           GNUNET_free(spos->name);
660           GNUNET_free(spos);
661           return;
662         }
663       prev = spos;
664       spos = spos->next;
665     }
666 }
667
668
669 /**
670  * Copy a configuration value to the given target configuration.
671  * Overwrites existing entries.
672  *
673  * @param cls the destination configuration (`struct GNUNET_CONFIGURATION_Handle *`)
674  * @param section section for the value
675  * @param option option name of the value
676  * @param value value to copy
677  */
678 static void
679 copy_entry(void *cls,
680            const char *section,
681            const char *option,
682            const char *value)
683 {
684   struct GNUNET_CONFIGURATION_Handle *dst = cls;
685
686   GNUNET_CONFIGURATION_set_value_string(dst, section, option, value);
687 }
688
689
690 /**
691  * Duplicate an existing configuration object.
692  *
693  * @param cfg configuration to duplicate
694  * @return duplicate configuration
695  */
696 struct GNUNET_CONFIGURATION_Handle *
697 GNUNET_CONFIGURATION_dup(const struct GNUNET_CONFIGURATION_Handle *cfg)
698 {
699   struct GNUNET_CONFIGURATION_Handle *ret;
700
701   ret = GNUNET_CONFIGURATION_create();
702   GNUNET_CONFIGURATION_iterate(cfg, &copy_entry, ret);
703   return ret;
704 }
705
706
707 /**
708  * Find a section entry from a configuration.
709  *
710  * @param cfg configuration to search in
711  * @param section name of the section to look for
712  * @return matching entry, NULL if not found
713  */
714 static struct ConfigSection *
715 find_section(const struct GNUNET_CONFIGURATION_Handle *cfg,
716              const char *section)
717 {
718   struct ConfigSection *pos;
719
720   pos = cfg->sections;
721   while ((pos != NULL) && (0 != strcasecmp(section, pos->name)))
722     pos = pos->next;
723   return pos;
724 }
725
726
727 /**
728  * Find an entry from a configuration.
729  *
730  * @param cfg handle to the configuration
731  * @param section section the option is in
732  * @param key the option
733  * @return matching entry, NULL if not found
734  */
735 static struct ConfigEntry *
736 find_entry(const struct GNUNET_CONFIGURATION_Handle *cfg,
737            const char *section,
738            const char *key)
739 {
740   struct ConfigSection *sec;
741   struct ConfigEntry *pos;
742
743   if (NULL == (sec = find_section(cfg, section)))
744     return NULL;
745   pos = sec->entries;
746   while ((pos != NULL) && (0 != strcasecmp(key, pos->key)))
747     pos = pos->next;
748   return pos;
749 }
750
751
752 /**
753  * A callback function, compares entries from two configurations
754  * (default against a new configuration) and write the diffs in a
755  * diff-configuration object (the callback object).
756  *
757  * @param cls the diff configuration (`struct DiffHandle *`)
758  * @param section section for the value (of the default conf.)
759  * @param option option name of the value (of the default conf.)
760  * @param value value to copy (of the default conf.)
761  */
762 static void
763 compare_entries(void *cls,
764                 const char *section,
765                 const char *option,
766                 const char *value)
767 {
768   struct DiffHandle *dh = cls;
769   struct ConfigEntry *entNew;
770
771   entNew = find_entry(dh->cfg_default, section, option);
772   if ((NULL != entNew) && (NULL != entNew->val) &&
773       (0 == strcmp(entNew->val, value)))
774     return;
775   GNUNET_CONFIGURATION_set_value_string(dh->cfgDiff, section, option, value);
776 }
777
778
779 /**
780  * Compute configuration with only entries that have been changed
781  *
782  * @param cfg_default original configuration
783  * @param cfg_new new configuration
784  * @return configuration with only the differences, never NULL
785  */
786 struct GNUNET_CONFIGURATION_Handle *
787 GNUNET_CONFIGURATION_get_diff(
788   const struct GNUNET_CONFIGURATION_Handle *cfg_default,
789   const struct GNUNET_CONFIGURATION_Handle *cfg_new)
790 {
791   struct DiffHandle diffHandle;
792
793   diffHandle.cfgDiff = GNUNET_CONFIGURATION_create();
794   diffHandle.cfg_default = cfg_default;
795   GNUNET_CONFIGURATION_iterate(cfg_new, &compare_entries, &diffHandle);
796   return diffHandle.cfgDiff;
797 }
798
799
800 /**
801  * Write only configuration entries that have been changed to configuration file
802  *
803  * @param cfg_default default configuration
804  * @param cfg_new new configuration
805  * @param filename where to write the configuration diff between default and new
806  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
807  */
808 int
809 GNUNET_CONFIGURATION_write_diffs(
810   const struct GNUNET_CONFIGURATION_Handle *cfg_default,
811   const struct GNUNET_CONFIGURATION_Handle *cfg_new,
812   const char *filename)
813 {
814   int ret;
815   struct GNUNET_CONFIGURATION_Handle *diff;
816
817   diff = GNUNET_CONFIGURATION_get_diff(cfg_default, cfg_new);
818   ret = GNUNET_CONFIGURATION_write(diff, filename);
819   GNUNET_CONFIGURATION_destroy(diff);
820   return ret;
821 }
822
823
824 /**
825  * Set a configuration value that should be a string.
826  *
827  * @param cfg configuration to update
828  * @param section section of interest
829  * @param option option of interest
830  * @param value value to set
831  */
832 void
833 GNUNET_CONFIGURATION_set_value_string(struct GNUNET_CONFIGURATION_Handle *cfg,
834                                       const char *section,
835                                       const char *option,
836                                       const char *value)
837 {
838   struct ConfigSection *sec;
839   struct ConfigEntry *e;
840   char *nv;
841
842   e = find_entry(cfg, section, option);
843   if (NULL != e)
844     {
845       if (NULL == value)
846         {
847           GNUNET_free_non_null(e->val);
848           e->val = NULL;
849         }
850       else
851         {
852           nv = GNUNET_strdup(value);
853           GNUNET_free_non_null(e->val);
854           e->val = nv;
855         }
856       return;
857     }
858   sec = find_section(cfg, section);
859   if (sec == NULL)
860     {
861       sec = GNUNET_new(struct ConfigSection);
862       sec->name = GNUNET_strdup(section);
863       sec->next = cfg->sections;
864       cfg->sections = sec;
865     }
866   e = GNUNET_new(struct ConfigEntry);
867   e->key = GNUNET_strdup(option);
868   e->val = GNUNET_strdup(value);
869   e->next = sec->entries;
870   sec->entries = e;
871 }
872
873
874 /**
875  * Set a configuration value that should be a number.
876  *
877  * @param cfg configuration to update
878  * @param section section of interest
879  * @param option option of interest
880  * @param number value to set
881  */
882 void
883 GNUNET_CONFIGURATION_set_value_number(struct GNUNET_CONFIGURATION_Handle *cfg,
884                                       const char *section,
885                                       const char *option,
886                                       unsigned long long number)
887 {
888   char s[64];
889
890   GNUNET_snprintf(s, 64, "%llu", number);
891   GNUNET_CONFIGURATION_set_value_string(cfg, section, option, s);
892 }
893
894
895 /**
896  * Get a configuration value that should be a number.
897  *
898  * @param cfg configuration to inspect
899  * @param section section of interest
900  * @param option option of interest
901  * @param number where to store the numeric value of the option
902  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
903  */
904 int
905 GNUNET_CONFIGURATION_get_value_number(
906   const struct GNUNET_CONFIGURATION_Handle *cfg,
907   const char *section,
908   const char *option,
909   unsigned long long *number)
910 {
911   struct ConfigEntry *e;
912   char dummy[2];
913
914   if (NULL == (e = find_entry(cfg, section, option)))
915     return GNUNET_SYSERR;
916   if (NULL == e->val)
917     return GNUNET_SYSERR;
918   if (1 != sscanf(e->val, "%llu%1s", number, dummy))
919     return GNUNET_SYSERR;
920   return GNUNET_OK;
921 }
922
923
924 /**
925  * Get a configuration value that should be a floating point number.
926  *
927  * @param cfg configuration to inspect
928  * @param section section of interest
929  * @param option option of interest
930  * @param number where to store the floating value of the option
931  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
932  */
933 int
934 GNUNET_CONFIGURATION_get_value_float(
935   const struct GNUNET_CONFIGURATION_Handle *cfg,
936   const char *section,
937   const char *option,
938   float *number)
939 {
940   struct ConfigEntry *e;
941   char dummy[2];
942
943   if (NULL == (e = find_entry(cfg, section, option)))
944     return GNUNET_SYSERR;
945   if (NULL == e->val)
946     return GNUNET_SYSERR;
947   if (1 != sscanf(e->val, "%f%1s", number, dummy))
948     return GNUNET_SYSERR;
949   return GNUNET_OK;
950 }
951
952
953 /**
954  * Get a configuration value that should be a relative time.
955  *
956  * @param cfg configuration to inspect
957  * @param section section of interest
958  * @param option option of interest
959  * @param time set to the time value stored in the configuration
960  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
961  */
962 int
963 GNUNET_CONFIGURATION_get_value_time(
964   const struct GNUNET_CONFIGURATION_Handle *cfg,
965   const char *section,
966   const char *option,
967   struct GNUNET_TIME_Relative *time)
968 {
969   struct ConfigEntry *e;
970   int ret;
971
972   if (NULL == (e = find_entry(cfg, section, option)))
973     return GNUNET_SYSERR;
974   if (NULL == e->val)
975     return GNUNET_SYSERR;
976   ret = GNUNET_STRINGS_fancy_time_to_relative(e->val, time);
977   if (GNUNET_OK != ret)
978     GNUNET_log_config_invalid(GNUNET_ERROR_TYPE_ERROR,
979                               section,
980                               option,
981                               _("Not a valid relative time specification"));
982   return ret;
983 }
984
985
986 /**
987  * Get a configuration value that should be a size in bytes.
988  *
989  * @param cfg configuration to inspect
990  * @param section section of interest
991  * @param option option of interest
992  * @param size set to the size in bytes as stored in the configuration
993  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
994  */
995 int
996 GNUNET_CONFIGURATION_get_value_size(
997   const struct GNUNET_CONFIGURATION_Handle *cfg,
998   const char *section,
999   const char *option,
1000   unsigned long long *size)
1001 {
1002   struct ConfigEntry *e;
1003
1004   if (NULL == (e = find_entry(cfg, section, option)))
1005     return GNUNET_SYSERR;
1006   if (NULL == e->val)
1007     return GNUNET_SYSERR;
1008   return GNUNET_STRINGS_fancy_size_to_bytes(e->val, size);
1009 }
1010
1011
1012 /**
1013  * Get a configuration value that should be a string.
1014  *
1015  * @param cfg configuration to inspect
1016  * @param section section of interest
1017  * @param option option of interest
1018  * @param value will be set to a freshly allocated configuration
1019  *        value, or NULL if option is not specified
1020  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1021  */
1022 int
1023 GNUNET_CONFIGURATION_get_value_string(
1024   const struct GNUNET_CONFIGURATION_Handle *cfg,
1025   const char *section,
1026   const char *option,
1027   char **value)
1028 {
1029   struct ConfigEntry *e;
1030
1031   if ((NULL == (e = find_entry(cfg, section, option))) || (NULL == e->val))
1032     {
1033       *value = NULL;
1034       return GNUNET_SYSERR;
1035     }
1036   *value = GNUNET_strdup(e->val);
1037   return GNUNET_OK;
1038 }
1039
1040
1041 /**
1042  * Get a configuration value that should be in a set of
1043  * predefined strings
1044  *
1045  * @param cfg configuration to inspect
1046  * @param section section of interest
1047  * @param option option of interest
1048  * @param choices NULL-terminated list of legal values
1049  * @param value will be set to an entry in the legal list,
1050  *        or NULL if option is not specified and no default given
1051  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1052  */
1053 int
1054 GNUNET_CONFIGURATION_get_value_choice(
1055   const struct GNUNET_CONFIGURATION_Handle *cfg,
1056   const char *section,
1057   const char *option,
1058   const char *const *choices,
1059   const char **value)
1060 {
1061   struct ConfigEntry *e;
1062   unsigned int i;
1063
1064   if (NULL == (e = find_entry(cfg, section, option)))
1065     return GNUNET_SYSERR;
1066   for (i = 0; NULL != choices[i]; i++)
1067     if (0 == strcasecmp(choices[i], e->val))
1068       break;
1069   if (NULL == choices[i])
1070     {
1071       LOG(GNUNET_ERROR_TYPE_ERROR,
1072           _("Configuration value '%s' for '%s'"
1073             " in section '%s' is not in set of legal choices\n"),
1074           e->val,
1075           option,
1076           section);
1077       return GNUNET_SYSERR;
1078     }
1079   *value = choices[i];
1080   return GNUNET_OK;
1081 }
1082
1083
1084 /**
1085  * Get crockford32-encoded fixed-size binary data from a configuration.
1086  *
1087  * @param cfg configuration to access
1088  * @param section section to access
1089  * @param option option to access
1090  * @param buf where to store the decoded binary result
1091  * @param buf_size exact number of bytes to store in @a buf
1092  * @return #GNUNET_OK on success
1093  *         #GNUNET_NO is the value does not exist
1094  *         #GNUNET_SYSERR on decoding error
1095  */
1096 int
1097 GNUNET_CONFIGURATION_get_data(const struct GNUNET_CONFIGURATION_Handle *cfg,
1098                               const char *section,
1099                               const char *option,
1100                               void *buf,
1101                               size_t buf_size)
1102 {
1103   char *enc;
1104   int res;
1105   size_t data_size;
1106
1107   if (GNUNET_OK !=
1108       (res =
1109          GNUNET_CONFIGURATION_get_value_string(cfg, section, option, &enc)))
1110     return res;
1111   data_size = (strlen(enc) * 5) / 8;
1112   if (data_size != buf_size)
1113     {
1114       GNUNET_free(enc);
1115       return GNUNET_SYSERR;
1116     }
1117   if (GNUNET_OK !=
1118       GNUNET_STRINGS_string_to_data(enc, strlen(enc), buf, buf_size))
1119     {
1120       GNUNET_free(enc);
1121       return GNUNET_SYSERR;
1122     }
1123   GNUNET_free(enc);
1124   return GNUNET_OK;
1125 }
1126
1127
1128 /**
1129  * Test if we have a value for a particular option
1130  *
1131  * @param cfg configuration to inspect
1132  * @param section section of interest
1133  * @param option option of interest
1134  * @return #GNUNET_YES if so, #GNUNET_NO if not.
1135  */
1136 int
1137 GNUNET_CONFIGURATION_have_value(const struct GNUNET_CONFIGURATION_Handle *cfg,
1138                                 const char *section,
1139                                 const char *option)
1140 {
1141   struct ConfigEntry *e;
1142
1143   if ((NULL == (e = find_entry(cfg, section, option))) || (NULL == e->val))
1144     return GNUNET_NO;
1145   return GNUNET_YES;
1146 }
1147
1148
1149 /**
1150  * Expand an expression of the form "$FOO/BAR" to "DIRECTORY/BAR"
1151  * where either in the "PATHS" section or the environtment "FOO" is
1152  * set to "DIRECTORY".  We also support default expansion,
1153  * i.e. ${VARIABLE:-default} will expand to $VARIABLE if VARIABLE is
1154  * set in PATHS or the environment, and otherwise to "default".  Note
1155  * that "default" itself can also be a $-expression, thus
1156  * "${VAR1:-{$VAR2}}" will expand to VAR1 and if that is not defined
1157  * to VAR2.
1158  *
1159  * @param cfg configuration to use for path expansion
1160  * @param orig string to $-expand (will be freed!)
1161  * @param depth recursion depth, used to detect recursive expansions
1162  * @return $-expanded string
1163  */
1164 static char *
1165 expand_dollar(const struct GNUNET_CONFIGURATION_Handle *cfg,
1166               char *orig,
1167               unsigned int depth)
1168 {
1169   char *prefix;
1170   char *result;
1171   char *start;
1172   const char *post;
1173   const char *env;
1174   char *def;
1175   char *end;
1176   unsigned int lopen;
1177   char erased_char;
1178   char *erased_pos;
1179   size_t len;
1180
1181   if (NULL == orig)
1182     return NULL;
1183   if (depth > 128)
1184     {
1185       LOG(GNUNET_ERROR_TYPE_WARNING,
1186           _(
1187             "Recursive expansion suspected, aborting $-expansion for term `%s'\n"),
1188           orig);
1189       return orig;
1190     }
1191   LOG(GNUNET_ERROR_TYPE_DEBUG, "Asked to $-expand %s\n", orig);
1192   if ('$' != orig[0])
1193     {
1194       LOG(GNUNET_ERROR_TYPE_DEBUG, "Doesn't start with $ - not expanding\n");
1195       return orig;
1196     }
1197   erased_char = 0;
1198   erased_pos = NULL;
1199   if ('{' == orig[1])
1200     {
1201       start = &orig[2];
1202       lopen = 1;
1203       end = &orig[1];
1204       while (lopen > 0)
1205         {
1206           end++;
1207           switch (*end)
1208             {
1209             case '}':
1210               lopen--;
1211               break;
1212
1213             case '{':
1214               lopen++;
1215               break;
1216
1217             case '\0':
1218               LOG(GNUNET_ERROR_TYPE_WARNING,
1219                   _("Missing closing `%s' in option `%s'\n"),
1220                   "}",
1221                   orig);
1222               return orig;
1223
1224             default:
1225               break;
1226             }
1227         }
1228       erased_char = *end;
1229       erased_pos = end;
1230       *end = '\0';
1231       post = end + 1;
1232       def = strchr(orig, ':');
1233       if (NULL != def)
1234         {
1235           *def = '\0';
1236           def++;
1237           if (('-' == *def) || ('=' == *def))
1238             def++;
1239           def = GNUNET_strdup(def);
1240         }
1241     }
1242   else
1243     {
1244       int i;
1245
1246       start = &orig[1];
1247       def = NULL;
1248       i = 0;
1249       while ((orig[i] != '/') && (orig[i] != '\\') && (orig[i] != '\0') &&
1250              (orig[i] != ' '))
1251         i++;
1252       if (orig[i] == '\0')
1253         {
1254           post = "";
1255         }
1256       else
1257         {
1258           erased_char = orig[i];
1259           erased_pos = &orig[i];
1260           orig[i] = '\0';
1261           post = &orig[i + 1];
1262         }
1263     }
1264   LOG(GNUNET_ERROR_TYPE_DEBUG,
1265       "Split into `%s' and `%s' with default %s\n",
1266       start,
1267       post,
1268       def);
1269   if (GNUNET_OK !=
1270       GNUNET_CONFIGURATION_get_value_string(cfg, "PATHS", start, &prefix))
1271     {
1272       if (NULL == (env = getenv(start)))
1273         {
1274           /* try default */
1275           def = expand_dollar(cfg, def, depth + 1);
1276           env = def;
1277         }
1278       if (NULL == env)
1279         {
1280           start = GNUNET_strdup(start);
1281           if (erased_pos)
1282             *erased_pos = erased_char;
1283           LOG(GNUNET_ERROR_TYPE_WARNING,
1284               _(
1285                 "Failed to expand `%s' in `%s' as it is neither found in [PATHS] nor defined as an environmental variable\n"),
1286               start,
1287               orig);
1288           GNUNET_free(start);
1289           return orig;
1290         }
1291       prefix = GNUNET_strdup(env);
1292     }
1293   prefix = GNUNET_CONFIGURATION_expand_dollar(cfg, prefix);
1294   if ((erased_pos) && ('}' != erased_char))
1295     {
1296       len = strlen(prefix) + 1;
1297       prefix = GNUNET_realloc(prefix, len + 1);
1298       prefix[len - 1] = erased_char;
1299       prefix[len] = '\0';
1300     }
1301   result = GNUNET_malloc(strlen(prefix) + strlen(post) + 1);
1302   strcpy(result, prefix);
1303   strcat(result, post);
1304   GNUNET_free_non_null(def);
1305   GNUNET_free(prefix);
1306   GNUNET_free(orig);
1307   return result;
1308 }
1309
1310
1311 /**
1312  * Expand an expression of the form "$FOO/BAR" to "DIRECTORY/BAR"
1313  * where either in the "PATHS" section or the environtment "FOO" is
1314  * set to "DIRECTORY".  We also support default expansion,
1315  * i.e. ${VARIABLE:-default} will expand to $VARIABLE if VARIABLE is
1316  * set in PATHS or the environment, and otherwise to "default".  Note
1317  * that "default" itself can also be a $-expression, thus
1318  * "${VAR1:-{$VAR2}}" will expand to VAR1 and if that is not defined
1319  * to VAR2.
1320  *
1321  * @param cfg configuration to use for path expansion
1322  * @param orig string to $-expand (will be freed!).  Note that multiple
1323  *          $-expressions can be present in this string.  They will all be
1324  *          $-expanded.
1325  * @return $-expanded string
1326  */
1327 char *
1328 GNUNET_CONFIGURATION_expand_dollar(
1329   const struct GNUNET_CONFIGURATION_Handle *cfg,
1330   char *orig)
1331 {
1332   char *dup;
1333   size_t i;
1334   size_t len;
1335
1336   for (i = 0; '\0' != orig[i]; i++)
1337     {
1338       if ('$' != orig[i])
1339         continue;
1340       dup = GNUNET_strdup(orig + i);
1341       dup = expand_dollar(cfg, dup, 0);
1342       len = strlen(dup) + 1;
1343       orig = GNUNET_realloc(orig, i + len);
1344       GNUNET_memcpy(orig + i, dup, len);
1345       GNUNET_free(dup);
1346     }
1347   return orig;
1348 }
1349
1350
1351 /**
1352  * Get a configuration value that should be a string.
1353  *
1354  * @param cfg configuration to inspect
1355  * @param section section of interest
1356  * @param option option of interest
1357  * @param value will be set to a freshly allocated configuration
1358  *        value, or NULL if option is not specified
1359  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1360  */
1361 int
1362 GNUNET_CONFIGURATION_get_value_filename(
1363   const struct GNUNET_CONFIGURATION_Handle *cfg,
1364   const char *section,
1365   const char *option,
1366   char **value)
1367 {
1368   char *tmp;
1369
1370   if (GNUNET_OK !=
1371       GNUNET_CONFIGURATION_get_value_string(cfg, section, option, &tmp))
1372     {
1373       LOG(GNUNET_ERROR_TYPE_DEBUG, "Failed to retrieve filename\n");
1374       *value = NULL;
1375       return GNUNET_SYSERR;
1376     }
1377   tmp = GNUNET_CONFIGURATION_expand_dollar(cfg, tmp);
1378   *value = GNUNET_STRINGS_filename_expand(tmp);
1379   GNUNET_free(tmp);
1380   if (*value == NULL)
1381     return GNUNET_SYSERR;
1382   return GNUNET_OK;
1383 }
1384
1385
1386 /**
1387  * Get a configuration value that should be in a set of
1388  * "YES" or "NO".
1389  *
1390  * @param cfg configuration to inspect
1391  * @param section section of interest
1392  * @param option option of interest
1393  * @return #GNUNET_YES, #GNUNET_NO or #GNUNET_SYSERR
1394  */
1395 int
1396 GNUNET_CONFIGURATION_get_value_yesno(
1397   const struct GNUNET_CONFIGURATION_Handle *cfg,
1398   const char *section,
1399   const char *option)
1400 {
1401   static const char *yesno[] = { "YES", "NO", NULL };
1402   const char *val;
1403   int ret;
1404
1405   ret =
1406     GNUNET_CONFIGURATION_get_value_choice(cfg, section, option, yesno, &val);
1407   if (ret == GNUNET_SYSERR)
1408     return ret;
1409   if (val == yesno[0])
1410     return GNUNET_YES;
1411   return GNUNET_NO;
1412 }
1413
1414
1415 /**
1416  * Iterate over the set of filenames stored in a configuration value.
1417  *
1418  * @param cfg configuration to inspect
1419  * @param section section of interest
1420  * @param option option of interest
1421  * @param cb function to call on each filename
1422  * @param cb_cls closure for @a cb
1423  * @return number of filenames iterated over, -1 on error
1424  */
1425 int
1426 GNUNET_CONFIGURATION_iterate_value_filenames(
1427   const struct GNUNET_CONFIGURATION_Handle *cfg,
1428   const char *section,
1429   const char *option,
1430   GNUNET_FileNameCallback cb,
1431   void *cb_cls)
1432 {
1433   char *list;
1434   char *pos;
1435   char *end;
1436   char old;
1437   int ret;
1438
1439   if (GNUNET_OK !=
1440       GNUNET_CONFIGURATION_get_value_string(cfg, section, option, &list))
1441     return 0;
1442   GNUNET_assert(list != NULL);
1443   ret = 0;
1444   pos = list;
1445   while (1)
1446     {
1447       while (pos[0] == ' ')
1448         pos++;
1449       if (strlen(pos) == 0)
1450         break;
1451       end = pos + 1;
1452       while ((end[0] != ' ') && (end[0] != '\0'))
1453         {
1454           if (end[0] == '\\')
1455             {
1456               switch (end[1])
1457                 {
1458                 case '\\':
1459                 case ' ':
1460                   memmove(end, &end[1], strlen(&end[1]) + 1);
1461
1462                 case '\0':
1463                   /* illegal, but just keep it */
1464                   break;
1465
1466                 default:
1467                   /* illegal, but just ignore that there was a '/' */
1468                   break;
1469                 }
1470             }
1471           end++;
1472         }
1473       old = end[0];
1474       end[0] = '\0';
1475       if (strlen(pos) > 0)
1476         {
1477           ret++;
1478           if ((cb != NULL) && (GNUNET_OK != cb(cb_cls, pos)))
1479             {
1480               ret = GNUNET_SYSERR;
1481               break;
1482             }
1483         }
1484       if (old == '\0')
1485         break;
1486       pos = end + 1;
1487     }
1488   GNUNET_free(list);
1489   return ret;
1490 }
1491
1492
1493 /**
1494  * FIXME.
1495  *
1496  * @param value FIXME
1497  * @return FIXME
1498  */
1499 static char *
1500 escape_name(const char *value)
1501 {
1502   char *escaped;
1503   const char *rpos;
1504   char *wpos;
1505
1506   escaped = GNUNET_malloc(strlen(value) * 2 + 1);
1507   memset(escaped, 0, strlen(value) * 2 + 1);
1508   rpos = value;
1509   wpos = escaped;
1510   while (rpos[0] != '\0')
1511     {
1512       switch (rpos[0])
1513         {
1514         case '\\':
1515         case ' ':
1516           wpos[0] = '\\';
1517           wpos[1] = rpos[0];
1518           wpos += 2;
1519           break;
1520
1521         default:
1522           wpos[0] = rpos[0];
1523           wpos++;
1524         }
1525       rpos++;
1526     }
1527   return escaped;
1528 }
1529
1530
1531 /**
1532  * FIXME.
1533  *
1534  * @param cls string we compare with (const char*)
1535  * @param fn filename we are currently looking at
1536  * @return #GNUNET_OK if the names do not match, #GNUNET_SYSERR if they do
1537  */
1538 static int
1539 test_match(void *cls, const char *fn)
1540 {
1541   const char *of = cls;
1542
1543   return (0 == strcmp(of, fn)) ? GNUNET_SYSERR : GNUNET_OK;
1544 }
1545
1546
1547 /**
1548  * Append a filename to a configuration value that
1549  * represents a list of filenames
1550  *
1551  * @param cfg configuration to update
1552  * @param section section of interest
1553  * @param option option of interest
1554  * @param value filename to append
1555  * @return #GNUNET_OK on success,
1556  *         #GNUNET_NO if the filename already in the list
1557  *         #GNUNET_SYSERR on error
1558  */
1559 int
1560 GNUNET_CONFIGURATION_append_value_filename(
1561   struct GNUNET_CONFIGURATION_Handle *cfg,
1562   const char *section,
1563   const char *option,
1564   const char *value)
1565 {
1566   char *escaped;
1567   char *old;
1568   char *nw;
1569
1570   if (GNUNET_SYSERR ==
1571       GNUNET_CONFIGURATION_iterate_value_filenames(cfg,
1572                                                    section,
1573                                                    option,
1574                                                    &test_match,
1575                                                    (void *)value))
1576     return GNUNET_NO; /* already exists */
1577   if (GNUNET_OK !=
1578       GNUNET_CONFIGURATION_get_value_string(cfg, section, option, &old))
1579     old = GNUNET_strdup("");
1580   escaped = escape_name(value);
1581   nw = GNUNET_malloc(strlen(old) + strlen(escaped) + 2);
1582   strcpy(nw, old);
1583   if (strlen(old) > 0)
1584     strcat(nw, " ");
1585   strcat(nw, escaped);
1586   GNUNET_CONFIGURATION_set_value_string(cfg, section, option, nw);
1587   GNUNET_free(old);
1588   GNUNET_free(nw);
1589   GNUNET_free(escaped);
1590   return GNUNET_OK;
1591 }
1592
1593
1594 /**
1595  * Remove a filename from a configuration value that
1596  * represents a list of filenames
1597  *
1598  * @param cfg configuration to update
1599  * @param section section of interest
1600  * @param option option of interest
1601  * @param value filename to remove
1602  * @return #GNUNET_OK on success,
1603  *         #GNUNET_NO if the filename is not in the list,
1604  *         #GNUNET_SYSERR on error
1605  */
1606 int
1607 GNUNET_CONFIGURATION_remove_value_filename(
1608   struct GNUNET_CONFIGURATION_Handle *cfg,
1609   const char *section,
1610   const char *option,
1611   const char *value)
1612 {
1613   char *list;
1614   char *pos;
1615   char *end;
1616   char *match;
1617   char old;
1618
1619   if (GNUNET_OK !=
1620       GNUNET_CONFIGURATION_get_value_string(cfg, section, option, &list))
1621     return GNUNET_NO;
1622   match = escape_name(value);
1623   pos = list;
1624   while (1)
1625     {
1626       while (pos[0] == ' ')
1627         pos++;
1628       if (strlen(pos) == 0)
1629         break;
1630       end = pos + 1;
1631       while ((end[0] != ' ') && (end[0] != '\0'))
1632         {
1633           if (end[0] == '\\')
1634             {
1635               switch (end[1])
1636                 {
1637                 case '\\':
1638                 case ' ':
1639                   end++;
1640                   break;
1641
1642                 case '\0':
1643                   /* illegal, but just keep it */
1644                   break;
1645
1646                 default:
1647                   /* illegal, but just ignore that there was a '/' */
1648                   break;
1649                 }
1650             }
1651           end++;
1652         }
1653       old = end[0];
1654       end[0] = '\0';
1655       if (0 == strcmp(pos, match))
1656         {
1657           if (old != '\0')
1658             memmove(pos, &end[1], strlen(&end[1]) + 1);
1659           else
1660             {
1661               if (pos != list)
1662                 pos[-1] = '\0';
1663               else
1664                 pos[0] = '\0';
1665             }
1666           GNUNET_CONFIGURATION_set_value_string(cfg, section, option, list);
1667           GNUNET_free(list);
1668           GNUNET_free(match);
1669           return GNUNET_OK;
1670         }
1671       if (old == '\0')
1672         break;
1673       end[0] = old;
1674       pos = end + 1;
1675     }
1676   GNUNET_free(list);
1677   GNUNET_free(match);
1678   return GNUNET_NO;
1679 }
1680
1681
1682 /**
1683  * Wrapper around #GNUNET_CONFIGURATION_parse.  Called on each
1684  * file in a directory, we trigger parsing on those files that
1685  * end with ".conf".
1686  *
1687  * @param cls the cfg
1688  * @param filename file to parse
1689  * @return #GNUNET_OK on success
1690  */
1691 static int
1692 parse_configuration_file(void *cls, const char *filename)
1693 {
1694   struct GNUNET_CONFIGURATION_Handle *cfg = cls;
1695   char *ext;
1696   int ret;
1697
1698   /* Examine file extension */
1699   ext = strrchr(filename, '.');
1700   if ((NULL == ext) || (0 != strcmp(ext, ".conf")))
1701     {
1702       GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Skipping file `%s'\n", filename);
1703       return GNUNET_OK;
1704     }
1705
1706   ret = GNUNET_CONFIGURATION_parse(cfg, filename);
1707   return ret;
1708 }
1709
1710
1711 /**
1712  * Load default configuration.  This function will parse the
1713  * defaults from the given defaults_d directory.
1714  *
1715  * @param cfg configuration to update
1716  * @param defaults_d directory with the defaults
1717  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1718  */
1719 int
1720 GNUNET_CONFIGURATION_load_from(struct GNUNET_CONFIGURATION_Handle *cfg,
1721                                const char *defaults_d)
1722 {
1723   if (GNUNET_SYSERR ==
1724       GNUNET_DISK_directory_scan(defaults_d, &parse_configuration_file, cfg))
1725     return GNUNET_SYSERR; /* no configuration at all found */
1726   return GNUNET_OK;
1727 }
1728
1729
1730 /* end of configuration.c */