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