a269ed0361eada3470552b70089205cfa070c559
[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   if ((0 == strcasecmp (e->val, "infinity")) ||
735       (0 == strcasecmp (e->val, "forever")))
736     {
737       *time = GNUNET_TIME_UNIT_FOREVER_REL;
738       return GNUNET_OK;
739     }
740   if (1 != SSCANF (e->val, "%llu", &num))
741     return GNUNET_SYSERR;
742   time->rel_value = (uint64_t) num;
743   return GNUNET_OK;
744 }
745
746
747 /**
748  * Get a configuration value that should be a string.
749  *
750  * @param cfg configuration to inspect
751  * @param section section of interest
752  * @param option option of interest
753  * @param value will be set to a freshly allocated configuration
754  *        value, or NULL if option is not specified
755  * @return GNUNET_OK on success, GNUNET_SYSERR on error
756  */
757 int
758 GNUNET_CONFIGURATION_get_value_string (const struct
759                                        GNUNET_CONFIGURATION_Handle *cfg,
760                                        const char *section,
761                                        const char *option, char **value)
762 {
763   struct ConfigEntry *e;
764
765   e = findEntry (cfg, section, option);
766   if ((e == NULL) || (e->val == NULL))
767     {
768       *value = NULL;
769       return GNUNET_SYSERR;
770     }
771   *value = GNUNET_strdup (e->val);
772   return GNUNET_OK;
773 }
774
775
776 /**
777  * Get a configuration value that should be in a set of
778  * predefined strings
779  *
780  * @param cfg configuration to inspect
781  * @param section section of interest
782  * @param option option of interest
783  * @param choices NULL-terminated list of legal values
784  * @param value will be set to an entry in the legal list,
785  *        or NULL if option is not specified and no default given
786  * @return GNUNET_OK on success, GNUNET_SYSERR on error
787  */
788 int
789 GNUNET_CONFIGURATION_get_value_choice (const struct
790                                        GNUNET_CONFIGURATION_Handle *cfg,
791                                        const char *section,
792                                        const char *option,
793                                        const char **choices,
794                                        const char **value)
795 {
796   struct ConfigEntry *e;
797   int i;
798
799   e = findEntry (cfg, section, option);
800   if (e == NULL)
801     return GNUNET_SYSERR;
802   i = 0;
803   while (choices[i] != NULL)
804     {
805       if (0 == strcasecmp (choices[i], e->val))
806         break;
807       i++;
808     }
809   if (choices[i] == NULL)
810     {
811       LOG (GNUNET_ERROR_TYPE_ERROR,
812            _("Configuration value '%s' for '%s'"
813              " in section '%s' is not in set of legal choices\n"), e->val,
814            option, section);
815       return GNUNET_SYSERR;
816     }
817   *value = choices[i];
818   return GNUNET_OK;
819 }
820
821
822 /**
823  * Test if we have a value for a particular option
824  * @param cfg configuration to inspect
825  * @param section section of interest
826  * @param option option of interest
827  * @return GNUNET_YES if so, GNUNET_NO if not.
828  */
829 int
830 GNUNET_CONFIGURATION_have_value (const struct GNUNET_CONFIGURATION_Handle
831                                  *cfg, const char *section,
832                                  const char *option)
833 {
834   struct ConfigEntry *e;
835
836   if ((NULL == (e = findEntry (cfg, section, option))) || (e->val == NULL))
837     return GNUNET_NO;
838   return GNUNET_YES;
839 }
840
841
842 /**
843  * Expand an expression of the form "$FOO/BAR" to "DIRECTORY/BAR"
844  * where either in the "PATHS" section or the environtment
845  * "FOO" is set to "DIRECTORY".
846  *
847  * @param cfg configuration to use for path expansion
848  * @param orig string to $-expand (will be freed!)
849  * @return $-expanded string
850  */
851 char *
852 GNUNET_CONFIGURATION_expand_dollar (const struct GNUNET_CONFIGURATION_Handle
853                                     *cfg, char *orig)
854 {
855   int i;
856   char *prefix;
857   char *result;
858   const char *post;
859   const char *env;
860
861   if (orig[0] != '$')
862     return orig;
863   i = 0;
864   while ((orig[i] != '/') && (orig[i] != '\\') && (orig[i] != '\0'))
865     i++;
866   if (orig[i] == '\0')
867     {
868       post = "";
869     }
870   else
871     {
872       orig[i] = '\0';
873       post = &orig[i + 1];
874     }
875   if (GNUNET_OK !=
876       GNUNET_CONFIGURATION_get_value_filename (cfg, "PATHS", &orig[1],
877                                                &prefix))
878     {
879       if (NULL == (env = getenv (&orig[1])))
880         {
881           orig[i] = DIR_SEPARATOR;
882           return orig;
883         }
884       prefix = GNUNET_strdup (env);
885     }
886   result = GNUNET_malloc (strlen (prefix) + strlen (post) + 2);
887   strcpy (result, prefix);
888   if ((strlen (prefix) == 0) ||
889       ((prefix[strlen (prefix) - 1] != DIR_SEPARATOR) && (strlen (post) > 0)))
890     strcat (result, DIR_SEPARATOR_STR);
891   strcat (result, post);
892   GNUNET_free (prefix);
893   GNUNET_free (orig);
894   return result;
895 }
896
897
898 /**
899  * Get a configuration value that should be a string.
900  *
901  * @param cfg configuration to inspect
902  * @param section section of interest
903  * @param option option of interest
904  * @param value will be set to a freshly allocated configuration
905  *        value, or NULL if option is not specified
906  * @return GNUNET_OK on success, GNUNET_SYSERR on error
907  */
908 int
909 GNUNET_CONFIGURATION_get_value_filename (const struct
910                                          GNUNET_CONFIGURATION_Handle *cfg,
911                                          const char *section,
912                                          const char *option, char **value)
913 {
914   char *tmp;
915
916   if (GNUNET_OK !=
917       GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &tmp))
918     {
919       *value = NULL;
920       return GNUNET_SYSERR;
921     }
922   tmp = GNUNET_CONFIGURATION_expand_dollar (cfg, tmp);
923   *value = GNUNET_STRINGS_filename_expand (tmp);
924   GNUNET_free (tmp);
925   if (*value == NULL)
926     return GNUNET_SYSERR;
927   return GNUNET_OK;
928 }
929
930
931 /**
932  * Get a configuration value that should be in a set of
933  * "GNUNET_YES" or "GNUNET_NO".
934  *
935  * @param cfg configuration to inspect
936  * @param section section of interest
937  * @param option option of interest
938  * @return GNUNET_YES, GNUNET_NO or GNUNET_SYSERR
939  */
940 int
941 GNUNET_CONFIGURATION_get_value_yesno (const struct GNUNET_CONFIGURATION_Handle
942                                       *cfg, const char *section,
943                                       const char *option)
944 {
945   static const char *yesno[] = { "YES", "NO", NULL };
946   const char *val;
947   int ret;
948
949   ret =
950     GNUNET_CONFIGURATION_get_value_choice (cfg, section, option, yesno, &val);
951   if (ret == GNUNET_SYSERR)
952     return ret;
953   if (val == yesno[0])
954     return GNUNET_YES;
955   return GNUNET_NO;
956 }
957
958
959 /**
960  * Iterate over the set of filenames stored in a configuration value.
961  *
962  * @param cfg configuration to inspect
963  * @param section section of interest
964  * @param option option of interest
965  * @param cb function to call on each filename
966  * @param cb_cls closure for cb
967  * @return number of filenames iterated over, -1 on error
968  */
969 int
970 GNUNET_CONFIGURATION_iterate_value_filenames (const struct
971                                               GNUNET_CONFIGURATION_Handle
972                                               *cfg, const char *section,
973                                               const char *option,
974                                               GNUNET_FileNameCallback cb,
975                                               void *cb_cls)
976 {
977   char *list;
978   char *pos;
979   char *end;
980   char old;
981   int ret;
982
983   if (GNUNET_OK !=
984       GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &list))
985     return 0;
986   GNUNET_assert (list != NULL);
987   ret = 0;
988   pos = list;
989   while (1)
990     {
991       while (pos[0] == ' ')
992         pos++;
993       if (strlen (pos) == 0)
994         break;
995       end = pos + 1;
996       while ((end[0] != ' ') && (end[0] != '\0'))
997         {
998           if (end[0] == '\\')
999             {
1000               switch (end[1])
1001                 {
1002                 case '\\':
1003                 case ' ':
1004                   memmove (end, &end[1], strlen (&end[1]) + 1);
1005                 case '\0':
1006                   /* illegal, but just keep it */
1007                   break;
1008                 default:
1009                   /* illegal, but just ignore that there was a '/' */
1010                   break;
1011                 }
1012             }
1013           end++;
1014         }
1015       old = end[0];
1016       end[0] = '\0';
1017       if (strlen (pos) > 0)
1018         {
1019           ret++;
1020           if ((cb != NULL) && (GNUNET_OK != cb (cb_cls, pos)))
1021             {
1022               ret = GNUNET_SYSERR;
1023               break;
1024             }
1025         }
1026       if (old == '\0')
1027         break;
1028       pos = end + 1;
1029     }
1030   GNUNET_free (list);
1031   return ret;
1032 }
1033
1034
1035 /**
1036  * FIXME.
1037  *
1038  * @param value FIXME
1039  * @return FIXME
1040  */
1041 static char *
1042 escape_name (const char *value)
1043 {
1044   char *escaped;
1045   const char *rpos;
1046   char *wpos;
1047
1048   escaped = GNUNET_malloc (strlen (value) * 2 + 1);
1049   memset (escaped, 0, strlen (value) * 2 + 1);
1050   rpos = value;
1051   wpos = escaped;
1052   while (rpos[0] != '\0')
1053     {
1054       switch (rpos[0])
1055         {
1056         case '\\':
1057         case ' ':
1058           wpos[0] = '\\';
1059           wpos[1] = rpos[0];
1060           wpos += 2;
1061           break;
1062         default:
1063           wpos[0] = rpos[0];
1064           wpos++;
1065         }
1066       rpos++;
1067     }
1068   return escaped;
1069 }
1070
1071
1072 /**
1073  * FIXME.
1074  *
1075  * @param cls string we compare with (const char*)
1076  * @param fn filename we are currently looking at
1077  * @return GNUNET_OK if the names do not match, GNUNET_SYSERR if they do
1078  */
1079 static int
1080 test_match (void *cls, const char *fn)
1081 {
1082   const char *of = cls;
1083
1084   return (0 == strcmp (of, fn)) ? GNUNET_SYSERR : GNUNET_OK;
1085 }
1086
1087
1088 /**
1089  * Append a filename to a configuration value that
1090  * represents a list of filenames
1091  *
1092  * @param cfg configuration to update
1093  * @param section section of interest
1094  * @param option option of interest
1095  * @param value filename to append
1096  * @return GNUNET_OK on success,
1097  *         GNUNET_NO if the filename already in the list
1098  *         GNUNET_SYSERR on error
1099  */
1100 int
1101 GNUNET_CONFIGURATION_append_value_filename (struct GNUNET_CONFIGURATION_Handle
1102                                             *cfg, const char *section,
1103                                             const char *option,
1104                                             const char *value)
1105 {
1106   char *escaped;
1107   char *old;
1108   char *nw;
1109
1110   if (GNUNET_SYSERR ==
1111       GNUNET_CONFIGURATION_iterate_value_filenames (cfg, section, option,
1112                                                     &test_match,
1113                                                     (void *) value))
1114     return GNUNET_NO;           /* already exists */
1115   if (GNUNET_OK !=
1116       GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &old))
1117     old = GNUNET_strdup ("");
1118   escaped = escape_name (value);
1119   nw = GNUNET_malloc (strlen (old) + strlen (escaped) + 2);
1120   strcpy (nw, old);
1121   if (strlen (old) > 0)
1122     strcat (nw, " ");
1123   strcat (nw, escaped);
1124   GNUNET_CONFIGURATION_set_value_string (cfg, section, option, nw);
1125   GNUNET_free (old);
1126   GNUNET_free (nw);
1127   GNUNET_free (escaped);
1128   return GNUNET_OK;
1129 }
1130
1131
1132 /**
1133  * Remove a filename from a configuration value that
1134  * represents a list of filenames
1135  *
1136  * @param cfg configuration to update
1137  * @param section section of interest
1138  * @param option option of interest
1139  * @param value filename to remove
1140  * @return GNUNET_OK on success,
1141  *         GNUNET_NO if the filename is not in the list,
1142  *         GNUNET_SYSERR on error
1143  */
1144 int
1145 GNUNET_CONFIGURATION_remove_value_filename (struct GNUNET_CONFIGURATION_Handle
1146                                             *cfg, const char *section,
1147                                             const char *option,
1148                                             const char *value)
1149 {
1150   char *list;
1151   char *pos;
1152   char *end;
1153   char *match;
1154   char old;
1155
1156   if (GNUNET_OK !=
1157       GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &list))
1158     return GNUNET_NO;
1159   match = escape_name (value);
1160   pos = list;
1161   while (1)
1162     {
1163       while (pos[0] == ' ')
1164         pos++;
1165       if (strlen (pos) == 0)
1166         break;
1167       end = pos + 1;
1168       while ((end[0] != ' ') && (end[0] != '\0'))
1169         {
1170           if (end[0] == '\\')
1171             {
1172               switch (end[1])
1173                 {
1174                 case '\\':
1175                 case ' ':
1176                   end++;
1177                   break;
1178                 case '\0':
1179                   /* illegal, but just keep it */
1180                   break;
1181                 default:
1182                   /* illegal, but just ignore that there was a '/' */
1183                   break;
1184                 }
1185             }
1186           end++;
1187         }
1188       old = end[0];
1189       end[0] = '\0';
1190       if (0 == strcmp (pos, match))
1191         {
1192           if (old != '\0')
1193             memmove (pos, &end[1], strlen (&end[1]) + 1);
1194           else
1195             {
1196               if (pos != list)
1197                 pos[-1] = '\0';
1198               else
1199                 pos[0] = '\0';
1200             }
1201           GNUNET_CONFIGURATION_set_value_string (cfg, section, option, list);
1202           GNUNET_free (list);
1203           GNUNET_free (match);
1204           return GNUNET_OK;
1205         }
1206       if (old == '\0')
1207         break;
1208       end[0] = old;
1209       pos = end + 1;
1210     }
1211   GNUNET_free (list);
1212   GNUNET_free (match);
1213   return GNUNET_NO;
1214 }
1215
1216
1217 /**
1218  * Wrapper around GNUNET_CONFIGURATION_parse.
1219  *
1220  * @param cls the cfg
1221  * @param filename file to parse
1222  * @return GNUNET_OK on success
1223  */
1224 static int
1225 parse_configuration_file (void *cls,
1226                           const char *filename)
1227 {
1228   struct GNUNET_CONFIGURATION_Handle *cfg = cls;
1229   int ret;
1230
1231   ret = GNUNET_CONFIGURATION_parse (cfg, filename);
1232   return ret;
1233 }
1234
1235
1236 /**
1237  * Load configuration (starts with defaults, then loads
1238  * system-specific configuration).
1239  *
1240  * @param cfg configuration to update
1241  * @param filename name of the configuration file, NULL to load defaults
1242  * @return GNUNET_OK on success, GNUNET_SYSERR on error
1243  */
1244 int
1245 GNUNET_CONFIGURATION_load (struct GNUNET_CONFIGURATION_Handle *cfg,
1246                            const char *filename)
1247 {
1248   char *baseconfig;
1249   char *ipath;
1250
1251   ipath = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR);
1252   if (ipath == NULL)
1253     return GNUNET_SYSERR;
1254   baseconfig = NULL;
1255   GNUNET_asprintf (&baseconfig, "%s%s", ipath, 
1256                    "config.d");
1257   GNUNET_free (ipath);
1258   if (GNUNET_SYSERR ==
1259       GNUNET_DISK_directory_scan (baseconfig,
1260                                   &parse_configuration_file,
1261                                   cfg))
1262   {
1263     GNUNET_free (baseconfig);
1264     return GNUNET_SYSERR; /* no configuration at all found */    
1265   }
1266   GNUNET_free (baseconfig);  
1267   if ( (filename != NULL) &&
1268        (GNUNET_OK != GNUNET_CONFIGURATION_parse (cfg, filename)) )
1269   {
1270     /* specified configuration not found */
1271     return GNUNET_SYSERR;
1272   }
1273   if (((GNUNET_YES !=
1274         GNUNET_CONFIGURATION_have_value (cfg, "PATHS", "DEFAULTCONFIG"))) &&
1275       (filename != NULL))
1276     GNUNET_CONFIGURATION_set_value_string (cfg, "PATHS", "DEFAULTCONFIG",
1277                                            filename);
1278   if ((GNUNET_YES ==
1279        GNUNET_CONFIGURATION_have_value (cfg, "TESTING", "WEAKRANDOM")) &&
1280       (GNUNET_YES ==
1281        GNUNET_CONFIGURATION_get_value_yesno (cfg, "TESTING", "WEAKRANDOM")))
1282     GNUNET_CRYPTO_random_disable_entropy_gathering ();
1283   return GNUNET_OK;
1284 }
1285
1286
1287
1288 /* end of configuration.c */