4413b0377ff2af0533257d5044029a43080a3d2c
[oweals/gnunet.git] / src / util / configuration.c
1 /*
2      This file is part of GNUnet.
3      (C) 2006, 2007, 2008, 2009 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 2, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  * @file src/util/configuration.c
23  * @brief configuration management
24  *
25  * @author Christian Grothoff
26  */
27
28 #include "platform.h"
29 #include "gnunet_common.h"
30 #include "gnunet_configuration_lib.h"
31 #include "gnunet_crypto_lib.h"
32 #include "gnunet_disk_lib.h"
33 #include "gnunet_os_lib.h"
34 #include "gnunet_strings_lib.h"
35
36 /**
37  * @brief configuration entry
38  */
39 struct ConfigEntry
40 {
41
42   /**
43    * This is a linked list.
44    */
45   struct ConfigEntry *next;
46
47   /**
48    * key for this entry
49    */
50   char *key;
51
52   /**
53    * current, commited value
54    */
55   char *val;
56 };
57
58 /**
59  * @brief configuration section
60  */
61 struct ConfigSection
62 {
63   /**
64    * This is a linked list.
65    */
66   struct ConfigSection *next;
67
68   /**
69    * entries in the section
70    */
71   struct ConfigEntry *entries;
72
73   /**
74    * name of the section
75    */
76   char *name;
77 };
78
79 /**
80  * @brief configuration data
81  */
82 struct GNUNET_CONFIGURATION_Handle
83 {
84   /**
85    * Configuration sections.
86    */
87   struct ConfigSection *sections;
88
89   /**
90    * Modification indication since last save
91    * GNUNET_NO if clean, GNUNET_YES if dirty,
92    * GNUNET_SYSERR on error (i.e. last save failed)
93    */
94   int dirty;
95
96 };
97
98 /**
99  * Create a GNUNET_CONFIGURATION_Configuration.
100  */
101 struct GNUNET_CONFIGURATION_Handle *
102 GNUNET_CONFIGURATION_create ()
103 {
104   return GNUNET_malloc (sizeof (struct GNUNET_CONFIGURATION_Handle));
105 }
106
107 void
108 GNUNET_CONFIGURATION_destroy (struct GNUNET_CONFIGURATION_Handle *cfg)
109 {
110   struct ConfigSection *sec;
111   struct ConfigEntry *ent;
112
113   while (NULL != (sec = cfg->sections))
114     {
115       cfg->sections = sec->next;
116       while (NULL != (ent = sec->entries))
117         {
118           sec->entries = ent->next;
119           GNUNET_free (ent->key);
120           GNUNET_free_non_null (ent->val);
121           GNUNET_free (ent);
122         }
123       GNUNET_free (sec->name);
124       GNUNET_free (sec);
125     }
126   GNUNET_free (cfg);
127 }
128
129 int
130 GNUNET_CONFIGURATION_parse (struct GNUNET_CONFIGURATION_Handle *cfg,
131                             const char *filename)
132 {
133   int dirty;
134   char line[256];
135   char tag[64];
136   char value[192];
137   FILE *fp;
138   unsigned int nr;
139   int i;
140   int emptyline;
141   int ret;
142   char *section;
143   char *fn;
144
145   fn = GNUNET_STRINGS_filename_expand (filename);
146   dirty = cfg->dirty;           /* back up value! */
147   if (NULL == (fp = FOPEN (fn, "r")))
148     {
149       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "fopen", fn);
150       GNUNET_free (fn);
151       return GNUNET_SYSERR;
152     }
153   GNUNET_free (fn);
154   ret = GNUNET_OK;
155   section = GNUNET_strdup ("");
156   memset (line, 0, 256);
157   nr = 0;
158   while (NULL != fgets (line, 255, fp))
159     {
160       nr++;
161       for (i = 0; i < 255; i++)
162         if (line[i] == '\t')
163           line[i] = ' ';
164       if (line[0] == '\n' || line[0] == '#' || line[0] == '%' ||
165           line[0] == '\r')
166         continue;
167       emptyline = 1;
168       for (i = 0; (i < 255 && line[i] != 0); i++)
169         if (line[i] != ' ' && line[i] != '\n' && line[i] != '\r')
170           emptyline = 0;
171       if (emptyline == 1)
172         continue;
173       /* remove tailing whitespace */
174       for (i = strlen (line) - 1; (i >= 0) && (isspace (line[i])); i--)
175         line[i] = '\0';
176       if (1 == sscanf (line, "@INLINE@ %191[^\n]", value))
177         {
178           /* @INLINE@ value */
179           if (0 != GNUNET_CONFIGURATION_parse (cfg, value))
180             ret = GNUNET_SYSERR;        /* failed to parse included config */
181         }
182       else if (1 == sscanf (line, "[%99[^]]]", value))
183         {
184           /* [value] */
185           GNUNET_free (section);
186           section = GNUNET_strdup (value);
187         }
188       else if (2 == sscanf (line, " %63[^= ] = %191[^\n]", tag, value))
189         {
190           /* tag = value */
191           /* Strip LF */
192           i = strlen (value) - 1;
193           while ((i >= 0) && (isspace (value[i])))
194             value[i--] = '\0';
195           /* remove quotes */
196           i = 0;
197           if (value[0] == '"')
198             {
199               i = 1;
200               while ((value[i] != '\0') && (value[i] != '"'))
201                 i++;
202               if (value[i] == '"')
203                 {
204                   value[i] = '\0';
205                   i = 1;
206                 }
207               else
208                 i = 0;
209             }
210           GNUNET_CONFIGURATION_set_value_string (cfg,
211                                                  section, tag, &value[i]);
212         }
213       else if (1 == sscanf (line, " %63[^= ] =[^\n]", tag))
214         {
215           /* tag = */
216           GNUNET_CONFIGURATION_set_value_string (cfg, section, tag, "");
217         }
218       else
219         {
220           /* parse error */
221           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
222                       _
223                       ("Syntax error in configuration file `%s' at line %u.\n"),
224                       filename, nr);
225           ret = GNUNET_SYSERR;
226           break;
227         }
228     }
229   GNUNET_assert (0 == fclose (fp));
230   /* restore dirty flag - anything we set in the meantime
231      came from disk */
232   cfg->dirty = dirty;
233   GNUNET_free (section);
234   return ret;
235 }
236
237 int
238 GNUNET_CONFIGURATION_test_dirty (struct GNUNET_CONFIGURATION_Handle *cfg)
239 {
240   return cfg->dirty;
241 }
242
243 int
244 GNUNET_CONFIGURATION_write (struct GNUNET_CONFIGURATION_Handle *data,
245                             const char *filename)
246 {
247   struct ConfigSection *sec;
248   struct ConfigEntry *ent;
249   FILE *fp;
250   int error;
251   char *fn;
252   char *val;
253   char *pos;
254
255   fn = GNUNET_STRINGS_filename_expand (filename);
256   GNUNET_DISK_directory_create_for_file (fn);
257   if (NULL == (fp = FOPEN (fn, "w")))
258     {
259       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "fopen", fn);
260       GNUNET_free (fn);
261       return GNUNET_SYSERR;
262     }
263   GNUNET_free (fn);
264   error = 0;
265   sec = data->sections;
266   while (sec != NULL)
267     {
268       if (0 > fprintf (fp, "[%s]\n", sec->name))
269         {
270           error = 1;
271           break;
272         }
273       ent = sec->entries;
274       while (ent != NULL)
275         {
276           if (ent->val != NULL)
277             {
278               val = GNUNET_malloc (strlen (ent->val) * 2 + 1);
279               strcpy (val, ent->val);
280               while (NULL != (pos = strstr (val, "\n")))
281                 {
282                   memmove (&pos[2], &pos[1], strlen (&pos[1]));
283                   pos[0] = '\\';
284                   pos[1] = 'n';
285                 }
286               if (0 > fprintf (fp, "%s = %s\n", ent->key, val))
287                 {
288                   error = 1;
289                   GNUNET_free (val);
290                   break;
291                 }
292               GNUNET_free (val);
293             }
294           ent = ent->next;
295         }
296       if (error != 0)
297         break;
298       if (0 > fprintf (fp, "\n"))
299         {
300           error = 1;
301           break;
302         }
303       sec = sec->next;
304     }
305   if (error != 0)
306     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "fprintf", filename);
307   GNUNET_assert (0 == fclose (fp));
308   if (error != 0)
309     {
310       data->dirty = GNUNET_SYSERR;      /* last write failed */
311       return GNUNET_SYSERR;
312     }
313   data->dirty = GNUNET_NO;      /* last write succeeded */
314   return GNUNET_OK;
315 }
316
317
318 static struct ConfigSection *
319 findSection (struct GNUNET_CONFIGURATION_Handle *data, const char *section)
320 {
321   struct ConfigSection *pos;
322
323   pos = data->sections;
324   while ((pos != NULL) && (0 != strcasecmp (section, pos->name)))
325     pos = pos->next;
326   return pos;
327 }
328
329
330 static struct ConfigEntry *
331 findEntry (struct GNUNET_CONFIGURATION_Handle *data,
332            const char *section, const char *key)
333 {
334   struct ConfigSection *sec;
335   struct ConfigEntry *pos;
336
337   sec = findSection (data, section);
338   if (sec == NULL)
339     return NULL;
340   pos = sec->entries;
341   while ((pos != NULL) && (0 != strcasecmp (key, pos->key)))
342     pos = pos->next;
343   return pos;
344 }
345
346 void
347 GNUNET_CONFIGURATION_set_value_string (struct GNUNET_CONFIGURATION_Handle
348                                        *data,
349                                        const char *section,
350                                        const char *option, const char *value)
351 {
352   struct ConfigSection *sec;
353   struct ConfigEntry *e;
354
355   e = findEntry (data, section, option);
356   if (e != NULL)
357     {
358       GNUNET_free_non_null (e->val);
359       e->val = GNUNET_strdup (value);
360       return;
361     }
362   sec = findSection (data, section);
363   if (sec == NULL)
364     {
365       sec = GNUNET_malloc (sizeof (struct ConfigSection));
366       sec->name = GNUNET_strdup (section);
367       sec->next = data->sections;
368       data->sections = sec;
369     }
370   e = GNUNET_malloc (sizeof (struct ConfigEntry));
371   e->key = GNUNET_strdup (option);
372   e->val = GNUNET_strdup (value);
373   e->next = sec->entries;
374   sec->entries = e;
375 }
376
377 void
378 GNUNET_CONFIGURATION_set_value_number (struct GNUNET_CONFIGURATION_Handle
379                                        *cfg, const char *section,
380                                        const char *option,
381                                        unsigned long long number)
382 {
383   char s[64];
384   GNUNET_snprintf (s, 64, "%llu", number);
385   GNUNET_CONFIGURATION_set_value_string (cfg, section, option, s);
386 }
387
388 int
389 GNUNET_CONFIGURATION_get_value_number (struct GNUNET_CONFIGURATION_Handle
390                                        *cfg, const char *section,
391                                        const char *option,
392                                        unsigned long long *number)
393 {
394   struct ConfigEntry *e;
395
396   e = findEntry (cfg, section, option);
397   if (e == NULL)
398     return GNUNET_SYSERR;
399   if (1 != SSCANF (e->val, "%llu", number))
400     return GNUNET_SYSERR;
401   return GNUNET_OK;
402 }
403
404 int
405 GNUNET_CONFIGURATION_get_value_string (struct GNUNET_CONFIGURATION_Handle
406                                        *cfg, const char *section,
407                                        const char *option, char **value)
408 {
409   struct ConfigEntry *e;
410
411   e = findEntry (cfg, section, option);
412   if ((e == NULL) || (e->val == NULL))
413     {
414       *value = NULL;
415       return GNUNET_SYSERR;
416     }
417   *value = GNUNET_strdup (e->val);
418   return GNUNET_OK;
419 }
420
421 int
422 GNUNET_CONFIGURATION_get_value_choice (struct GNUNET_CONFIGURATION_Handle
423                                        *cfg, const char *section,
424                                        const char *option,
425                                        const char **choices,
426                                        const char **value)
427 {
428   struct ConfigEntry *e;
429   int i;
430
431   e = findEntry (cfg, section, option);
432   if (e == NULL)
433     return GNUNET_SYSERR;
434   i = 0;
435   while (choices[i] != NULL)
436     {
437       if (0 == strcasecmp (choices[i], e->val))
438         break;
439       i++;
440     }
441   if (choices[i] == NULL)
442     {
443       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
444                   _("Configuration value '%s' for '%s'"
445                     " in section '%s' is not in set of legal choices\n"),
446                   e->val, option, section);
447       return GNUNET_SYSERR;
448     }
449   *value = choices[i];
450   return GNUNET_OK;
451 }
452
453 /**
454  * Test if we have a value for a particular option
455  * @return GNUNET_YES if so, GNUNET_NO if not.
456  */
457 int
458 GNUNET_CONFIGURATION_have_value (struct GNUNET_CONFIGURATION_Handle *cfg,
459                                  const char *section, const char *option)
460 {
461   struct ConfigEntry *e;
462   if ((NULL == (e = findEntry (cfg, section, option))) || (e->val == NULL))
463     return GNUNET_NO;
464   return GNUNET_YES;
465 }
466
467 /**
468  * Expand an expression of the form "$FOO/BAR" to "DIRECTORY/BAR"
469  * where either in the "PATHS" section or the environtment
470  * "FOO" is set to "DIRECTORY".
471  *
472  * @param old string to $-expand (will be freed!)
473  * @return $-expanded string
474  */
475 char *
476 GNUNET_CONFIGURATION_expand_dollar (struct GNUNET_CONFIGURATION_Handle *cfg,
477                                     char *orig)
478 {
479   int i;
480   char *prefix;
481   char *result;
482   const char *post;
483   const char *env;
484
485   if (orig[0] != '$')
486     return orig;
487   i = 0;
488   while ((orig[i] != '/') && (orig[i] != '\\') && (orig[i] != '\0'))
489     i++;
490   if (orig[i] == '\0')
491     {
492       post = "";
493     }
494   else
495     {
496       orig[i] = '\0';
497       post = &orig[i + 1];
498     }
499   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg,
500                                                           "PATHS",
501                                                           &orig[1], &prefix))
502     {
503       if (NULL == (env = getenv (&orig[1])))
504         {
505           orig[i] = DIR_SEPARATOR;
506           return orig;
507         }
508       prefix = GNUNET_strdup (env);
509     }
510   result = GNUNET_malloc (strlen (prefix) + strlen (post) + 2);
511   strcpy (result, prefix);
512   if ((strlen (prefix) == 0) ||
513       ((prefix[strlen (prefix) - 1] != DIR_SEPARATOR) && (strlen (post) > 0)))
514     strcat (result, DIR_SEPARATOR_STR);
515   strcat (result, post);
516   GNUNET_free (prefix);
517   GNUNET_free (orig);
518   return result;
519 }
520
521 /**
522  * Get a configuration value that should be a string.
523  * @param value will be set to a freshly allocated configuration
524  *        value, or NULL if option is not specified
525  * @return GNUNET_OK on success, GNUNET_SYSERR on error
526  */
527 int
528 GNUNET_CONFIGURATION_get_value_filename (struct GNUNET_CONFIGURATION_Handle
529                                          *data, const char *section,
530                                          const char *option, char **value)
531 {
532   int ret;
533   char *tmp;
534
535   tmp = NULL;
536   ret = GNUNET_CONFIGURATION_get_value_string (data, section, option, &tmp);
537   if (ret == GNUNET_SYSERR)
538     return ret;
539   if (tmp != NULL)
540     {
541       tmp = GNUNET_CONFIGURATION_expand_dollar (data, tmp);
542       *value = GNUNET_STRINGS_filename_expand (tmp);
543       GNUNET_free (tmp);
544     }
545   else
546     {
547       *value = NULL;
548     }
549   return ret;
550 }
551
552 /**
553  * Get a configuration value that should be in a set of
554  * "GNUNET_YES" or "GNUNET_NO".
555  *
556  * @return GNUNET_YES, GNUNET_NO or GNUNET_SYSERR
557  */
558 int
559 GNUNET_CONFIGURATION_get_value_yesno (struct GNUNET_CONFIGURATION_Handle *cfg,
560                                       const char *section, const char *option)
561 {
562   static const char *yesno[] = { "YES", "NO", NULL };
563   const char *val;
564   int ret;
565
566   ret = GNUNET_CONFIGURATION_get_value_choice (cfg,
567                                                section, option, yesno, &val);
568   if (ret == GNUNET_SYSERR)
569     return ret;
570   if (val == yesno[0])
571     return GNUNET_YES;
572   return GNUNET_NO;
573 }
574
575
576 /**
577  * Iterate over the set of filenames stored in a configuration value.
578  *
579  * @return number of filenames iterated over, -1 on error
580  */
581 int
582 GNUNET_CONFIGURATION_iterate_value_filenames (struct
583                                               GNUNET_CONFIGURATION_Handle
584                                               *cfg, const char *section,
585                                               const char *option,
586                                               GNUNET_FileNameCallback cb,
587                                               void *cls)
588 {
589   char *list;
590   char *pos;
591   char *end;
592   char old;
593   int ret;
594
595   if (GNUNET_OK !=
596       GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &list))
597     return 0;
598   GNUNET_assert (list != NULL);
599   ret = 0;
600   pos = list;
601   while (1)
602     {
603       while (pos[0] == ' ')
604         pos++;
605       if (strlen (pos) == 0)
606         break;
607       end = pos + 1;
608       while ((end[0] != ' ') && (end[0] != '\0'))
609         {
610           if (end[0] == '\\')
611             {
612               switch (end[1])
613                 {
614                 case '\\':
615                 case ' ':
616                   memmove (end, &end[1], strlen (&end[1]) + 1);
617                 case '\0':
618                   /* illegal, but just keep it */
619                   break;
620                 default:
621                   /* illegal, but just ignore that there was a '/' */
622                   break;
623                 }
624             }
625           end++;
626         }
627       old = end[0];
628       end[0] = '\0';
629       if (strlen (pos) > 0)
630         {
631           ret++;
632           if ((cb != NULL) && (GNUNET_OK != cb (cls, pos)))
633             {
634               ret = GNUNET_SYSERR;
635               break;
636             }
637         }
638       if (old == '\0')
639         break;
640       pos = end + 1;
641     }
642   GNUNET_free (list);
643   return ret;
644 }
645
646 static char *
647 escape_name (const char *value)
648 {
649   char *escaped;
650   const char *rpos;
651   char *wpos;
652
653   escaped = GNUNET_malloc (strlen (value) * 2 + 1);
654   memset (escaped, 0, strlen (value) * 2 + 1);
655   rpos = value;
656   wpos = escaped;
657   while (rpos[0] != '\0')
658     {
659       switch (rpos[0])
660         {
661         case '\\':
662         case ' ':
663           wpos[0] = '\\';
664           wpos[1] = rpos[0];
665           wpos += 2;
666           break;
667         default:
668           wpos[0] = rpos[0];
669           wpos++;
670         }
671       rpos++;
672     }
673   return escaped;
674 }
675
676 static int
677 test_match (void *cls, const char *fn)
678 {
679   const char *of = cls;
680   return (0 == strcmp (of, fn)) ? GNUNET_SYSERR : GNUNET_OK;
681 }
682
683 /**
684  * Append a filename to a configuration value that
685  * represents a list of filenames
686  *
687  * @param value filename to append
688  * @return GNUNET_OK on success,
689  *         GNUNET_NO if the filename already in the list
690  *         GNUNET_SYSERR on error
691  */
692 int
693 GNUNET_CONFIGURATION_append_value_filename (struct GNUNET_CONFIGURATION_Handle
694                                             *cfg,
695                                             const char *section,
696                                             const char *option,
697                                             const char *value)
698 {
699   char *escaped;
700   char *old;
701   char *nw;
702
703   if (GNUNET_SYSERR
704       == GNUNET_CONFIGURATION_iterate_value_filenames (cfg,
705                                                        section,
706                                                        option,
707                                                        &test_match,
708                                                        (void *) value))
709     return GNUNET_NO;           /* already exists */
710   if (GNUNET_OK !=
711       GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &old))
712     old = GNUNET_strdup ("");
713   escaped = escape_name (value);
714   nw = GNUNET_malloc (strlen (old) + strlen (escaped) + 2);
715   strcpy (nw, old);
716   strcat (nw, " ");
717   strcat (nw, escaped);
718   GNUNET_CONFIGURATION_set_value_string (cfg, section, option, nw);
719   GNUNET_free (old);
720   GNUNET_free (nw);
721   GNUNET_free (escaped);
722   return GNUNET_OK;
723 }
724
725
726 /**
727  * Remove a filename from a configuration value that
728  * represents a list of filenames
729  *
730  * @param value filename to remove
731  * @return GNUNET_OK on success,
732  *         GNUNET_NO if the filename is not in the list,
733  *         GNUNET_SYSERR on error
734  */
735 int
736 GNUNET_CONFIGURATION_remove_value_filename (struct GNUNET_CONFIGURATION_Handle
737                                             *cfg,
738                                             const char *section,
739                                             const char *option,
740                                             const char *value)
741 {
742   char *list;
743   char *pos;
744   char *end;
745   char *match;
746   char old;
747   int ret;
748
749   if (GNUNET_OK !=
750       GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &list))
751     return GNUNET_NO;
752   match = escape_name (value);
753   ret = 0;
754   pos = list;
755   while (1)
756     {
757       while (pos[0] == ' ')
758         pos++;
759       if (strlen (pos) == 0)
760         break;
761       end = pos + 1;
762       while ((end[0] != ' ') && (end[0] != '\0'))
763         {
764           if (end[0] == '\\')
765             {
766               switch (end[1])
767                 {
768                 case '\\':
769                 case ' ':
770                   end++;
771                   break;
772                 case '\0':
773                   /* illegal, but just keep it */
774                   break;
775                 default:
776                   /* illegal, but just ignore that there was a '/' */
777                   break;
778                 }
779             }
780           end++;
781         }
782       old = end[0];
783       end[0] = '\0';
784       if (strlen (pos) > 0)
785         {
786           if (0 == strcmp (pos, match))
787             {
788               memmove (pos, &end[1], strlen (&end[1]) + 1);
789
790               if (pos != list)
791                 pos[-1] = ' ';  /* previously changed to "\0" */
792               GNUNET_CONFIGURATION_set_value_string (cfg,
793                                                      section, option, list);
794               GNUNET_free (list);
795               GNUNET_free (match);
796               return GNUNET_OK;
797             }
798         }
799       if (old == '\0')
800         break;
801       pos = end + 1;
802     }
803   GNUNET_free (list);
804   GNUNET_free (match);
805   return GNUNET_NO;
806 }
807
808
809 /**
810  * Load configuration (starts with defaults, then loads
811  * system-specific configuration).
812  */
813 int
814 GNUNET_CONFIGURATION_load (struct GNUNET_CONFIGURATION_Handle *cfg,
815                            const char *cfgfn)
816 {
817   char *baseconfig;
818   char *ipath;
819
820   ipath = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR);
821   if (ipath == NULL)
822     return GNUNET_SYSERR;
823   baseconfig = NULL;
824   GNUNET_asprintf (&baseconfig,
825                    "%s%s%s", ipath, DIR_SEPARATOR_STR, "defaults.conf");
826   GNUNET_free (ipath);
827   if ((GNUNET_OK !=
828        GNUNET_CONFIGURATION_parse (cfg, baseconfig)) ||
829       (!((cfgfn == NULL) ||
830          (GNUNET_OK == GNUNET_CONFIGURATION_parse (cfg, cfgfn)))))
831     {
832       GNUNET_free (baseconfig);
833       return GNUNET_SYSERR;
834     }
835   GNUNET_free (baseconfig);
836   if ((GNUNET_YES == GNUNET_CONFIGURATION_have_value (cfg,
837                                                       "TESTING",
838                                                       "WEAKRANDOM")) &&
839       (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno (cfg,
840                                                            "TESTING",
841                                                            "WEAKRANDOM")))
842     GNUNET_CRYPTO_random_disable_entropy_gathering ();
843   return GNUNET_OK;
844 }
845
846
847
848 /* end of configuration.c */