get time cfg api added
[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_time (struct GNUNET_CONFIGURATION_Handle
406                                      *cfg, const char *section,
407                                      const char *option,
408                                      struct GNUNET_TIME_Relative *time)
409 {
410   unsigned long long num;
411   int ret;
412
413   ret = GNUNET_CONFIGURATION_get_value_number (cfg,
414                                                section,
415                                                option,
416                                                &num);
417   if (ret == GNUNET_OK)
418     time->value = (uint64_t) num;
419   return ret;
420 }
421
422 int
423 GNUNET_CONFIGURATION_get_value_string (struct GNUNET_CONFIGURATION_Handle
424                                        *cfg, const char *section,
425                                        const char *option, char **value)
426 {
427   struct ConfigEntry *e;
428
429   e = findEntry (cfg, section, option);
430   if ((e == NULL) || (e->val == NULL))
431     {
432       *value = NULL;
433       return GNUNET_SYSERR;
434     }
435   *value = GNUNET_strdup (e->val);
436   return GNUNET_OK;
437 }
438
439 int
440 GNUNET_CONFIGURATION_get_value_choice (struct GNUNET_CONFIGURATION_Handle
441                                        *cfg, const char *section,
442                                        const char *option,
443                                        const char **choices,
444                                        const char **value)
445 {
446   struct ConfigEntry *e;
447   int i;
448
449   e = findEntry (cfg, section, option);
450   if (e == NULL)
451     return GNUNET_SYSERR;
452   i = 0;
453   while (choices[i] != NULL)
454     {
455       if (0 == strcasecmp (choices[i], e->val))
456         break;
457       i++;
458     }
459   if (choices[i] == NULL)
460     {
461       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
462                   _("Configuration value '%s' for '%s'"
463                     " in section '%s' is not in set of legal choices\n"),
464                   e->val, option, section);
465       return GNUNET_SYSERR;
466     }
467   *value = choices[i];
468   return GNUNET_OK;
469 }
470
471 /**
472  * Test if we have a value for a particular option
473  * @return GNUNET_YES if so, GNUNET_NO if not.
474  */
475 int
476 GNUNET_CONFIGURATION_have_value (struct GNUNET_CONFIGURATION_Handle *cfg,
477                                  const char *section, const char *option)
478 {
479   struct ConfigEntry *e;
480   if ((NULL == (e = findEntry (cfg, section, option))) || (e->val == NULL))
481     return GNUNET_NO;
482   return GNUNET_YES;
483 }
484
485 /**
486  * Expand an expression of the form "$FOO/BAR" to "DIRECTORY/BAR"
487  * where either in the "PATHS" section or the environtment
488  * "FOO" is set to "DIRECTORY".
489  *
490  * @param old string to $-expand (will be freed!)
491  * @return $-expanded string
492  */
493 char *
494 GNUNET_CONFIGURATION_expand_dollar (struct GNUNET_CONFIGURATION_Handle *cfg,
495                                     char *orig)
496 {
497   int i;
498   char *prefix;
499   char *result;
500   const char *post;
501   const char *env;
502
503   if (orig[0] != '$')
504     return orig;
505   i = 0;
506   while ((orig[i] != '/') && (orig[i] != '\\') && (orig[i] != '\0'))
507     i++;
508   if (orig[i] == '\0')
509     {
510       post = "";
511     }
512   else
513     {
514       orig[i] = '\0';
515       post = &orig[i + 1];
516     }
517   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg,
518                                                           "PATHS",
519                                                           &orig[1], &prefix))
520     {
521       if (NULL == (env = getenv (&orig[1])))
522         {
523           orig[i] = DIR_SEPARATOR;
524           return orig;
525         }
526       prefix = GNUNET_strdup (env);
527     }
528   result = GNUNET_malloc (strlen (prefix) + strlen (post) + 2);
529   strcpy (result, prefix);
530   if ((strlen (prefix) == 0) ||
531       ((prefix[strlen (prefix) - 1] != DIR_SEPARATOR) && (strlen (post) > 0)))
532     strcat (result, DIR_SEPARATOR_STR);
533   strcat (result, post);
534   GNUNET_free (prefix);
535   GNUNET_free (orig);
536   return result;
537 }
538
539 /**
540  * Get a configuration value that should be a string.
541  * @param value will be set to a freshly allocated configuration
542  *        value, or NULL if option is not specified
543  * @return GNUNET_OK on success, GNUNET_SYSERR on error
544  */
545 int
546 GNUNET_CONFIGURATION_get_value_filename (struct GNUNET_CONFIGURATION_Handle
547                                          *data, const char *section,
548                                          const char *option, char **value)
549 {
550   int ret;
551   char *tmp;
552
553   tmp = NULL;
554   ret = GNUNET_CONFIGURATION_get_value_string (data, section, option, &tmp);
555   if (ret == GNUNET_SYSERR)
556     return ret;
557   if (tmp != NULL)
558     {
559       tmp = GNUNET_CONFIGURATION_expand_dollar (data, tmp);
560       *value = GNUNET_STRINGS_filename_expand (tmp);
561       GNUNET_free (tmp);
562     }
563   else
564     {
565       *value = NULL;
566     }
567   return ret;
568 }
569
570 /**
571  * Get a configuration value that should be in a set of
572  * "GNUNET_YES" or "GNUNET_NO".
573  *
574  * @return GNUNET_YES, GNUNET_NO or GNUNET_SYSERR
575  */
576 int
577 GNUNET_CONFIGURATION_get_value_yesno (struct GNUNET_CONFIGURATION_Handle *cfg,
578                                       const char *section, const char *option)
579 {
580   static const char *yesno[] = { "YES", "NO", NULL };
581   const char *val;
582   int ret;
583
584   ret = GNUNET_CONFIGURATION_get_value_choice (cfg,
585                                                section, option, yesno, &val);
586   if (ret == GNUNET_SYSERR)
587     return ret;
588   if (val == yesno[0])
589     return GNUNET_YES;
590   return GNUNET_NO;
591 }
592
593
594 /**
595  * Iterate over the set of filenames stored in a configuration value.
596  *
597  * @return number of filenames iterated over, -1 on error
598  */
599 int
600 GNUNET_CONFIGURATION_iterate_value_filenames (struct
601                                               GNUNET_CONFIGURATION_Handle
602                                               *cfg, const char *section,
603                                               const char *option,
604                                               GNUNET_FileNameCallback cb,
605                                               void *cls)
606 {
607   char *list;
608   char *pos;
609   char *end;
610   char old;
611   int ret;
612
613   if (GNUNET_OK !=
614       GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &list))
615     return 0;
616   GNUNET_assert (list != NULL);
617   ret = 0;
618   pos = list;
619   while (1)
620     {
621       while (pos[0] == ' ')
622         pos++;
623       if (strlen (pos) == 0)
624         break;
625       end = pos + 1;
626       while ((end[0] != ' ') && (end[0] != '\0'))
627         {
628           if (end[0] == '\\')
629             {
630               switch (end[1])
631                 {
632                 case '\\':
633                 case ' ':
634                   memmove (end, &end[1], strlen (&end[1]) + 1);
635                 case '\0':
636                   /* illegal, but just keep it */
637                   break;
638                 default:
639                   /* illegal, but just ignore that there was a '/' */
640                   break;
641                 }
642             }
643           end++;
644         }
645       old = end[0];
646       end[0] = '\0';
647       if (strlen (pos) > 0)
648         {
649           ret++;
650           if ((cb != NULL) && (GNUNET_OK != cb (cls, pos)))
651             {
652               ret = GNUNET_SYSERR;
653               break;
654             }
655         }
656       if (old == '\0')
657         break;
658       pos = end + 1;
659     }
660   GNUNET_free (list);
661   return ret;
662 }
663
664 static char *
665 escape_name (const char *value)
666 {
667   char *escaped;
668   const char *rpos;
669   char *wpos;
670
671   escaped = GNUNET_malloc (strlen (value) * 2 + 1);
672   memset (escaped, 0, strlen (value) * 2 + 1);
673   rpos = value;
674   wpos = escaped;
675   while (rpos[0] != '\0')
676     {
677       switch (rpos[0])
678         {
679         case '\\':
680         case ' ':
681           wpos[0] = '\\';
682           wpos[1] = rpos[0];
683           wpos += 2;
684           break;
685         default:
686           wpos[0] = rpos[0];
687           wpos++;
688         }
689       rpos++;
690     }
691   return escaped;
692 }
693
694 static int
695 test_match (void *cls, const char *fn)
696 {
697   const char *of = cls;
698   return (0 == strcmp (of, fn)) ? GNUNET_SYSERR : GNUNET_OK;
699 }
700
701 /**
702  * Append a filename to a configuration value that
703  * represents a list of filenames
704  *
705  * @param value filename to append
706  * @return GNUNET_OK on success,
707  *         GNUNET_NO if the filename already in the list
708  *         GNUNET_SYSERR on error
709  */
710 int
711 GNUNET_CONFIGURATION_append_value_filename (struct GNUNET_CONFIGURATION_Handle
712                                             *cfg,
713                                             const char *section,
714                                             const char *option,
715                                             const char *value)
716 {
717   char *escaped;
718   char *old;
719   char *nw;
720
721   if (GNUNET_SYSERR
722       == GNUNET_CONFIGURATION_iterate_value_filenames (cfg,
723                                                        section,
724                                                        option,
725                                                        &test_match,
726                                                        (void *) value))
727     return GNUNET_NO;           /* already exists */
728   if (GNUNET_OK !=
729       GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &old))
730     old = GNUNET_strdup ("");
731   escaped = escape_name (value);
732   nw = GNUNET_malloc (strlen (old) + strlen (escaped) + 2);
733   strcpy (nw, old);
734   strcat (nw, " ");
735   strcat (nw, escaped);
736   GNUNET_CONFIGURATION_set_value_string (cfg, section, option, nw);
737   GNUNET_free (old);
738   GNUNET_free (nw);
739   GNUNET_free (escaped);
740   return GNUNET_OK;
741 }
742
743
744 /**
745  * Remove a filename from a configuration value that
746  * represents a list of filenames
747  *
748  * @param value filename to remove
749  * @return GNUNET_OK on success,
750  *         GNUNET_NO if the filename is not in the list,
751  *         GNUNET_SYSERR on error
752  */
753 int
754 GNUNET_CONFIGURATION_remove_value_filename (struct GNUNET_CONFIGURATION_Handle
755                                             *cfg,
756                                             const char *section,
757                                             const char *option,
758                                             const char *value)
759 {
760   char *list;
761   char *pos;
762   char *end;
763   char *match;
764   char old;
765   int ret;
766
767   if (GNUNET_OK !=
768       GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &list))
769     return GNUNET_NO;
770   match = escape_name (value);
771   ret = 0;
772   pos = list;
773   while (1)
774     {
775       while (pos[0] == ' ')
776         pos++;
777       if (strlen (pos) == 0)
778         break;
779       end = pos + 1;
780       while ((end[0] != ' ') && (end[0] != '\0'))
781         {
782           if (end[0] == '\\')
783             {
784               switch (end[1])
785                 {
786                 case '\\':
787                 case ' ':
788                   end++;
789                   break;
790                 case '\0':
791                   /* illegal, but just keep it */
792                   break;
793                 default:
794                   /* illegal, but just ignore that there was a '/' */
795                   break;
796                 }
797             }
798           end++;
799         }
800       old = end[0];
801       end[0] = '\0';
802       if (strlen (pos) > 0)
803         {
804           if (0 == strcmp (pos, match))
805             {
806               memmove (pos, &end[1], strlen (&end[1]) + 1);
807
808               if (pos != list)
809                 pos[-1] = ' ';  /* previously changed to "\0" */
810               GNUNET_CONFIGURATION_set_value_string (cfg,
811                                                      section, option, list);
812               GNUNET_free (list);
813               GNUNET_free (match);
814               return GNUNET_OK;
815             }
816         }
817       if (old == '\0')
818         break;
819       pos = end + 1;
820     }
821   GNUNET_free (list);
822   GNUNET_free (match);
823   return GNUNET_NO;
824 }
825
826
827 /**
828  * Load configuration (starts with defaults, then loads
829  * system-specific configuration).
830  */
831 int
832 GNUNET_CONFIGURATION_load (struct GNUNET_CONFIGURATION_Handle *cfg,
833                            const char *cfgfn)
834 {
835   char *baseconfig;
836   char *ipath;
837
838   ipath = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR);
839   if (ipath == NULL)
840     return GNUNET_SYSERR;
841   baseconfig = NULL;
842   GNUNET_asprintf (&baseconfig,
843                    "%s%s%s", ipath, DIR_SEPARATOR_STR, "defaults.conf");
844   GNUNET_free (ipath);
845   if ((GNUNET_OK !=
846        GNUNET_CONFIGURATION_parse (cfg, baseconfig)) ||
847       (!((cfgfn == NULL) ||
848          (GNUNET_OK == GNUNET_CONFIGURATION_parse (cfg, cfgfn)))))
849     {
850       GNUNET_free (baseconfig);
851       return GNUNET_SYSERR;
852     }
853   GNUNET_free (baseconfig);
854   if ((GNUNET_YES == GNUNET_CONFIGURATION_have_value (cfg,
855                                                       "TESTING",
856                                                       "WEAKRANDOM")) &&
857       (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno (cfg,
858                                                            "TESTING",
859                                                            "WEAKRANDOM")))
860     GNUNET_CRYPTO_random_disable_entropy_gathering ();
861   return GNUNET_OK;
862 }
863
864
865
866 /* end of configuration.c */