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