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