aboutsummaryrefslogtreecommitdiff
path: root/src/util/configuration.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/util/configuration.c')
-rw-r--r--src/util/configuration.c297
1 files changed, 245 insertions, 52 deletions
diff --git a/src/util/configuration.c b/src/util/configuration.c
index fffe08788..cc71a239d 100644
--- a/src/util/configuration.c
+++ b/src/util/configuration.c
@@ -29,6 +29,7 @@
29#include "gnunet_configuration_lib.h" 29#include "gnunet_configuration_lib.h"
30#include "gnunet_disk_lib.h" 30#include "gnunet_disk_lib.h"
31#include "gnunet_buffer_lib.h" 31#include "gnunet_buffer_lib.h"
32#include "gnunet_container_lib.h"
32 33
33#define LOG(kind, ...) GNUNET_log_from (kind, "util", __VA_ARGS__) 34#define LOG(kind, ...) GNUNET_log_from (kind, "util", __VA_ARGS__)
34 35
@@ -111,6 +112,23 @@ struct ConfigSection
111 unsigned int hint_inlined_from_line; 112 unsigned int hint_inlined_from_line;
112}; 113};
113 114
115struct ConfigFile
116{
117 /**
118 * Source filename.
119 */
120 char *source_filename;
121
122 /**
123 * Level in the tree of loaded config files.
124 */
125 unsigned int level;
126
127 struct ConfigFile *prev;
128
129 struct ConfigFile *next;
130};
131
114 132
115/** 133/**
116 * @brief configuration data 134 * @brief configuration data
@@ -123,6 +141,21 @@ struct GNUNET_CONFIGURATION_Handle
123 struct ConfigSection *sections; 141 struct ConfigSection *sections;
124 142
125 /** 143 /**
144 * Linked list of loaded files.
145 */
146 struct ConfigFile *loaded_files_head;
147
148 /**
149 * Linked list of loaded files.
150 */
151 struct ConfigFile *loaded_files_tail;
152
153 /**
154 * Current nesting level of file loading.
155 */
156 unsigned int current_nest_level;
157
158 /**
126 * Enable diagnostics. 159 * Enable diagnostics.
127 */ 160 */
128 bool diagnostics; 161 bool diagnostics;
@@ -135,6 +168,11 @@ struct GNUNET_CONFIGURATION_Handle
135 enum GNUNET_GenericReturnValue dirty; 168 enum GNUNET_GenericReturnValue dirty;
136 169
137 /** 170 /**
171 * Was the configuration ever loaded via GNUNET_CONFIGURATION_load?
172 */
173 bool load_called;
174
175 /**
138 * Name of the entry point configuration file. 176 * Name of the entry point configuration file.
139 */ 177 */
140 char *main_filename; 178 char *main_filename;
@@ -250,9 +288,14 @@ void
250GNUNET_CONFIGURATION_destroy (struct GNUNET_CONFIGURATION_Handle *cfg) 288GNUNET_CONFIGURATION_destroy (struct GNUNET_CONFIGURATION_Handle *cfg)
251{ 289{
252 struct ConfigSection *sec; 290 struct ConfigSection *sec;
291 struct ConfigFile *cf;
253 292
254 while (NULL != (sec = cfg->sections)) 293 while (NULL != (sec = cfg->sections))
255 GNUNET_CONFIGURATION_remove_section (cfg, sec->name); 294 GNUNET_CONFIGURATION_remove_section (cfg, sec->name);
295 while (NULL != (cf = cfg->loaded_files_head))
296 GNUNET_CONTAINER_DLL_remove (cfg->loaded_files_head,
297 cfg->loaded_files_tail,
298 cf);
256 GNUNET_free (cfg); 299 GNUNET_free (cfg);
257} 300}
258 301
@@ -279,9 +322,9 @@ GNUNET_CONFIGURATION_parse_and_run (const char *filename,
279 322
280 323
281/** 324/**
282 * Closure to inline_glob_cb. 325 * Closure to collect_files_cb.
283 */ 326 */
284struct InlineGlobClosure 327struct CollectFilesContext
285{ 328{
286 /** 329 /**
287 * Collected files from globbing. 330 * Collected files from globbing.
@@ -305,14 +348,10 @@ struct InlineGlobClosure
305 * #GNUNET_SYSERR to abort iteration with error! 348 * #GNUNET_SYSERR to abort iteration with error!
306 */ 349 */
307static int 350static int
308inline_glob_cb (void *cls, 351collect_files_cb (void *cls,
309 const char *filename) 352 const char *filename)
310{ 353{
311 struct InlineGlobClosure *igc = cls; 354 struct CollectFilesContext *igc = cls;
312
313 LOG (GNUNET_ERROR_TYPE_DEBUG,
314 "Found globbed config file '%s'\n",
315 filename);
316 355
317 GNUNET_array_append (igc->files, 356 GNUNET_array_append (igc->files,
318 igc->files_length, 357 igc->files_length,
@@ -363,11 +402,12 @@ handle_inline (struct GNUNET_CONFIGURATION_Handle *cfg,
363{ 402{
364 char *inline_path; 403 char *inline_path;
365 struct GNUNET_CONFIGURATION_Handle *other_cfg = NULL; 404 struct GNUNET_CONFIGURATION_Handle *other_cfg = NULL;
366 struct InlineGlobClosure igc = { 405 struct CollectFilesContext igc = {
367 .files = NULL, 406 .files = NULL,
368 .files_length = 0, 407 .files_length = 0,
369 }; 408 };
370 enum GNUNET_GenericReturnValue fun_ret; 409 enum GNUNET_GenericReturnValue fun_ret;
410 unsigned int old_nest_level = cfg->current_nest_level++;
371 411
372 /* We support the section restriction only for non-globs */ 412 /* We support the section restriction only for non-globs */
373 GNUNET_assert (! (path_is_glob && (NULL != restrict_section))); 413 GNUNET_assert (! (path_is_glob && (NULL != restrict_section)));
@@ -419,7 +459,7 @@ handle_inline (struct GNUNET_CONFIGURATION_Handle *cfg,
419 "processing config glob '%s'\n", 459 "processing config glob '%s'\n",
420 inline_path); 460 inline_path);
421 461
422 nret = GNUNET_DISK_glob (inline_path, inline_glob_cb, &igc); 462 nret = GNUNET_DISK_glob (inline_path, collect_files_cb, &igc);
423 if (-1 == nret) 463 if (-1 == nret)
424 { 464 {
425 fun_ret = GNUNET_SYSERR; 465 fun_ret = GNUNET_SYSERR;
@@ -441,10 +481,10 @@ handle_inline (struct GNUNET_CONFIGURATION_Handle *cfg,
441 } 481 }
442 else if (NULL != restrict_section) 482 else if (NULL != restrict_section)
443 { 483 {
444 enum GNUNET_GenericReturnValue fret; 484 enum GNUNET_GenericReturnValue inner_ret;
445 struct ConfigSection *cs; 485 struct ConfigSection *cs;
446 486
447 fret = GNUNET_DISK_file_test_read (inline_path); 487 inner_ret = GNUNET_DISK_file_test_read (inline_path);
448 488
449 cs = find_section (cfg, restrict_section); 489 cs = find_section (cfg, restrict_section);
450 490
@@ -467,7 +507,7 @@ handle_inline (struct GNUNET_CONFIGURATION_Handle *cfg,
467 } 507 }
468 } 508 }
469 509
470 if (GNUNET_OK != fret) 510 if (GNUNET_OK != inner_ret)
471 { 511 {
472 cs->inaccessible = true; 512 cs->inaccessible = true;
473 fun_ret = GNUNET_OK; 513 fun_ret = GNUNET_OK;
@@ -475,10 +515,11 @@ handle_inline (struct GNUNET_CONFIGURATION_Handle *cfg,
475 } 515 }
476 516
477 other_cfg = GNUNET_CONFIGURATION_create (); 517 other_cfg = GNUNET_CONFIGURATION_create ();
478 if (GNUNET_OK != GNUNET_CONFIGURATION_parse (other_cfg, 518 inner_ret = GNUNET_CONFIGURATION_parse (other_cfg,
479 inline_path)) 519 inline_path);
520 if (GNUNET_OK != inner_ret)
480 { 521 {
481 fun_ret = GNUNET_SYSERR; 522 fun_ret = inner_ret;
482 goto cleanup; 523 goto cleanup;
483 } 524 }
484 525
@@ -513,6 +554,7 @@ handle_inline (struct GNUNET_CONFIGURATION_Handle *cfg,
513 fun_ret = GNUNET_OK; 554 fun_ret = GNUNET_OK;
514 } 555 }
515 cleanup: 556 cleanup:
557 cfg->current_nest_level = old_nest_level;
516 if (NULL != other_cfg) 558 if (NULL != other_cfg)
517 GNUNET_CONFIGURATION_destroy (other_cfg); 559 GNUNET_CONFIGURATION_destroy (other_cfg);
518 GNUNET_free (inline_path); 560 GNUNET_free (inline_path);
@@ -756,11 +798,7 @@ GNUNET_CONFIGURATION_deserialize (struct GNUNET_CONFIGURATION_Handle *cfg,
756 } 798 }
757 if (GNUNET_OK != directive_ret) 799 if (GNUNET_OK != directive_ret)
758 { 800 {
759 LOG (GNUNET_ERROR_TYPE_WARNING, 801 ret = directive_ret;
760 _ ("Bad directive '%s' in line %u\n"),
761 directive,
762 nr);
763 ret = GNUNET_SYSERR;
764 break; 802 break;
765 } 803 }
766 continue; 804 continue;
@@ -845,6 +883,55 @@ GNUNET_CONFIGURATION_parse (struct GNUNET_CONFIGURATION_Handle *cfg,
845 LOG (GNUNET_ERROR_TYPE_DEBUG, "Asked to parse config file `%s'\n", fn); 883 LOG (GNUNET_ERROR_TYPE_DEBUG, "Asked to parse config file `%s'\n", fn);
846 if (NULL == fn) 884 if (NULL == fn)
847 return GNUNET_SYSERR; 885 return GNUNET_SYSERR;
886
887
888 /* Check for cycles */
889 {
890 unsigned int lvl = cfg->current_nest_level;
891 struct ConfigFile *cf = cfg->loaded_files_tail;
892 struct ConfigFile *parent = NULL;
893
894
895 for (; NULL != cf; parent = cf, cf = cf->prev)
896 {
897 /* Check parents based on level, skipping children of siblings. */
898 if (cf->level >= lvl)
899 continue;
900 lvl = cf->level;
901 if ( (NULL == cf->source_filename) || (NULL == filename))
902 continue;
903 if (0 == strcmp (cf->source_filename, filename))
904 {
905 if (NULL == parent)
906 {
907 LOG (GNUNET_ERROR_TYPE_ERROR,
908 "Forbidden direct cyclic configuration import (%s -> %s)\n",
909 cf->source_filename,
910 filename);
911 }
912 else
913 LOG (GNUNET_ERROR_TYPE_ERROR,
914 "Forbidden indirect cyclic configuration import (%s -> ... -> %s -> %s)\n",
915 cf->source_filename,
916 parent->source_filename,
917 filename);
918 return GNUNET_SYSERR;
919 }
920 }
921
922 }
923
924 /* Keep track of loaded files.*/
925 {
926 struct ConfigFile *cf = GNUNET_new (struct ConfigFile);
927
928 cf->level = cfg->current_nest_level;
929 cf->source_filename = GNUNET_strdup (filename ? filename : "<input>");
930 GNUNET_CONTAINER_DLL_insert_tail (cfg->loaded_files_head,
931 cfg->loaded_files_tail,
932 cf);
933 }
934
848 dirty = cfg->dirty; /* back up value! */ 935 dirty = cfg->dirty; /* back up value! */
849 if (GNUNET_SYSERR == 936 if (GNUNET_SYSERR ==
850 GNUNET_DISK_file_size (fn, &fs64, GNUNET_YES, GNUNET_YES)) 937 GNUNET_DISK_file_size (fn, &fs64, GNUNET_YES, GNUNET_YES))
@@ -876,7 +963,7 @@ GNUNET_CONFIGURATION_parse (struct GNUNET_CONFIGURATION_Handle *cfg,
876 mem, 963 mem,
877 fs, 964 fs,
878 fn); 965 fn);
879 if (GNUNET_OK != ret) 966 if (GNUNET_SYSERR == ret)
880 { 967 {
881 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 968 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
882 _ ("Failed to parse configuration file `%s'\n"), 969 _ ("Failed to parse configuration file `%s'\n"),
@@ -1036,6 +1123,36 @@ GNUNET_CONFIGURATION_serialize_diagnostics (const struct
1036{ 1123{
1037 struct GNUNET_Buffer buf = { 0 }; 1124 struct GNUNET_Buffer buf = { 0 };
1038 1125
1126 GNUNET_buffer_write_fstr (&buf,
1127 "#\n# Configuration file diagnostics\n#\n");
1128 GNUNET_buffer_write_fstr (&buf,
1129 "# Entry point: %s\n",
1130 cfg->main_filename ? cfg->main_filename :
1131 "<input>");
1132 GNUNET_buffer_write_fstr (&buf,
1133 "#\n# Files Loaded:\n");
1134
1135 for (struct ConfigFile *cfil = cfg->loaded_files_head;
1136 NULL != cfil;
1137 cfil = cfil->next)
1138 {
1139 GNUNET_buffer_write_fstr (&buf,
1140 "# ");
1141 for (unsigned int i = 0; i < cfil->level; i++)
1142 GNUNET_buffer_write_fstr (&buf,
1143 "+");
1144 if (0 != cfil->level)
1145 GNUNET_buffer_write_fstr (&buf,
1146 " ");
1147
1148 GNUNET_buffer_write_fstr (&buf,
1149 "%s\n",
1150 cfil->source_filename);
1151 }
1152
1153 GNUNET_buffer_write_fstr (&buf,
1154 "#\n\n");
1155
1039 for (struct ConfigSection *sec = cfg->sections; 1156 for (struct ConfigSection *sec = cfg->sections;
1040 NULL != sec; 1157 NULL != sec;
1041 sec = sec->next) 1158 sec = sec->next)
@@ -2059,41 +2176,51 @@ GNUNET_CONFIGURATION_remove_value_filename (
2059} 2176}
2060 2177
2061 2178
2062/**
2063 * Wrapper around #GNUNET_CONFIGURATION_parse. Called on each
2064 * file in a directory, we trigger parsing on those files that
2065 * end with ".conf".
2066 *
2067 * @param cls the cfg
2068 * @param filename file to parse
2069 * @return #GNUNET_OK on success
2070 */
2071static enum GNUNET_GenericReturnValue
2072parse_configuration_file (void *cls, const char *filename)
2073{
2074 struct GNUNET_CONFIGURATION_Handle *cfg = cls;
2075 char *ext;
2076
2077 /* Examine file extension */
2078 ext = strrchr (filename, '.');
2079 if ((NULL == ext) || (0 != strcmp (ext, ".conf")))
2080 {
2081 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Skipping file `%s'\n", filename);
2082 return GNUNET_OK;
2083 }
2084
2085 return GNUNET_CONFIGURATION_parse (cfg, filename);
2086}
2087
2088
2089enum GNUNET_GenericReturnValue 2179enum GNUNET_GenericReturnValue
2090GNUNET_CONFIGURATION_load_from (struct GNUNET_CONFIGURATION_Handle *cfg, 2180GNUNET_CONFIGURATION_load_from (struct GNUNET_CONFIGURATION_Handle *cfg,
2091 const char *defaults_d) 2181 const char *defaults_d)
2092{ 2182{
2183 struct CollectFilesContext files_context = {
2184 .files = NULL,
2185 .files_length = 0,
2186 };
2187 enum GNUNET_GenericReturnValue fun_ret;
2188
2093 if (GNUNET_SYSERR == 2189 if (GNUNET_SYSERR ==
2094 GNUNET_DISK_directory_scan (defaults_d, &parse_configuration_file, cfg)) 2190 GNUNET_DISK_directory_scan (defaults_d, &collect_files_cb,
2191 &files_context))
2095 return GNUNET_SYSERR; /* no configuration at all found */ 2192 return GNUNET_SYSERR; /* no configuration at all found */
2096 return GNUNET_OK; 2193 qsort (files_context.files,
2194 files_context.files_length,
2195 sizeof (char *),
2196 pstrcmp);
2197 for (unsigned int i = 0; i < files_context.files_length; i++)
2198 {
2199 char *ext;
2200 const char *filename = files_context.files[i];
2201
2202 /* Examine file extension */
2203 ext = strrchr (filename, '.');
2204 if ((NULL == ext) || (0 != strcmp (ext, ".conf")))
2205 {
2206 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Skipping file `%s'\n", filename);
2207 fun_ret = GNUNET_OK;
2208 goto cleanup;
2209 }
2210 fun_ret = GNUNET_CONFIGURATION_parse (cfg, filename);
2211 if (fun_ret != GNUNET_OK)
2212 break;
2213 }
2214 cleanup:
2215 if (files_context.files_length > 0)
2216 {
2217 for (size_t i = 0; i < files_context.files_length; i++)
2218 GNUNET_free (files_context.files[i]);
2219 GNUNET_array_grow (files_context.files,
2220 files_context.files_length,
2221 0);
2222 }
2223 return fun_ret;
2097} 2224}
2098 2225
2099 2226
@@ -2158,5 +2285,71 @@ GNUNET_CONFIGURATION_default (void)
2158 return cfg; 2285 return cfg;
2159} 2286}
2160 2287
2288/**
2289 * Load configuration (starts with defaults, then loads
2290 * system-specific configuration).
2291 *
2292 * @param cfg configuration to update
2293 * @param filename name of the configuration file, NULL to load defaults
2294 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
2295 */
2296int
2297GNUNET_CONFIGURATION_load (struct GNUNET_CONFIGURATION_Handle *cfg,
2298 const char *filename)
2299{
2300 char *baseconfig;
2301 const char *base_config_varname;
2302
2303 if (cfg->load_called)
2304 {
2305 /* FIXME: Make this a GNUNET_assert later */
2306 GNUNET_break (0);
2307 GNUNET_free (cfg->main_filename);
2308 }
2309 cfg->load_called = true;
2310 if (NULL != filename)
2311 cfg->main_filename = GNUNET_strdup (filename);
2312
2313 base_config_varname = GNUNET_OS_project_data_get ()->base_config_varname;
2314
2315 if ((NULL != base_config_varname)
2316 && (NULL != (baseconfig = getenv (base_config_varname))))
2317 {
2318 baseconfig = GNUNET_strdup (baseconfig);
2319 }
2320 else
2321 {
2322 char *ipath;
2323
2324 ipath = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR);
2325 if (NULL == ipath)
2326 return GNUNET_SYSERR;
2327 GNUNET_asprintf (&baseconfig, "%s%s", ipath, "config.d");
2328 GNUNET_free (ipath);
2329 }
2330
2331 char *dname = GNUNET_STRINGS_filename_expand (baseconfig);
2332 GNUNET_free (baseconfig);
2333
2334 if ((GNUNET_YES == GNUNET_DISK_directory_test (dname, GNUNET_YES))&&
2335 (GNUNET_SYSERR == GNUNET_CONFIGURATION_load_from (cfg, dname)))
2336 {
2337 GNUNET_free (dname);
2338 return GNUNET_SYSERR; /* no configuration at all found */
2339 }
2340 GNUNET_free (dname);
2341 if ((NULL != filename) &&
2342 (GNUNET_OK != GNUNET_CONFIGURATION_parse (cfg, filename)))
2343 {
2344 /* specified configuration not found */
2345 return GNUNET_SYSERR;
2346 }
2347 if (((GNUNET_YES !=
2348 GNUNET_CONFIGURATION_have_value (cfg, "PATHS", "DEFAULTCONFIG"))) &&
2349 (filename != NULL))
2350 GNUNET_CONFIGURATION_set_value_string (cfg, "PATHS", "DEFAULTCONFIG",
2351 filename);
2352 return GNUNET_OK;
2353}
2161 2354
2162/* end of configuration.c */ 2355/* end of configuration.c */