implementing time and size parsers for #1875
[oweals/gnunet.git] / src / util / configuration.c
1 /*
2      This file is part of GNUnet.
3      (C) 2006, 2007, 2008, 2009 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 2, or (at your
8      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      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  * @file src/util/configuration.c
23  * @brief configuration management
24  *
25  * @author Christian Grothoff
26  */
27
28 #include "platform.h"
29 #include "gnunet_common.h"
30 #include "gnunet_configuration_lib.h"
31 #include "gnunet_crypto_lib.h"
32 #include "gnunet_disk_lib.h"
33 #include "gnunet_os_lib.h"
34 #include "gnunet_strings_lib.h"
35
36 #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
37
38 #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
39
40 /**
41  * @brief configuration entry
42  */
43 struct ConfigEntry
44 {
45
46   /**
47    * This is a linked list.
48    */
49   struct ConfigEntry *next;
50
51   /**
52    * key for this entry
53    */
54   char *key;
55
56   /**
57    * current, commited value
58    */
59   char *val;
60 };
61
62
63 /**
64  * @brief configuration section
65  */
66 struct ConfigSection
67 {
68   /**
69    * This is a linked list.
70    */
71   struct ConfigSection *next;
72
73   /**
74    * entries in the section
75    */
76   struct ConfigEntry *entries;
77
78   /**
79    * name of the section
80    */
81   char *name;
82 };
83
84
85 /**
86  * @brief configuration data
87  */
88 struct GNUNET_CONFIGURATION_Handle
89 {
90   /**
91    * Configuration sections.
92    */
93   struct ConfigSection *sections;
94
95   /**
96    * Modification indication since last save
97    * GNUNET_NO if clean, GNUNET_YES if dirty,
98    * GNUNET_SYSERR on error (i.e. last save failed)
99    */
100   int dirty;
101
102 };
103
104
105 /**
106  * Used for diffing a configuration object against
107  * the default one
108  */
109 struct DiffHandle
110 {
111   const struct GNUNET_CONFIGURATION_Handle *cfgDefault;
112   struct GNUNET_CONFIGURATION_Handle *cfgDiff;
113 };
114
115
116
117 /**
118  * Create a GNUNET_CONFIGURATION_Handle.
119  *
120  * @return fresh configuration object
121  */
122 struct GNUNET_CONFIGURATION_Handle *
123 GNUNET_CONFIGURATION_create ()
124 {
125   return GNUNET_malloc (sizeof (struct GNUNET_CONFIGURATION_Handle));
126 }
127
128
129 /**
130  * Destroy configuration object.
131  *
132  * @param cfg configuration to destroy
133  */
134 void
135 GNUNET_CONFIGURATION_destroy (struct GNUNET_CONFIGURATION_Handle *cfg)
136 {
137   struct ConfigSection *sec;
138
139   while (NULL != (sec = cfg->sections))
140     GNUNET_CONFIGURATION_remove_section (cfg, sec->name);
141   GNUNET_free (cfg);
142 }
143
144
145 /**
146  * Parse a configuration file, add all of the options in the
147  * file to the configuration environment.
148  *
149  * @param cfg configuration to update
150  * @param filename name of the configuration file
151  * @return GNUNET_OK on success, GNUNET_SYSERR on error
152  */
153 int
154 GNUNET_CONFIGURATION_parse (struct GNUNET_CONFIGURATION_Handle *cfg,
155                             const char *filename)
156 {
157   int dirty;
158   char line[256];
159   char tag[64];
160   char value[192];
161   FILE *fp;
162   unsigned int nr;
163   int i;
164   int emptyline;
165   int ret;
166   char *section;
167   char *fn;
168
169   fn = GNUNET_STRINGS_filename_expand (filename);
170   if (fn == NULL)
171     return GNUNET_SYSERR;
172   dirty = cfg->dirty;           /* back up value! */
173   if (NULL == (fp = FOPEN (fn, "r")))
174     {
175       LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fopen", fn);
176       GNUNET_free (fn);
177       return GNUNET_SYSERR;
178     }
179   GNUNET_free (fn);
180   ret = GNUNET_OK;
181   section = GNUNET_strdup ("");
182   memset (line, 0, 256);
183   nr = 0;
184   while (NULL != fgets (line, 255, fp))
185     {
186       nr++;
187       for (i = 0; i < 255; i++)
188         if (line[i] == '\t')
189           line[i] = ' ';
190       if (line[0] == '\n' || line[0] == '#' || line[0] == '%'
191           || line[0] == '\r')
192         continue;
193       emptyline = 1;
194       for (i = 0; (i < 255 && line[i] != 0); i++)
195         if (line[i] != ' ' && line[i] != '\n' && line[i] != '\r')
196           emptyline = 0;
197       if (emptyline == 1)
198         continue;
199       /* remove tailing whitespace */
200       for (i = strlen (line) - 1;
201            (i >= 0) && (isspace ((unsigned char) line[i])); i--)
202         line[i] = '\0';
203       if (1 == sscanf (line, "@INLINE@ %191[^\n]", value))
204         {
205           /* @INLINE@ value */
206           if (GNUNET_OK != GNUNET_CONFIGURATION_parse (cfg, value))
207             ret = GNUNET_SYSERR;        /* failed to parse included config */
208         }
209       else if (1 == sscanf (line, "[%99[^]]]", value))
210         {
211           /* [value] */
212           GNUNET_free (section);
213           section = GNUNET_strdup (value);
214         }
215       else if (2 == sscanf (line, " %63[^= ] = %191[^\n]", tag, value))
216         {
217           /* tag = value */
218           /* Strip LF */
219           i = strlen (value) - 1;
220           while ((i >= 0) && (isspace ((unsigned char) value[i])))
221             value[i--] = '\0';
222           /* remove quotes */
223           i = 0;
224           if (value[0] == '"')
225             {
226               i = 1;
227               while ((value[i] != '\0') && (value[i] != '"'))
228                 i++;
229               if (value[i] == '"')
230                 {
231                   value[i] = '\0';
232                   i = 1;
233                 }
234               else
235                 i = 0;
236             }
237           GNUNET_CONFIGURATION_set_value_string (cfg, section, tag,
238                                                  &value[i]);
239         }
240       else if (1 == sscanf (line, " %63[^= ] =[^\n]", tag))
241         {
242           /* tag = */
243           GNUNET_CONFIGURATION_set_value_string (cfg, section, tag, "");
244         }
245       else
246         {
247           /* parse error */
248           LOG (GNUNET_ERROR_TYPE_WARNING,
249                _("Syntax error in configuration file `%s' at line %u.\n"),
250                filename, nr);
251           ret = GNUNET_SYSERR;
252           break;
253         }
254     }
255   GNUNET_assert (0 == fclose (fp));
256   /* restore dirty flag - anything we set in the meantime
257    * came from disk */
258   cfg->dirty = dirty;
259   GNUNET_free (section);
260   return ret;
261 }
262
263
264 /**
265  * Test if there are configuration options that were
266  * changed since the last save.
267  *
268  * @param cfg configuration to inspect
269  * @return GNUNET_NO if clean, GNUNET_YES if dirty, GNUNET_SYSERR on error (i.e. last save failed)
270  */
271 int
272 GNUNET_CONFIGURATION_is_dirty (const struct GNUNET_CONFIGURATION_Handle *cfg)
273 {
274   return cfg->dirty;
275 }
276
277
278 /**
279  * Write configuration file.
280  *
281  * @param cfg configuration to write
282  * @param filename where to write the configuration
283  * @return GNUNET_OK on success, GNUNET_SYSERR on error
284  */
285 int
286 GNUNET_CONFIGURATION_write (struct GNUNET_CONFIGURATION_Handle *cfg,
287                             const char *filename)
288 {
289   struct ConfigSection *sec;
290   struct ConfigEntry *ent;
291   FILE *fp;
292   int error;
293   char *fn;
294   char *val;
295   char *pos;
296
297   fn = GNUNET_STRINGS_filename_expand (filename);
298   if (fn == NULL)
299     return GNUNET_SYSERR;
300   if (GNUNET_OK != GNUNET_DISK_directory_create_for_file (fn))
301     {
302       GNUNET_free (fn);
303       return GNUNET_SYSERR;
304     }
305   if (NULL == (fp = FOPEN (fn, "w")))
306     {
307       LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fopen", fn);
308       GNUNET_free (fn);
309       return GNUNET_SYSERR;
310     }
311   GNUNET_free (fn);
312   error = 0;
313   sec = cfg->sections;
314   while (sec != NULL)
315     {
316       if (0 > fprintf (fp, "[%s]\n", sec->name))
317         {
318           error = 1;
319           break;
320         }
321       ent = sec->entries;
322       while (ent != NULL)
323         {
324           if (ent->val != NULL)
325             {
326               val = GNUNET_malloc (strlen (ent->val) * 2 + 1);
327               strcpy (val, ent->val);
328               while (NULL != (pos = strstr (val, "\n")))
329                 {
330                   memmove (&pos[2], &pos[1], strlen (&pos[1]));
331                   pos[0] = '\\';
332                   pos[1] = 'n';
333                 }
334               if (0 > fprintf (fp, "%s = %s\n", ent->key, val))
335                 {
336                   error = 1;
337                   GNUNET_free (val);
338                   break;
339                 }
340               GNUNET_free (val);
341             }
342           ent = ent->next;
343         }
344       if (error != 0)
345         break;
346       if (0 > fprintf (fp, "\n"))
347         {
348           error = 1;
349           break;
350         }
351       sec = sec->next;
352     }
353   if (error != 0)
354     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fprintf", filename);
355   GNUNET_assert (0 == fclose (fp));
356   if (error != 0)
357     {
358       cfg->dirty = GNUNET_SYSERR;       /* last write failed */
359       return GNUNET_SYSERR;
360     }
361   cfg->dirty = GNUNET_NO;       /* last write succeeded */
362   return GNUNET_OK;
363 }
364
365
366 /**
367  * Iterate over all options in the configuration.
368  *
369  * @param cfg configuration to inspect
370  * @param iter function to call on each option
371  * @param iter_cls closure for iter
372  */
373 void
374 GNUNET_CONFIGURATION_iterate (const struct GNUNET_CONFIGURATION_Handle *cfg,
375                               GNUNET_CONFIGURATION_Iterator iter,
376                               void *iter_cls)
377 {
378   struct ConfigSection *spos;
379   struct ConfigEntry *epos;
380
381   spos = cfg->sections;
382   while (spos != NULL)
383     {
384       epos = spos->entries;
385       while (epos != NULL)
386         {
387           iter (iter_cls, spos->name, epos->key, epos->val);
388           epos = epos->next;
389         }
390       spos = spos->next;
391     }
392 }
393
394
395 /**
396  * Iterate over values of a section in the configuration.
397  *
398  * @param cfg configuration to inspect
399  * @param section the section
400  * @param iter function to call on each option
401  * @param iter_cls closure for iter
402  */
403 void
404 GNUNET_CONFIGURATION_iterate_section_values (const struct
405                                              GNUNET_CONFIGURATION_Handle *cfg,
406                                              const char *section,
407                                              GNUNET_CONFIGURATION_Iterator
408                                              iter, void *iter_cls)
409 {
410   struct ConfigSection *spos;
411   struct ConfigEntry *epos;
412
413   spos = cfg->sections;
414   while ((spos != NULL) && (0 != strcmp (spos->name, section)))
415     spos = spos->next;
416
417   if (spos == NULL)
418     return;
419
420   epos = spos->entries;
421   while (epos != NULL)
422     {
423       iter (iter_cls, spos->name, epos->key, epos->val);
424       epos = epos->next;
425     }
426 }
427
428
429 /**
430  * Iterate over all sections in the configuration.
431  *
432  * @param cfg configuration to inspect
433  * @param iter function to call on each section
434  * @param iter_cls closure for iter
435  */
436 void
437 GNUNET_CONFIGURATION_iterate_sections (const struct
438                                        GNUNET_CONFIGURATION_Handle *cfg,
439                                        GNUNET_CONFIGURATION_Section_Iterator
440                                        iter, void *iter_cls)
441 {
442   struct ConfigSection *spos;
443   struct ConfigSection *next;
444
445   next = cfg->sections;
446   while (next != NULL)
447     {
448       spos = next;
449       next = spos->next;
450       iter (iter_cls, spos->name);
451     }
452 }
453
454 /**
455  * Remove the given section and all options in it.
456  *
457  * @param cfg configuration to inspect
458  * @param section name of the section to remove
459  */
460 void
461 GNUNET_CONFIGURATION_remove_section (struct GNUNET_CONFIGURATION_Handle *cfg,
462                                      const char *section)
463 {
464   struct ConfigSection *spos;
465   struct ConfigSection *prev;
466   struct ConfigEntry *ent;
467
468   prev = NULL;
469   spos = cfg->sections;
470   while (spos != NULL)
471     {
472       if (0 == strcmp (section, spos->name))
473         {
474           if (prev == NULL)
475             cfg->sections = spos->next;
476           else
477             prev->next = spos->next;
478           while (NULL != (ent = spos->entries))
479             {
480               spos->entries = ent->next;
481               GNUNET_free (ent->key);
482               GNUNET_free_non_null (ent->val);
483               GNUNET_free (ent);
484               cfg->dirty = GNUNET_YES;
485             }
486           GNUNET_free (spos->name);
487           GNUNET_free (spos);
488           return;
489         }
490       prev = spos;
491       spos = spos->next;
492     }
493 }
494
495
496 /**
497  * Copy a configuration value to the given target configuration.
498  * Overwrites existing entries.
499  *
500  * @param cls the destination configuration (struct GNUNET_CONFIGURATION_Handle*)
501  * @param section section for the value
502  * @param option option name of the value
503  * @param value value to copy
504  */
505 static void
506 copy_entry (void *cls, const char *section, const char *option,
507             const char *value)
508 {
509   struct GNUNET_CONFIGURATION_Handle *dst = cls;
510
511   GNUNET_CONFIGURATION_set_value_string (dst, section, option, value);
512 }
513
514
515 /**
516  * Duplicate an existing configuration object.
517  *
518  * @param cfg configuration to duplicate
519  * @return duplicate configuration
520  */
521 struct GNUNET_CONFIGURATION_Handle *
522 GNUNET_CONFIGURATION_dup (const struct GNUNET_CONFIGURATION_Handle *cfg)
523 {
524   struct GNUNET_CONFIGURATION_Handle *ret;
525
526   ret = GNUNET_CONFIGURATION_create ();
527   GNUNET_CONFIGURATION_iterate (cfg, &copy_entry, ret);
528   return ret;
529 }
530
531
532 /**
533  * FIXME.
534  *
535  * @param cfg FIXME
536  * @param section FIXME
537  * @return matching entry, NULL if not found
538  */
539 static struct ConfigSection *
540 findSection (const struct GNUNET_CONFIGURATION_Handle *cfg,
541              const char *section)
542 {
543   struct ConfigSection *pos;
544
545   pos = cfg->sections;
546   while ((pos != NULL) && (0 != strcasecmp (section, pos->name)))
547     pos = pos->next;
548   return pos;
549 }
550
551
552 /**
553  * Find an entry from a configuration.
554  *
555  * @param cfg handle to the configuration
556  * @param section section the option is in
557  * @param key the option
558  * @return matching entry, NULL if not found
559  */
560 static struct ConfigEntry *
561 findEntry (const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section,
562            const char *key)
563 {
564   struct ConfigSection *sec;
565   struct ConfigEntry *pos;
566
567   sec = findSection (cfg, section);
568   if (sec == NULL)
569     return NULL;
570   pos = sec->entries;
571   while ((pos != NULL) && (0 != strcasecmp (key, pos->key)))
572     pos = pos->next;
573   return pos;
574 }
575
576
577 /**
578  * A callback function, compares entries from two configurations
579  * (default against a new configuration) and write the diffs in a
580  * diff-configuration object (the callback object).
581  *
582  * @param cls the diff configuration (struct DiffHandle*)
583  * @param section section for the value (of the default conf.)
584  * @param option option name of the value (of the default conf.)
585  * @param value value to copy (of the default conf.)
586  */
587 static void
588 compareEntries (void *cls, const char *section, const char *option,
589                 const char *value)
590 {
591   struct DiffHandle *dh = cls;
592   struct ConfigEntry *entNew;
593
594   entNew = findEntry (dh->cfgDefault, section, option);
595   if ((entNew != NULL) && (strcmp (entNew->val, value) == 0))
596     return;
597   GNUNET_CONFIGURATION_set_value_string (dh->cfgDiff, section, option, value);
598 }
599
600
601 /**
602  * Write only configuration entries that have been changed to configuration file
603  * @param cfgDefault default configuration
604  * @param cfgNew new configuration
605  * @param filename where to write the configuration diff between default and new
606  * @return GNUNET_OK on success, GNUNET_SYSERR on error
607  */
608 int
609 GNUNET_CONFIGURATION_write_diffs (const struct GNUNET_CONFIGURATION_Handle
610                                   *cfgDefault,
611                                   const struct GNUNET_CONFIGURATION_Handle
612                                   *cfgNew, const char *filename)
613 {
614   int ret;
615   struct DiffHandle diffHandle;
616
617   diffHandle.cfgDiff = GNUNET_CONFIGURATION_create ();
618   diffHandle.cfgDefault = cfgDefault;
619   GNUNET_CONFIGURATION_iterate (cfgNew, compareEntries, &diffHandle);
620   ret = GNUNET_CONFIGURATION_write (diffHandle.cfgDiff, filename);
621   GNUNET_CONFIGURATION_destroy (diffHandle.cfgDiff);
622   return ret;
623 }
624
625
626 /**
627  * Set a configuration value that should be a string.
628  *
629  * @param cfg configuration to update
630  * @param section section of interest
631  * @param option option of interest
632  * @param value value to set
633  */
634 void
635 GNUNET_CONFIGURATION_set_value_string (struct GNUNET_CONFIGURATION_Handle
636                                        *cfg, const char *section,
637                                        const char *option, const char *value)
638 {
639   struct ConfigSection *sec;
640   struct ConfigEntry *e;
641
642   e = findEntry (cfg, section, option);
643   if (e != NULL)
644     {
645       GNUNET_free_non_null (e->val);
646       e->val = GNUNET_strdup (value);
647       return;
648     }
649   sec = findSection (cfg, section);
650   if (sec == NULL)
651     {
652       sec = GNUNET_malloc (sizeof (struct ConfigSection));
653       sec->name = GNUNET_strdup (section);
654       sec->next = cfg->sections;
655       cfg->sections = sec;
656     }
657   e = GNUNET_malloc (sizeof (struct ConfigEntry));
658   e->key = GNUNET_strdup (option);
659   e->val = GNUNET_strdup (value);
660   e->next = sec->entries;
661   sec->entries = e;
662 }
663
664
665 /**
666  * Set a configuration value that should be a number.
667  *
668  * @param cfg configuration to update
669  * @param section section of interest
670  * @param option option of interest
671  * @param number value to set
672  */
673 void
674 GNUNET_CONFIGURATION_set_value_number (struct GNUNET_CONFIGURATION_Handle
675                                        *cfg, const char *section,
676                                        const char *option,
677                                        unsigned long long number)
678 {
679   char s[64];
680
681   GNUNET_snprintf (s, 64, "%llu", number);
682   GNUNET_CONFIGURATION_set_value_string (cfg, section, option, s);
683 }
684
685
686 /**
687  * Get a configuration value that should be a number.
688  *
689  * @param cfg configuration to inspect
690  * @param section section of interest
691  * @param option option of interest
692  * @param number where to store the numeric value of the option
693  * @return GNUNET_OK on success, GNUNET_SYSERR on error
694  */
695 int
696 GNUNET_CONFIGURATION_get_value_number (const struct
697                                        GNUNET_CONFIGURATION_Handle *cfg,
698                                        const char *section,
699                                        const char *option,
700                                        unsigned long long *number)
701 {
702   struct ConfigEntry *e;
703
704   e = findEntry (cfg, section, option);
705   if (e == NULL)
706     return GNUNET_SYSERR;
707   if (1 != SSCANF (e->val, "%llu", number))
708     return GNUNET_SYSERR;
709   return GNUNET_OK;
710 }
711
712
713 /**
714  * Get a configuration value that should be a relative time.
715  *
716  * @param cfg configuration to inspect
717  * @param section section of interest
718  * @param option option of interest
719  * @param time set to the time value stored in the configuration
720  * @return GNUNET_OK on success, GNUNET_SYSERR on error
721  */
722 int
723 GNUNET_CONFIGURATION_get_value_time (const struct GNUNET_CONFIGURATION_Handle
724                                      *cfg, const char *section,
725                                      const char *option,
726                                      struct GNUNET_TIME_Relative *time)
727 {
728   struct ConfigEntry *e;
729   unsigned long long num;
730
731   e = findEntry (cfg, section, option);
732   if (e == NULL)
733     return GNUNET_SYSERR;
734
735   return GNUNET_STRINGS_fancy_time_to_relative (e->val,
736                                                 time);
737 }
738
739
740 /**
741  * Get a configuration value that should be a size in bytes.
742  *
743  * @param cfg configuration to inspect
744  * @param section section of interest
745  * @param option option of interest
746  * @param size set to the size in bytes as stored in the configuration
747  * @return GNUNET_OK on success, GNUNET_SYSERR on error
748  */
749 int
750 GNUNET_CONFIGURATION_get_value_size (const struct GNUNET_CONFIGURATION_Handle
751                                      *cfg, const char *section,
752                                      const char *option,
753                                      unsigned long long *size)
754 {
755   struct ConfigEntry *e;
756
757   e = findEntry (cfg, section, option);
758   if (e == NULL)
759     return GNUNET_SYSERR;
760   return GNUNET_STRINGS_fancy_size_to_bytes (e->val,
761                                              size);
762 }
763
764
765 /**
766  * Get a configuration value that should be a string.
767  *
768  * @param cfg configuration to inspect
769  * @param section section of interest
770  * @param option option of interest
771  * @param value will be set to a freshly allocated configuration
772  *        value, or NULL if option is not specified
773  * @return GNUNET_OK on success, GNUNET_SYSERR on error
774  */
775 int
776 GNUNET_CONFIGURATION_get_value_string (const struct
777                                        GNUNET_CONFIGURATION_Handle *cfg,
778                                        const char *section,
779                                        const char *option, char **value)
780 {
781   struct ConfigEntry *e;
782
783   e = findEntry (cfg, section, option);
784   if ((e == NULL) || (e->val == NULL))
785     {
786       *value = NULL;
787       return GNUNET_SYSERR;
788     }
789   *value = GNUNET_strdup (e->val);
790   return GNUNET_OK;
791 }
792
793
794 /**
795  * Get a configuration value that should be in a set of
796  * predefined strings
797  *
798  * @param cfg configuration to inspect
799  * @param section section of interest
800  * @param option option of interest
801  * @param choices NULL-terminated list of legal values
802  * @param value will be set to an entry in the legal list,
803  *        or NULL if option is not specified and no default given
804  * @return GNUNET_OK on success, GNUNET_SYSERR on error
805  */
806 int
807 GNUNET_CONFIGURATION_get_value_choice (const struct
808                                        GNUNET_CONFIGURATION_Handle *cfg,
809                                        const char *section,
810                                        const char *option,
811                                        const char **choices,
812                                        const char **value)
813 {
814   struct ConfigEntry *e;
815   int i;
816
817   e = findEntry (cfg, section, option);
818   if (e == NULL)
819     return GNUNET_SYSERR;
820   i = 0;
821   while (choices[i] != NULL)
822     {
823       if (0 == strcasecmp (choices[i], e->val))
824         break;
825       i++;
826     }
827   if (choices[i] == NULL)
828     {
829       LOG (GNUNET_ERROR_TYPE_ERROR,
830            _("Configuration value '%s' for '%s'"
831              " in section '%s' is not in set of legal choices\n"), e->val,
832            option, section);
833       return GNUNET_SYSERR;
834     }
835   *value = choices[i];
836   return GNUNET_OK;
837 }
838
839
840 /**
841  * Test if we have a value for a particular option
842  * @param cfg configuration to inspect
843  * @param section section of interest
844  * @param option option of interest
845  * @return GNUNET_YES if so, GNUNET_NO if not.
846  */
847 int
848 GNUNET_CONFIGURATION_have_value (const struct GNUNET_CONFIGURATION_Handle
849                                  *cfg, const char *section,
850                                  const char *option)
851 {
852   struct ConfigEntry *e;
853
854   if ((NULL == (e = findEntry (cfg, section, option))) || (e->val == NULL))
855     return GNUNET_NO;
856   return GNUNET_YES;
857 }
858
859
860 /**
861  * Expand an expression of the form "$FOO/BAR" to "DIRECTORY/BAR"
862  * where either in the "PATHS" section or the environtment
863  * "FOO" is set to "DIRECTORY".
864  *
865  * @param cfg configuration to use for path expansion
866  * @param orig string to $-expand (will be freed!)
867  * @return $-expanded string
868  */
869 char *
870 GNUNET_CONFIGURATION_expand_dollar (const struct GNUNET_CONFIGURATION_Handle
871                                     *cfg, char *orig)
872 {
873   int i;
874   char *prefix;
875   char *result;
876   const char *post;
877   const char *env;
878
879   if (orig[0] != '$')
880     return orig;
881   i = 0;
882   while ((orig[i] != '/') && (orig[i] != '\\') && (orig[i] != '\0'))
883     i++;
884   if (orig[i] == '\0')
885     {
886       post = "";
887     }
888   else
889     {
890       orig[i] = '\0';
891       post = &orig[i + 1];
892     }
893   if (GNUNET_OK !=
894       GNUNET_CONFIGURATION_get_value_filename (cfg, "PATHS", &orig[1],
895                                                &prefix))
896     {
897       if (NULL == (env = getenv (&orig[1])))
898         {
899           orig[i] = DIR_SEPARATOR;
900           return orig;
901         }
902       prefix = GNUNET_strdup (env);
903     }
904   result = GNUNET_malloc (strlen (prefix) + strlen (post) + 2);
905   strcpy (result, prefix);
906   if ((strlen (prefix) == 0) ||
907       ((prefix[strlen (prefix) - 1] != DIR_SEPARATOR) && (strlen (post) > 0)))
908     strcat (result, DIR_SEPARATOR_STR);
909   strcat (result, post);
910   GNUNET_free (prefix);
911   GNUNET_free (orig);
912   return result;
913 }
914
915
916 /**
917  * Get a configuration value that should be a string.
918  *
919  * @param cfg configuration to inspect
920  * @param section section of interest
921  * @param option option of interest
922  * @param value will be set to a freshly allocated configuration
923  *        value, or NULL if option is not specified
924  * @return GNUNET_OK on success, GNUNET_SYSERR on error
925  */
926 int
927 GNUNET_CONFIGURATION_get_value_filename (const struct
928                                          GNUNET_CONFIGURATION_Handle *cfg,
929                                          const char *section,
930                                          const char *option, char **value)
931 {
932   char *tmp;
933
934   if (GNUNET_OK !=
935       GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &tmp))
936     {
937       *value = NULL;
938       return GNUNET_SYSERR;
939     }
940   tmp = GNUNET_CONFIGURATION_expand_dollar (cfg, tmp);
941   *value = GNUNET_STRINGS_filename_expand (tmp);
942   GNUNET_free (tmp);
943   if (*value == NULL)
944     return GNUNET_SYSERR;
945   return GNUNET_OK;
946 }
947
948
949 /**
950  * Get a configuration value that should be in a set of
951  * "GNUNET_YES" or "GNUNET_NO".
952  *
953  * @param cfg configuration to inspect
954  * @param section section of interest
955  * @param option option of interest
956  * @return GNUNET_YES, GNUNET_NO or GNUNET_SYSERR
957  */
958 int
959 GNUNET_CONFIGURATION_get_value_yesno (const struct GNUNET_CONFIGURATION_Handle
960                                       *cfg, const char *section,
961                                       const char *option)
962 {
963   static const char *yesno[] = { "YES", "NO", NULL };
964   const char *val;
965   int ret;
966
967   ret =
968     GNUNET_CONFIGURATION_get_value_choice (cfg, section, option, yesno, &val);
969   if (ret == GNUNET_SYSERR)
970     return ret;
971   if (val == yesno[0])
972     return GNUNET_YES;
973   return GNUNET_NO;
974 }
975
976
977 /**
978  * Iterate over the set of filenames stored in a configuration value.
979  *
980  * @param cfg configuration to inspect
981  * @param section section of interest
982  * @param option option of interest
983  * @param cb function to call on each filename
984  * @param cb_cls closure for cb
985  * @return number of filenames iterated over, -1 on error
986  */
987 int
988 GNUNET_CONFIGURATION_iterate_value_filenames (const struct
989                                               GNUNET_CONFIGURATION_Handle
990                                               *cfg, const char *section,
991                                               const char *option,
992                                               GNUNET_FileNameCallback cb,
993                                               void *cb_cls)
994 {
995   char *list;
996   char *pos;
997   char *end;
998   char old;
999   int ret;
1000
1001   if (GNUNET_OK !=
1002       GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &list))
1003     return 0;
1004   GNUNET_assert (list != NULL);
1005   ret = 0;
1006   pos = list;
1007   while (1)
1008     {
1009       while (pos[0] == ' ')
1010         pos++;
1011       if (strlen (pos) == 0)
1012         break;
1013       end = pos + 1;
1014       while ((end[0] != ' ') && (end[0] != '\0'))
1015         {
1016           if (end[0] == '\\')
1017             {
1018               switch (end[1])
1019                 {
1020                 case '\\':
1021                 case ' ':
1022                   memmove (end, &end[1], strlen (&end[1]) + 1);
1023                 case '\0':
1024                   /* illegal, but just keep it */
1025                   break;
1026                 default:
1027                   /* illegal, but just ignore that there was a '/' */
1028                   break;
1029                 }
1030             }
1031           end++;
1032         }
1033       old = end[0];
1034       end[0] = '\0';
1035       if (strlen (pos) > 0)
1036         {
1037           ret++;
1038           if ((cb != NULL) && (GNUNET_OK != cb (cb_cls, pos)))
1039             {
1040               ret = GNUNET_SYSERR;
1041               break;
1042             }
1043         }
1044       if (old == '\0')
1045         break;
1046       pos = end + 1;
1047     }
1048   GNUNET_free (list);
1049   return ret;
1050 }
1051
1052
1053 /**
1054  * FIXME.
1055  *
1056  * @param value FIXME
1057  * @return FIXME
1058  */
1059 static char *
1060 escape_name (const char *value)
1061 {
1062   char *escaped;
1063   const char *rpos;
1064   char *wpos;
1065
1066   escaped = GNUNET_malloc (strlen (value) * 2 + 1);
1067   memset (escaped, 0, strlen (value) * 2 + 1);
1068   rpos = value;
1069   wpos = escaped;
1070   while (rpos[0] != '\0')
1071     {
1072       switch (rpos[0])
1073         {
1074         case '\\':
1075         case ' ':
1076           wpos[0] = '\\';
1077           wpos[1] = rpos[0];
1078           wpos += 2;
1079           break;
1080         default:
1081           wpos[0] = rpos[0];
1082           wpos++;
1083         }
1084       rpos++;
1085     }
1086   return escaped;
1087 }
1088
1089
1090 /**
1091  * FIXME.
1092  *
1093  * @param cls string we compare with (const char*)
1094  * @param fn filename we are currently looking at
1095  * @return GNUNET_OK if the names do not match, GNUNET_SYSERR if they do
1096  */
1097 static int
1098 test_match (void *cls, const char *fn)
1099 {
1100   const char *of = cls;
1101
1102   return (0 == strcmp (of, fn)) ? GNUNET_SYSERR : GNUNET_OK;
1103 }
1104
1105
1106 /**
1107  * Append a filename to a configuration value that
1108  * represents a list of filenames
1109  *
1110  * @param cfg configuration to update
1111  * @param section section of interest
1112  * @param option option of interest
1113  * @param value filename to append
1114  * @return GNUNET_OK on success,
1115  *         GNUNET_NO if the filename already in the list
1116  *         GNUNET_SYSERR on error
1117  */
1118 int
1119 GNUNET_CONFIGURATION_append_value_filename (struct GNUNET_CONFIGURATION_Handle
1120                                             *cfg, const char *section,
1121                                             const char *option,
1122                                             const char *value)
1123 {
1124   char *escaped;
1125   char *old;
1126   char *nw;
1127
1128   if (GNUNET_SYSERR ==
1129       GNUNET_CONFIGURATION_iterate_value_filenames (cfg, section, option,
1130                                                     &test_match,
1131                                                     (void *) value))
1132     return GNUNET_NO;           /* already exists */
1133   if (GNUNET_OK !=
1134       GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &old))
1135     old = GNUNET_strdup ("");
1136   escaped = escape_name (value);
1137   nw = GNUNET_malloc (strlen (old) + strlen (escaped) + 2);
1138   strcpy (nw, old);
1139   if (strlen (old) > 0)
1140     strcat (nw, " ");
1141   strcat (nw, escaped);
1142   GNUNET_CONFIGURATION_set_value_string (cfg, section, option, nw);
1143   GNUNET_free (old);
1144   GNUNET_free (nw);
1145   GNUNET_free (escaped);
1146   return GNUNET_OK;
1147 }
1148
1149
1150 /**
1151  * Remove a filename from a configuration value that
1152  * represents a list of filenames
1153  *
1154  * @param cfg configuration to update
1155  * @param section section of interest
1156  * @param option option of interest
1157  * @param value filename to remove
1158  * @return GNUNET_OK on success,
1159  *         GNUNET_NO if the filename is not in the list,
1160  *         GNUNET_SYSERR on error
1161  */
1162 int
1163 GNUNET_CONFIGURATION_remove_value_filename (struct GNUNET_CONFIGURATION_Handle
1164                                             *cfg, const char *section,
1165                                             const char *option,
1166                                             const char *value)
1167 {
1168   char *list;
1169   char *pos;
1170   char *end;
1171   char *match;
1172   char old;
1173
1174   if (GNUNET_OK !=
1175       GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &list))
1176     return GNUNET_NO;
1177   match = escape_name (value);
1178   pos = list;
1179   while (1)
1180     {
1181       while (pos[0] == ' ')
1182         pos++;
1183       if (strlen (pos) == 0)
1184         break;
1185       end = pos + 1;
1186       while ((end[0] != ' ') && (end[0] != '\0'))
1187         {
1188           if (end[0] == '\\')
1189             {
1190               switch (end[1])
1191                 {
1192                 case '\\':
1193                 case ' ':
1194                   end++;
1195                   break;
1196                 case '\0':
1197                   /* illegal, but just keep it */
1198                   break;
1199                 default:
1200                   /* illegal, but just ignore that there was a '/' */
1201                   break;
1202                 }
1203             }
1204           end++;
1205         }
1206       old = end[0];
1207       end[0] = '\0';
1208       if (0 == strcmp (pos, match))
1209         {
1210           if (old != '\0')
1211             memmove (pos, &end[1], strlen (&end[1]) + 1);
1212           else
1213             {
1214               if (pos != list)
1215                 pos[-1] = '\0';
1216               else
1217                 pos[0] = '\0';
1218             }
1219           GNUNET_CONFIGURATION_set_value_string (cfg, section, option, list);
1220           GNUNET_free (list);
1221           GNUNET_free (match);
1222           return GNUNET_OK;
1223         }
1224       if (old == '\0')
1225         break;
1226       end[0] = old;
1227       pos = end + 1;
1228     }
1229   GNUNET_free (list);
1230   GNUNET_free (match);
1231   return GNUNET_NO;
1232 }
1233
1234
1235 /**
1236  * Wrapper around GNUNET_CONFIGURATION_parse.
1237  *
1238  * @param cls the cfg
1239  * @param filename file to parse
1240  * @return GNUNET_OK on success
1241  */
1242 static int
1243 parse_configuration_file (void *cls,
1244                           const char *filename)
1245 {
1246   struct GNUNET_CONFIGURATION_Handle *cfg = cls;
1247   int ret;
1248
1249   ret = GNUNET_CONFIGURATION_parse (cfg, filename);
1250   return ret;
1251 }
1252
1253
1254 /**
1255  * Load configuration (starts with defaults, then loads
1256  * system-specific configuration).
1257  *
1258  * @param cfg configuration to update
1259  * @param filename name of the configuration file, NULL to load defaults
1260  * @return GNUNET_OK on success, GNUNET_SYSERR on error
1261  */
1262 int
1263 GNUNET_CONFIGURATION_load (struct GNUNET_CONFIGURATION_Handle *cfg,
1264                            const char *filename)
1265 {
1266   char *baseconfig;
1267   char *ipath;
1268
1269   ipath = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR);
1270   if (ipath == NULL)
1271     return GNUNET_SYSERR;
1272   baseconfig = NULL;
1273   GNUNET_asprintf (&baseconfig, "%s%s", ipath, 
1274                    "config.d");
1275   GNUNET_free (ipath);
1276   if (GNUNET_SYSERR ==
1277       GNUNET_DISK_directory_scan (baseconfig,
1278                                   &parse_configuration_file,
1279                                   cfg))
1280   {
1281     GNUNET_free (baseconfig);
1282     return GNUNET_SYSERR; /* no configuration at all found */    
1283   }
1284   GNUNET_free (baseconfig);  
1285   if ( (filename != NULL) &&
1286        (GNUNET_OK != GNUNET_CONFIGURATION_parse (cfg, filename)) )
1287   {
1288     /* specified configuration not found */
1289     return GNUNET_SYSERR;
1290   }
1291   if (((GNUNET_YES !=
1292         GNUNET_CONFIGURATION_have_value (cfg, "PATHS", "DEFAULTCONFIG"))) &&
1293       (filename != NULL))
1294     GNUNET_CONFIGURATION_set_value_string (cfg, "PATHS", "DEFAULTCONFIG",
1295                                            filename);
1296   if ((GNUNET_YES ==
1297        GNUNET_CONFIGURATION_have_value (cfg, "TESTING", "WEAKRANDOM")) &&
1298       (GNUNET_YES ==
1299        GNUNET_CONFIGURATION_get_value_yesno (cfg, "TESTING", "WEAKRANDOM")))
1300     GNUNET_CRYPTO_random_disable_entropy_gathering ();
1301   return GNUNET_OK;
1302 }
1303
1304
1305
1306 /* end of configuration.c */