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