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