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