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