-check return value
[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 (const struct GNUNET_CONFIGURATION_Handle *cfg,
351                                 size_t *size)
352 {
353   struct ConfigSection *sec;
354   struct ConfigEntry *ent;
355   char *mem;
356   char *cbuf;
357   char *val;
358   char *pos;
359   int len;
360   size_t m_size;
361   size_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     GNUNET_assert (0 < len);
403     memcpy (mem + c_size, cbuf, len);
404     c_size += len;
405     GNUNET_free (cbuf);
406     ent = sec->entries;
407     while (NULL != ent)
408     {
409       if (NULL != ent->val)
410       {
411         val = GNUNET_malloc (strlen (ent->val) * 2 + 1);
412         strcpy (val, ent->val);
413         while (NULL != (pos = strstr (val, "\n")))
414         {
415           memmove (&pos[2], &pos[1], strlen (&pos[1]));
416           pos[0] = '\\';
417           pos[1] = 'n';
418         }
419         len = GNUNET_asprintf (&cbuf, "%s = %s\n", ent->key, val);
420         GNUNET_free (val);
421         memcpy (mem + c_size, cbuf, len);
422         c_size += len;
423         GNUNET_free (cbuf);     
424       }
425       ent = ent->next;
426     }
427     memcpy (mem + c_size, "\n", 1);
428     c_size ++;
429     sec = sec->next;
430   }
431   GNUNET_assert (c_size == m_size);
432   *size = c_size;
433   return mem;
434 }
435
436
437 /**
438  * Write configuration file.
439  *
440  * @param cfg configuration to write
441  * @param filename where to write the configuration
442  * @return GNUNET_OK on success, GNUNET_SYSERR on error
443  */
444 int
445 GNUNET_CONFIGURATION_write (struct GNUNET_CONFIGURATION_Handle *cfg,
446                             const char *filename)
447 {
448   char *fn;
449   char *cfg_buf;
450   size_t size;
451
452   fn = GNUNET_STRINGS_filename_expand (filename);
453   if (fn == NULL)
454     return GNUNET_SYSERR;
455   if (GNUNET_OK != GNUNET_DISK_directory_create_for_file (fn))
456   {
457     GNUNET_free (fn);
458     return GNUNET_SYSERR;
459   }
460   cfg_buf = GNUNET_CONFIGURATION_serialize (cfg, &size);
461   if (size != GNUNET_DISK_fn_write (fn, cfg_buf, size,
462                                     GNUNET_DISK_PERM_USER_READ 
463                                     | GNUNET_DISK_PERM_USER_WRITE
464                                     | GNUNET_DISK_PERM_GROUP_READ 
465                                     | GNUNET_DISK_PERM_GROUP_WRITE))
466   {
467     GNUNET_free (fn);
468     GNUNET_free (cfg_buf);
469     LOG (GNUNET_ERROR_TYPE_WARNING,
470          "Writing configration to file: %s failed\n", filename);
471     cfg->dirty = GNUNET_SYSERR; /* last write failed */
472     return GNUNET_SYSERR;
473   }
474   GNUNET_free (fn);
475   GNUNET_free (cfg_buf);
476   cfg->dirty = GNUNET_NO;       /* last write succeeded */
477   return GNUNET_OK;
478 }
479
480
481 /**
482  * Iterate over all options in the configuration.
483  *
484  * @param cfg configuration to inspect
485  * @param iter function to call on each option
486  * @param iter_cls closure for iter
487  */
488 void
489 GNUNET_CONFIGURATION_iterate (const struct GNUNET_CONFIGURATION_Handle *cfg,
490                               GNUNET_CONFIGURATION_Iterator iter,
491                               void *iter_cls)
492 {
493   struct ConfigSection *spos;
494   struct ConfigEntry *epos;
495
496   spos = cfg->sections;
497   while (spos != NULL)
498   {
499     epos = spos->entries;
500     while (epos != NULL)
501     {
502       iter (iter_cls, spos->name, epos->key, epos->val);
503       epos = epos->next;
504     }
505     spos = spos->next;
506   }
507 }
508
509
510 /**
511  * Iterate over values of a section in the configuration.
512  *
513  * @param cfg configuration to inspect
514  * @param section the section
515  * @param iter function to call on each option
516  * @param iter_cls closure for iter
517  */
518 void
519 GNUNET_CONFIGURATION_iterate_section_values (const struct
520                                              GNUNET_CONFIGURATION_Handle *cfg,
521                                              const char *section,
522                                              GNUNET_CONFIGURATION_Iterator iter,
523                                              void *iter_cls)
524 {
525   struct ConfigSection *spos;
526   struct ConfigEntry *epos;
527
528   spos = cfg->sections;
529   while ((spos != NULL) && (0 != strcasecmp (spos->name, section)))
530     spos = spos->next;
531
532   if (spos == NULL)
533     return;
534
535   epos = spos->entries;
536   while (epos != NULL)
537   {
538     iter (iter_cls, spos->name, epos->key, epos->val);
539     epos = epos->next;
540   }
541 }
542
543
544 /**
545  * Iterate over all sections in the configuration.
546  *
547  * @param cfg configuration to inspect
548  * @param iter function to call on each section
549  * @param iter_cls closure for iter
550  */
551 void
552 GNUNET_CONFIGURATION_iterate_sections (const struct GNUNET_CONFIGURATION_Handle
553                                        *cfg,
554                                        GNUNET_CONFIGURATION_Section_Iterator
555                                        iter, void *iter_cls)
556 {
557   struct ConfigSection *spos;
558   struct ConfigSection *next;
559
560   next = cfg->sections;
561   while (next != NULL)
562   {
563     spos = next;
564     next = spos->next;
565     iter (iter_cls, spos->name);
566   }
567 }
568
569 /**
570  * Remove the given section and all options in it.
571  *
572  * @param cfg configuration to inspect
573  * @param section name of the section to remove
574  */
575 void
576 GNUNET_CONFIGURATION_remove_section (struct GNUNET_CONFIGURATION_Handle *cfg,
577                                      const char *section)
578 {
579   struct ConfigSection *spos;
580   struct ConfigSection *prev;
581   struct ConfigEntry *ent;
582
583   prev = NULL;
584   spos = cfg->sections;
585   while (spos != NULL)
586   {
587     if (0 == strcasecmp (section, spos->name))
588     {
589       if (prev == NULL)
590         cfg->sections = spos->next;
591       else
592         prev->next = spos->next;
593       while (NULL != (ent = spos->entries))
594       {
595         spos->entries = ent->next;
596         GNUNET_free (ent->key);
597         GNUNET_free_non_null (ent->val);
598         GNUNET_free (ent);
599         cfg->dirty = GNUNET_YES;
600       }
601       GNUNET_free (spos->name);
602       GNUNET_free (spos);
603       return;
604     }
605     prev = spos;
606     spos = spos->next;
607   }
608 }
609
610
611 /**
612  * Copy a configuration value to the given target configuration.
613  * Overwrites existing entries.
614  *
615  * @param cls the destination configuration (struct GNUNET_CONFIGURATION_Handle*)
616  * @param section section for the value
617  * @param option option name of the value
618  * @param value value to copy
619  */
620 static void
621 copy_entry (void *cls, const char *section, const char *option,
622             const char *value)
623 {
624   struct GNUNET_CONFIGURATION_Handle *dst = cls;
625
626   GNUNET_CONFIGURATION_set_value_string (dst, section, option, value);
627 }
628
629
630 /**
631  * Duplicate an existing configuration object.
632  *
633  * @param cfg configuration to duplicate
634  * @return duplicate configuration
635  */
636 struct GNUNET_CONFIGURATION_Handle *
637 GNUNET_CONFIGURATION_dup (const struct GNUNET_CONFIGURATION_Handle *cfg)
638 {
639   struct GNUNET_CONFIGURATION_Handle *ret;
640
641   ret = GNUNET_CONFIGURATION_create ();
642   GNUNET_CONFIGURATION_iterate (cfg, &copy_entry, ret);
643   return ret;
644 }
645
646
647 /**
648  * FIXME.
649  *
650  * @param cfg FIXME
651  * @param section FIXME
652  * @return matching entry, NULL if not found
653  */
654 static struct ConfigSection *
655 findSection (const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section)
656 {
657   struct ConfigSection *pos;
658
659   pos = cfg->sections;
660   while ((pos != NULL) && (0 != strcasecmp (section, pos->name)))
661     pos = pos->next;
662   return pos;
663 }
664
665
666 /**
667  * Find an entry from a configuration.
668  *
669  * @param cfg handle to the configuration
670  * @param section section the option is in
671  * @param key the option
672  * @return matching entry, NULL if not found
673  */
674 static struct ConfigEntry *
675 findEntry (const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section,
676            const char *key)
677 {
678   struct ConfigSection *sec;
679   struct ConfigEntry *pos;
680
681   sec = findSection (cfg, section);
682   if (sec == NULL)
683     return NULL;
684   pos = sec->entries;
685   while ((pos != NULL) && (0 != strcasecmp (key, pos->key)))
686     pos = pos->next;
687   return pos;
688 }
689
690
691 /**
692  * A callback function, compares entries from two configurations
693  * (default against a new configuration) and write the diffs in a
694  * diff-configuration object (the callback object).
695  *
696  * @param cls the diff configuration (struct DiffHandle*)
697  * @param section section for the value (of the default conf.)
698  * @param option option name of the value (of the default conf.)
699  * @param value value to copy (of the default conf.)
700  */
701 static void
702 compareEntries (void *cls, const char *section, const char *option,
703                 const char *value)
704 {
705   struct DiffHandle *dh = cls;
706   struct ConfigEntry *entNew;
707
708   entNew = findEntry (dh->cfgDefault, section, option);
709   if ((entNew != NULL) && (strcmp (entNew->val, value) == 0))
710     return;
711   GNUNET_CONFIGURATION_set_value_string (dh->cfgDiff, section, option, value);
712 }
713
714
715 /**
716  * Write only configuration entries that have been changed to configuration file
717  * @param cfgDefault default configuration
718  * @param cfgNew new configuration
719  * @param filename where to write the configuration diff between default and new
720  * @return GNUNET_OK on success, GNUNET_SYSERR on error
721  */
722 int
723 GNUNET_CONFIGURATION_write_diffs (const struct GNUNET_CONFIGURATION_Handle
724                                   *cfgDefault,
725                                   const struct GNUNET_CONFIGURATION_Handle
726                                   *cfgNew, const char *filename)
727 {
728   int ret;
729   struct DiffHandle diffHandle;
730
731   diffHandle.cfgDiff = GNUNET_CONFIGURATION_create ();
732   diffHandle.cfgDefault = cfgDefault;
733   GNUNET_CONFIGURATION_iterate (cfgNew, compareEntries, &diffHandle);
734   ret = GNUNET_CONFIGURATION_write (diffHandle.cfgDiff, filename);
735   GNUNET_CONFIGURATION_destroy (diffHandle.cfgDiff);
736   return ret;
737 }
738
739
740 /**
741  * Set a configuration value that should be a string.
742  *
743  * @param cfg configuration to update
744  * @param section section of interest
745  * @param option option of interest
746  * @param value value to set
747  */
748 void
749 GNUNET_CONFIGURATION_set_value_string (struct GNUNET_CONFIGURATION_Handle *cfg,
750                                        const char *section, const char *option,
751                                        const char *value)
752 {
753   struct ConfigSection *sec;
754   struct ConfigEntry *e;
755   char *nv;
756
757   e = findEntry (cfg, section, option);
758   if (e != NULL)
759   {
760     nv = GNUNET_strdup (value);
761     GNUNET_free_non_null (e->val);
762     e->val = nv;
763     return;
764   }
765   sec = findSection (cfg, section);
766   if (sec == NULL)
767   {
768     sec = GNUNET_malloc (sizeof (struct ConfigSection));
769     sec->name = GNUNET_strdup (section);
770     sec->next = cfg->sections;
771     cfg->sections = sec;
772   }
773   e = GNUNET_malloc (sizeof (struct ConfigEntry));
774   e->key = GNUNET_strdup (option);
775   e->val = GNUNET_strdup (value);
776   e->next = sec->entries;
777   sec->entries = e;
778 }
779
780
781 /**
782  * Set a configuration value that should be a number.
783  *
784  * @param cfg configuration to update
785  * @param section section of interest
786  * @param option option of interest
787  * @param number value to set
788  */
789 void
790 GNUNET_CONFIGURATION_set_value_number (struct GNUNET_CONFIGURATION_Handle *cfg,
791                                        const char *section, const char *option,
792                                        unsigned long long number)
793 {
794   char s[64];
795
796   GNUNET_snprintf (s, 64, "%llu", number);
797   GNUNET_CONFIGURATION_set_value_string (cfg, section, option, s);
798 }
799
800
801 /**
802  * Get a configuration value that should be a number.
803  *
804  * @param cfg configuration to inspect
805  * @param section section of interest
806  * @param option option of interest
807  * @param number where to store the numeric value of the option
808  * @return GNUNET_OK on success, GNUNET_SYSERR on error
809  */
810 int
811 GNUNET_CONFIGURATION_get_value_number (const struct GNUNET_CONFIGURATION_Handle
812                                        *cfg, const char *section,
813                                        const char *option,
814                                        unsigned long long *number)
815 {
816   struct ConfigEntry *e;
817
818   e = findEntry (cfg, section, option);
819   if (e == NULL)
820     return GNUNET_SYSERR;
821   if (1 != SSCANF (e->val, "%llu", number))
822     return GNUNET_SYSERR;
823   return GNUNET_OK;
824 }
825
826
827 /**
828  * Get a configuration value that should be a relative time.
829  *
830  * @param cfg configuration to inspect
831  * @param section section of interest
832  * @param option option of interest
833  * @param time set to the time value stored in the configuration
834  * @return GNUNET_OK on success, GNUNET_SYSERR on error
835  */
836 int
837 GNUNET_CONFIGURATION_get_value_time (const struct GNUNET_CONFIGURATION_Handle
838                                      *cfg, const char *section,
839                                      const char *option,
840                                      struct GNUNET_TIME_Relative *time)
841 {
842   struct ConfigEntry *e;
843
844   e = findEntry (cfg, section, option);
845   if (e == NULL)
846     return GNUNET_SYSERR;
847
848   return GNUNET_STRINGS_fancy_time_to_relative (e->val, time);
849 }
850
851
852 /**
853  * Get a configuration value that should be a size in bytes.
854  *
855  * @param cfg configuration to inspect
856  * @param section section of interest
857  * @param option option of interest
858  * @param size set to the size in bytes as stored in the configuration
859  * @return GNUNET_OK on success, GNUNET_SYSERR on error
860  */
861 int
862 GNUNET_CONFIGURATION_get_value_size (const struct GNUNET_CONFIGURATION_Handle
863                                      *cfg, const char *section,
864                                      const char *option,
865                                      unsigned long long *size)
866 {
867   struct ConfigEntry *e;
868
869   e = findEntry (cfg, section, option);
870   if (e == NULL)
871     return GNUNET_SYSERR;
872   return GNUNET_STRINGS_fancy_size_to_bytes (e->val, size);
873 }
874
875
876 /**
877  * Get a configuration value that should be a string.
878  *
879  * @param cfg configuration to inspect
880  * @param section section of interest
881  * @param option option of interest
882  * @param value will be set to a freshly allocated configuration
883  *        value, or NULL if option is not specified
884  * @return GNUNET_OK on success, GNUNET_SYSERR on error
885  */
886 int
887 GNUNET_CONFIGURATION_get_value_string (const struct GNUNET_CONFIGURATION_Handle
888                                        *cfg, const char *section,
889                                        const char *option, char **value)
890 {
891   struct ConfigEntry *e;
892
893   e = findEntry (cfg, section, option);
894   if ((e == NULL) || (e->val == NULL))
895   {
896     *value = NULL;
897     return GNUNET_SYSERR;
898   }
899   *value = GNUNET_strdup (e->val);
900   return GNUNET_OK;
901 }
902
903
904 /**
905  * Get a configuration value that should be in a set of
906  * predefined strings
907  *
908  * @param cfg configuration to inspect
909  * @param section section of interest
910  * @param option option of interest
911  * @param choices NULL-terminated list of legal values
912  * @param value will be set to an entry in the legal list,
913  *        or NULL if option is not specified and no default given
914  * @return GNUNET_OK on success, GNUNET_SYSERR on error
915  */
916 int
917 GNUNET_CONFIGURATION_get_value_choice (const struct GNUNET_CONFIGURATION_Handle
918                                        *cfg, const char *section,
919                                        const char *option, const char **choices,
920                                        const char **value)
921 {
922   struct ConfigEntry *e;
923   int i;
924
925   e = findEntry (cfg, section, option);
926   if (e == NULL)
927     return GNUNET_SYSERR;
928   i = 0;
929   while (choices[i] != NULL)
930   {
931     if (0 == strcasecmp (choices[i], e->val))
932       break;
933     i++;
934   }
935   if (choices[i] == NULL)
936   {
937     LOG (GNUNET_ERROR_TYPE_ERROR,
938          _("Configuration value '%s' for '%s'"
939            " in section '%s' is not in set of legal choices\n"), e->val, option,
940          section);
941     return GNUNET_SYSERR;
942   }
943   *value = choices[i];
944   return GNUNET_OK;
945 }
946
947
948 /**
949  * Test if we have a value for a particular option
950  * @param cfg configuration to inspect
951  * @param section section of interest
952  * @param option option of interest
953  * @return GNUNET_YES if so, GNUNET_NO if not.
954  */
955 int
956 GNUNET_CONFIGURATION_have_value (const struct GNUNET_CONFIGURATION_Handle *cfg,
957                                  const char *section, const char *option)
958 {
959   struct ConfigEntry *e;
960
961   if ((NULL == (e = findEntry (cfg, section, option))) || (e->val == NULL))
962     return GNUNET_NO;
963   return GNUNET_YES;
964 }
965
966
967 /**
968  * Expand an expression of the form "$FOO/BAR" to "DIRECTORY/BAR"
969  * where either in the "PATHS" section or the environtment
970  * "FOO" is set to "DIRECTORY".
971  *
972  * @param cfg configuration to use for path expansion
973  * @param orig string to $-expand (will be freed!)
974  * @return $-expanded string
975  */
976 char *
977 GNUNET_CONFIGURATION_expand_dollar (const struct GNUNET_CONFIGURATION_Handle
978                                     *cfg, char *orig)
979 {
980   int i;
981   char *prefix;
982   char *result;
983   const char *post;
984   const char *env;
985
986   if (orig[0] != '$')
987     return orig;
988   i = 0;
989   while ((orig[i] != '/') && (orig[i] != '\\') && (orig[i] != '\0'))
990     i++;
991   if (orig[i] == '\0')
992   {
993     post = "";
994   }
995   else
996   {
997     orig[i] = '\0';
998     post = &orig[i + 1];
999   }
1000   if (GNUNET_OK !=
1001       GNUNET_CONFIGURATION_get_value_filename (cfg, "PATHS", &orig[1], &prefix))
1002   {
1003     if (NULL == (env = getenv (&orig[1])))
1004     {
1005       orig[i] = DIR_SEPARATOR;
1006       return orig;
1007     }
1008     prefix = GNUNET_strdup (env);
1009   }
1010   result = GNUNET_malloc (strlen (prefix) + strlen (post) + 2);
1011   strcpy (result, prefix);
1012   if ((strlen (prefix) == 0) ||
1013       ((prefix[strlen (prefix) - 1] != DIR_SEPARATOR) && (strlen (post) > 0)))
1014     strcat (result, DIR_SEPARATOR_STR);
1015   strcat (result, post);
1016   GNUNET_free (prefix);
1017   GNUNET_free (orig);
1018   return result;
1019 }
1020
1021
1022 /**
1023  * Get a configuration value that should be a string.
1024  *
1025  * @param cfg configuration to inspect
1026  * @param section section of interest
1027  * @param option option of interest
1028  * @param value will be set to a freshly allocated configuration
1029  *        value, or NULL if option is not specified
1030  * @return GNUNET_OK on success, GNUNET_SYSERR on error
1031  */
1032 int
1033 GNUNET_CONFIGURATION_get_value_filename (const struct
1034                                          GNUNET_CONFIGURATION_Handle *cfg,
1035                                          const char *section,
1036                                          const char *option, char **value)
1037 {
1038   char *tmp;
1039
1040   if (GNUNET_OK !=
1041       GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &tmp))
1042   {
1043     *value = NULL;
1044     return GNUNET_SYSERR;
1045   }
1046   tmp = GNUNET_CONFIGURATION_expand_dollar (cfg, tmp);
1047   *value = GNUNET_STRINGS_filename_expand (tmp);
1048   GNUNET_free (tmp);
1049   if (*value == NULL)
1050     return GNUNET_SYSERR;
1051   return GNUNET_OK;
1052 }
1053
1054
1055 /**
1056  * Get a configuration value that should be in a set of
1057  * "GNUNET_YES" or "GNUNET_NO".
1058  *
1059  * @param cfg configuration to inspect
1060  * @param section section of interest
1061  * @param option option of interest
1062  * @return GNUNET_YES, GNUNET_NO or GNUNET_SYSERR
1063  */
1064 int
1065 GNUNET_CONFIGURATION_get_value_yesno (const struct GNUNET_CONFIGURATION_Handle
1066                                       *cfg, const char *section,
1067                                       const char *option)
1068 {
1069   static const char *yesno[] = { "YES", "NO", NULL };
1070   const char *val;
1071   int ret;
1072
1073   ret =
1074       GNUNET_CONFIGURATION_get_value_choice (cfg, section, option, yesno, &val);
1075   if (ret == GNUNET_SYSERR)
1076     return ret;
1077   if (val == yesno[0])
1078     return GNUNET_YES;
1079   return GNUNET_NO;
1080 }
1081
1082
1083 /**
1084  * Iterate over the set of filenames stored in a configuration value.
1085  *
1086  * @param cfg configuration to inspect
1087  * @param section section of interest
1088  * @param option option of interest
1089  * @param cb function to call on each filename
1090  * @param cb_cls closure for cb
1091  * @return number of filenames iterated over, -1 on error
1092  */
1093 int
1094 GNUNET_CONFIGURATION_iterate_value_filenames (const struct
1095                                               GNUNET_CONFIGURATION_Handle *cfg,
1096                                               const char *section,
1097                                               const char *option,
1098                                               GNUNET_FileNameCallback cb,
1099                                               void *cb_cls)
1100 {
1101   char *list;
1102   char *pos;
1103   char *end;
1104   char old;
1105   int ret;
1106
1107   if (GNUNET_OK !=
1108       GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &list))
1109     return 0;
1110   GNUNET_assert (list != NULL);
1111   ret = 0;
1112   pos = list;
1113   while (1)
1114   {
1115     while (pos[0] == ' ')
1116       pos++;
1117     if (strlen (pos) == 0)
1118       break;
1119     end = pos + 1;
1120     while ((end[0] != ' ') && (end[0] != '\0'))
1121     {
1122       if (end[0] == '\\')
1123       {
1124         switch (end[1])
1125         {
1126         case '\\':
1127         case ' ':
1128           memmove (end, &end[1], strlen (&end[1]) + 1);
1129         case '\0':
1130           /* illegal, but just keep it */
1131           break;
1132         default:
1133           /* illegal, but just ignore that there was a '/' */
1134           break;
1135         }
1136       }
1137       end++;
1138     }
1139     old = end[0];
1140     end[0] = '\0';
1141     if (strlen (pos) > 0)
1142     {
1143       ret++;
1144       if ((cb != NULL) && (GNUNET_OK != cb (cb_cls, pos)))
1145       {
1146         ret = GNUNET_SYSERR;
1147         break;
1148       }
1149     }
1150     if (old == '\0')
1151       break;
1152     pos = end + 1;
1153   }
1154   GNUNET_free (list);
1155   return ret;
1156 }
1157
1158
1159 /**
1160  * FIXME.
1161  *
1162  * @param value FIXME
1163  * @return FIXME
1164  */
1165 static char *
1166 escape_name (const char *value)
1167 {
1168   char *escaped;
1169   const char *rpos;
1170   char *wpos;
1171
1172   escaped = GNUNET_malloc (strlen (value) * 2 + 1);
1173   memset (escaped, 0, strlen (value) * 2 + 1);
1174   rpos = value;
1175   wpos = escaped;
1176   while (rpos[0] != '\0')
1177   {
1178     switch (rpos[0])
1179     {
1180     case '\\':
1181     case ' ':
1182       wpos[0] = '\\';
1183       wpos[1] = rpos[0];
1184       wpos += 2;
1185       break;
1186     default:
1187       wpos[0] = rpos[0];
1188       wpos++;
1189     }
1190     rpos++;
1191   }
1192   return escaped;
1193 }
1194
1195
1196 /**
1197  * FIXME.
1198  *
1199  * @param cls string we compare with (const char*)
1200  * @param fn filename we are currently looking at
1201  * @return GNUNET_OK if the names do not match, GNUNET_SYSERR if they do
1202  */
1203 static int
1204 test_match (void *cls, const char *fn)
1205 {
1206   const char *of = cls;
1207
1208   return (0 == strcmp (of, fn)) ? GNUNET_SYSERR : GNUNET_OK;
1209 }
1210
1211
1212 /**
1213  * Append a filename to a configuration value that
1214  * represents a list of filenames
1215  *
1216  * @param cfg configuration to update
1217  * @param section section of interest
1218  * @param option option of interest
1219  * @param value filename to append
1220  * @return GNUNET_OK on success,
1221  *         GNUNET_NO if the filename already in the list
1222  *         GNUNET_SYSERR on error
1223  */
1224 int
1225 GNUNET_CONFIGURATION_append_value_filename (struct GNUNET_CONFIGURATION_Handle
1226                                             *cfg, const char *section,
1227                                             const char *option,
1228                                             const char *value)
1229 {
1230   char *escaped;
1231   char *old;
1232   char *nw;
1233
1234   if (GNUNET_SYSERR ==
1235       GNUNET_CONFIGURATION_iterate_value_filenames (cfg, section, option,
1236                                                     &test_match,
1237                                                     (void *) value))
1238     return GNUNET_NO;           /* already exists */
1239   if (GNUNET_OK !=
1240       GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &old))
1241     old = GNUNET_strdup ("");
1242   escaped = escape_name (value);
1243   nw = GNUNET_malloc (strlen (old) + strlen (escaped) + 2);
1244   strcpy (nw, old);
1245   if (strlen (old) > 0)
1246     strcat (nw, " ");
1247   strcat (nw, escaped);
1248   GNUNET_CONFIGURATION_set_value_string (cfg, section, option, nw);
1249   GNUNET_free (old);
1250   GNUNET_free (nw);
1251   GNUNET_free (escaped);
1252   return GNUNET_OK;
1253 }
1254
1255
1256 /**
1257  * Remove a filename from a configuration value that
1258  * represents a list of filenames
1259  *
1260  * @param cfg configuration to update
1261  * @param section section of interest
1262  * @param option option of interest
1263  * @param value filename to remove
1264  * @return GNUNET_OK on success,
1265  *         GNUNET_NO if the filename is not in the list,
1266  *         GNUNET_SYSERR on error
1267  */
1268 int
1269 GNUNET_CONFIGURATION_remove_value_filename (struct GNUNET_CONFIGURATION_Handle
1270                                             *cfg, const char *section,
1271                                             const char *option,
1272                                             const char *value)
1273 {
1274   char *list;
1275   char *pos;
1276   char *end;
1277   char *match;
1278   char old;
1279
1280   if (GNUNET_OK !=
1281       GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &list))
1282     return GNUNET_NO;
1283   match = escape_name (value);
1284   pos = list;
1285   while (1)
1286   {
1287     while (pos[0] == ' ')
1288       pos++;
1289     if (strlen (pos) == 0)
1290       break;
1291     end = pos + 1;
1292     while ((end[0] != ' ') && (end[0] != '\0'))
1293     {
1294       if (end[0] == '\\')
1295       {
1296         switch (end[1])
1297         {
1298         case '\\':
1299         case ' ':
1300           end++;
1301           break;
1302         case '\0':
1303           /* illegal, but just keep it */
1304           break;
1305         default:
1306           /* illegal, but just ignore that there was a '/' */
1307           break;
1308         }
1309       }
1310       end++;
1311     }
1312     old = end[0];
1313     end[0] = '\0';
1314     if (0 == strcmp (pos, match))
1315     {
1316       if (old != '\0')
1317         memmove (pos, &end[1], strlen (&end[1]) + 1);
1318       else
1319       {
1320         if (pos != list)
1321           pos[-1] = '\0';
1322         else
1323           pos[0] = '\0';
1324       }
1325       GNUNET_CONFIGURATION_set_value_string (cfg, section, option, list);
1326       GNUNET_free (list);
1327       GNUNET_free (match);
1328       return GNUNET_OK;
1329     }
1330     if (old == '\0')
1331       break;
1332     end[0] = old;
1333     pos = end + 1;
1334   }
1335   GNUNET_free (list);
1336   GNUNET_free (match);
1337   return GNUNET_NO;
1338 }
1339
1340
1341 /**
1342  * Wrapper around GNUNET_CONFIGURATION_parse.
1343  *
1344  * @param cls the cfg
1345  * @param filename file to parse
1346  * @return GNUNET_OK on success
1347  */
1348 static int
1349 parse_configuration_file (void *cls, const char *filename)
1350 {
1351   struct GNUNET_CONFIGURATION_Handle *cfg = cls;
1352   char * ext;
1353   int ret;
1354
1355   /* Examine file extension */
1356   ext = strrchr (filename, '.');
1357   if ((NULL == ext) || (0 != strcmp (ext, ".conf")))
1358   {
1359     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Skipping file `%s'\n", filename);
1360     return GNUNET_OK;
1361   }
1362
1363   ret = GNUNET_CONFIGURATION_parse (cfg, filename);
1364   return ret;
1365 }
1366
1367
1368 /**
1369  * Load default configuration.  This function will parse the
1370  * defaults from the given defaults_d directory.
1371  *
1372  * @param cfg configuration to update
1373  * @param defaults_d directory with the defaults
1374  * @return GNUNET_OK on success, GNUNET_SYSERR on error
1375  */
1376 int
1377 GNUNET_CONFIGURATION_load_from (struct GNUNET_CONFIGURATION_Handle *cfg,
1378                                 const char *defaults_d)
1379 {
1380   if (GNUNET_SYSERR ==
1381       GNUNET_DISK_directory_scan (defaults_d, &parse_configuration_file, cfg))
1382     return GNUNET_SYSERR;       /* no configuration at all found */
1383   return GNUNET_OK;
1384 }
1385
1386
1387 /**
1388  * Load configuration (starts with defaults, then loads
1389  * system-specific configuration).
1390  *
1391  * @param cfg configuration to update
1392  * @param filename name of the configuration file, NULL to load defaults
1393  * @return GNUNET_OK on success, GNUNET_SYSERR on error
1394  */
1395 int
1396 GNUNET_CONFIGURATION_load (struct GNUNET_CONFIGURATION_Handle *cfg,
1397                            const char *filename)
1398 {
1399   char *baseconfig;
1400   char *ipath;
1401
1402   ipath = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR);
1403   if (ipath == NULL)
1404     return GNUNET_SYSERR;
1405   baseconfig = NULL;
1406   GNUNET_asprintf (&baseconfig, "%s%s", ipath, "config.d");
1407   GNUNET_free (ipath);
1408   if (GNUNET_SYSERR ==
1409       GNUNET_DISK_directory_scan (baseconfig, &parse_configuration_file, cfg))
1410   {
1411     GNUNET_free (baseconfig);
1412     return GNUNET_SYSERR;       /* no configuration at all found */
1413   }
1414   GNUNET_free (baseconfig);
1415   if ((filename != NULL) &&
1416       (GNUNET_OK != GNUNET_CONFIGURATION_parse (cfg, filename)))
1417   {
1418     /* specified configuration not found */
1419     return GNUNET_SYSERR;
1420   }
1421   if (((GNUNET_YES !=
1422         GNUNET_CONFIGURATION_have_value (cfg, "PATHS", "DEFAULTCONFIG"))) &&
1423       (filename != NULL))
1424     GNUNET_CONFIGURATION_set_value_string (cfg, "PATHS", "DEFAULTCONFIG",
1425                                            filename);
1426   if ((GNUNET_YES ==
1427        GNUNET_CONFIGURATION_have_value (cfg, "TESTING", "WEAKRANDOM")) &&
1428       (GNUNET_YES ==
1429        GNUNET_CONFIGURATION_get_value_yesno (cfg, "TESTING", "WEAKRANDOM")))
1430     GNUNET_CRYPTO_random_disable_entropy_gathering ();
1431   return GNUNET_OK;
1432 }
1433
1434
1435
1436 /* end of configuration.c */