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