diff options
author | Florian Dold <florian@dold.me> | 2021-07-28 17:34:44 +0200 |
---|---|---|
committer | Florian Dold <florian@dold.me> | 2021-07-28 17:35:15 +0200 |
commit | 7a0caef7a7b1a3fe2949b6a0462125471905540b (patch) | |
tree | c1bcd66710e7aa7cc8a264016609b8a4a9f85ddd /src/util | |
parent | 8593b269709c6c328cad98e5f494e0339def8e62 (diff) | |
download | gnunet-7a0caef7a7b1a3fe2949b6a0462125471905540b.tar.gz gnunet-7a0caef7a7b1a3fe2949b6a0462125471905540b.zip |
diagnostics mode for gnunet-config
Diffstat (limited to 'src/util')
-rw-r--r-- | src/util/configuration.c | 271 | ||||
-rw-r--r-- | src/util/gnunet-config.c | 49 |
2 files changed, 250 insertions, 70 deletions
diff --git a/src/util/configuration.c b/src/util/configuration.c index 06938be67..6178ab68e 100644 --- a/src/util/configuration.c +++ b/src/util/configuration.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include "gnunet_os_lib.h" | 28 | #include "gnunet_os_lib.h" |
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 | 32 | ||
32 | #define LOG(kind, ...) GNUNET_log_from (kind, "util", __VA_ARGS__) | 33 | #define LOG(kind, ...) GNUNET_log_from (kind, "util", __VA_ARGS__) |
33 | 34 | ||
@@ -53,6 +54,16 @@ struct ConfigEntry | |||
53 | * current, committed value | 54 | * current, committed value |
54 | */ | 55 | */ |
55 | char *val; | 56 | char *val; |
57 | |||
58 | /** | ||
59 | * Diagnostics information for the filename. | ||
60 | */ | ||
61 | char *hint_filename; | ||
62 | |||
63 | /** | ||
64 | * Diagnostics information for the line number. | ||
65 | */ | ||
66 | unsigned int hint_lineno; | ||
56 | }; | 67 | }; |
57 | 68 | ||
58 | 69 | ||
@@ -83,6 +94,21 @@ struct ConfigSection | |||
83 | * directive, but the referenced file can't be found or accessed. | 94 | * directive, but the referenced file can't be found or accessed. |
84 | */ | 95 | */ |
85 | bool inaccessible; | 96 | bool inaccessible; |
97 | |||
98 | /** | ||
99 | * Diagnostics hint for the inaccessible file. | ||
100 | */ | ||
101 | char *hint_secret_filename; | ||
102 | |||
103 | /** | ||
104 | * For secret sections: Where was this inlined from? | ||
105 | */ | ||
106 | char *hint_inlined_from_filename; | ||
107 | |||
108 | /** | ||
109 | * For secret sections: Where was this inlined from? | ||
110 | */ | ||
111 | unsigned int hint_inlined_from_line; | ||
86 | }; | 112 | }; |
87 | 113 | ||
88 | 114 | ||
@@ -97,6 +123,11 @@ struct GNUNET_CONFIGURATION_Handle | |||
97 | struct ConfigSection *sections; | 123 | struct ConfigSection *sections; |
98 | 124 | ||
99 | /** | 125 | /** |
126 | * Enable diagnostics. | ||
127 | */ | ||
128 | bool diagnostics; | ||
129 | |||
130 | /** | ||
100 | * Modification indication since last save | 131 | * Modification indication since last save |
101 | * #GNUNET_NO if clean, #GNUNET_YES if dirty, | 132 | * #GNUNET_NO if clean, #GNUNET_YES if dirty, |
102 | * #GNUNET_SYSERR on error (i.e. last save failed) | 133 | * #GNUNET_SYSERR on error (i.e. last save failed) |
@@ -122,6 +153,14 @@ struct DiffHandle | |||
122 | }; | 153 | }; |
123 | 154 | ||
124 | 155 | ||
156 | void | ||
157 | GNUNET_CONFIGURATION_enable_diagnostics (struct | ||
158 | GNUNET_CONFIGURATION_Handle *cfg) | ||
159 | { | ||
160 | cfg->diagnostics = true; | ||
161 | } | ||
162 | |||
163 | |||
125 | struct GNUNET_CONFIGURATION_Handle * | 164 | struct GNUNET_CONFIGURATION_Handle * |
126 | GNUNET_CONFIGURATION_create () | 165 | GNUNET_CONFIGURATION_create () |
127 | { | 166 | { |
@@ -300,27 +339,6 @@ find_section (const struct GNUNET_CONFIGURATION_Handle *cfg, | |||
300 | } | 339 | } |
301 | 340 | ||
302 | 341 | ||
303 | static void | ||
304 | set_section_inaccessible (struct GNUNET_CONFIGURATION_Handle *cfg, | ||
305 | const char *section) | ||
306 | { | ||
307 | struct ConfigSection *sec; | ||
308 | |||
309 | sec = find_section (cfg, section); | ||
310 | |||
311 | if (NULL == sec) | ||
312 | { | ||
313 | sec = GNUNET_new (struct ConfigSection); | ||
314 | sec->name = GNUNET_strdup (section); | ||
315 | sec->next = cfg->sections; | ||
316 | cfg->sections = sec; | ||
317 | sec->entries = NULL; | ||
318 | } | ||
319 | |||
320 | sec->inaccessible = true; | ||
321 | } | ||
322 | |||
323 | |||
324 | /** | 342 | /** |
325 | * Handle an inline directive. | 343 | * Handle an inline directive. |
326 | * | 344 | * |
@@ -331,7 +349,8 @@ handle_inline (struct GNUNET_CONFIGURATION_Handle *cfg, | |||
331 | const char *path_or_glob, | 349 | const char *path_or_glob, |
332 | bool path_is_glob, | 350 | bool path_is_glob, |
333 | const char *restrict_section, | 351 | const char *restrict_section, |
334 | const char *source_filename) | 352 | const char *source_filename, |
353 | unsigned int source_lineno) | ||
335 | { | 354 | { |
336 | char *inline_path; | 355 | char *inline_path; |
337 | 356 | ||
@@ -399,9 +418,30 @@ handle_inline (struct GNUNET_CONFIGURATION_Handle *cfg, | |||
399 | 418 | ||
400 | fret = GNUNET_DISK_file_test_read (inline_path); | 419 | fret = GNUNET_DISK_file_test_read (inline_path); |
401 | 420 | ||
421 | cs = find_section (cfg, restrict_section); | ||
422 | |||
423 | if (NULL == cs) | ||
424 | { | ||
425 | cs = GNUNET_new (struct ConfigSection); | ||
426 | cs->name = GNUNET_strdup (restrict_section); | ||
427 | cs->next = cfg->sections; | ||
428 | cfg->sections = cs; | ||
429 | cs->entries = NULL; | ||
430 | } | ||
431 | if (cfg->diagnostics) | ||
432 | { | ||
433 | if (NULL != inline_path) | ||
434 | cs->hint_secret_filename = GNUNET_strdup (inline_path); | ||
435 | if (source_filename) | ||
436 | { | ||
437 | cs->hint_inlined_from_filename = GNUNET_strdup (source_filename); | ||
438 | cs->hint_inlined_from_line = source_lineno; | ||
439 | } | ||
440 | } | ||
441 | |||
402 | if (GNUNET_OK != fret) | 442 | if (GNUNET_OK != fret) |
403 | { | 443 | { |
404 | set_section_inaccessible (cfg, restrict_section); | 444 | cs->inaccessible = true; |
405 | GNUNET_free (inline_path); | 445 | GNUNET_free (inline_path); |
406 | return GNUNET_OK; | 446 | return GNUNET_OK; |
407 | } | 447 | } |
@@ -447,6 +487,67 @@ handle_inline (struct GNUNET_CONFIGURATION_Handle *cfg, | |||
447 | } | 487 | } |
448 | 488 | ||
449 | 489 | ||
490 | /** | ||
491 | * Find an entry from a configuration. | ||
492 | * | ||
493 | * @param cfg handle to the configuration | ||
494 | * @param section section the option is in | ||
495 | * @param key the option | ||
496 | * @return matching entry, NULL if not found | ||
497 | */ | ||
498 | static struct ConfigEntry * | ||
499 | find_entry (const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
500 | const char *section, | ||
501 | const char *key) | ||
502 | { | ||
503 | struct ConfigSection *sec; | ||
504 | struct ConfigEntry *pos; | ||
505 | |||
506 | if (NULL == (sec = find_section (cfg, section))) | ||
507 | return NULL; | ||
508 | if (sec->inaccessible) | ||
509 | { | ||
510 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
511 | "Section '%s' is marked as inaccessible, because the configuration " | ||
512 | " file that contains the section can't be read. Attempts to use " | ||
513 | "option '%s' will fail.\n", | ||
514 | section, | ||
515 | key); | ||
516 | return NULL; | ||
517 | } | ||
518 | pos = sec->entries; | ||
519 | while ((pos != NULL) && (0 != strcasecmp (key, pos->key))) | ||
520 | pos = pos->next; | ||
521 | return pos; | ||
522 | } | ||
523 | |||
524 | |||
525 | /** | ||
526 | * Set a configuration hint. | ||
527 | * | ||
528 | * @param cfg configuration handle | ||
529 | * @param section section | ||
530 | * @param option config option | ||
531 | * @param hint_filename | ||
532 | * @param hint_line | ||
533 | */ | ||
534 | static void | ||
535 | set_entry_hint (struct GNUNET_CONFIGURATION_Handle *cfg, | ||
536 | const char *section, | ||
537 | const char *option, | ||
538 | const char *hint_filename, | ||
539 | unsigned int hint_line) | ||
540 | { | ||
541 | struct ConfigEntry *e = find_entry (cfg, section, option); | ||
542 | if (! cfg->diagnostics) | ||
543 | return; | ||
544 | if (! e) | ||
545 | return; | ||
546 | e->hint_filename = GNUNET_strdup (hint_filename); | ||
547 | e->hint_lineno = hint_line; | ||
548 | } | ||
549 | |||
550 | |||
450 | enum GNUNET_GenericReturnValue | 551 | enum GNUNET_GenericReturnValue |
451 | GNUNET_CONFIGURATION_deserialize (struct GNUNET_CONFIGURATION_Handle *cfg, | 552 | GNUNET_CONFIGURATION_deserialize (struct GNUNET_CONFIGURATION_Handle *cfg, |
452 | const char *mem, | 553 | const char *mem, |
@@ -553,7 +654,8 @@ GNUNET_CONFIGURATION_deserialize (struct GNUNET_CONFIGURATION_Handle *cfg, | |||
553 | path, | 654 | path, |
554 | false, | 655 | false, |
555 | NULL, | 656 | NULL, |
556 | source_filename); | 657 | source_filename, |
658 | nr); | ||
557 | } | 659 | } |
558 | else if (0 == strcasecmp (directive, "INLINE-MATCHING")) | 660 | else if (0 == strcasecmp (directive, "INLINE-MATCHING")) |
559 | { | 661 | { |
@@ -567,7 +669,8 @@ GNUNET_CONFIGURATION_deserialize (struct GNUNET_CONFIGURATION_Handle *cfg, | |||
567 | path, | 669 | path, |
568 | true, | 670 | true, |
569 | NULL, | 671 | NULL, |
570 | source_filename); | 672 | source_filename, |
673 | nr); | ||
571 | } | 674 | } |
572 | else if (0 == strcasecmp (directive, "INLINE-SECRET")) | 675 | else if (0 == strcasecmp (directive, "INLINE-SECRET")) |
573 | { | 676 | { |
@@ -600,7 +703,8 @@ GNUNET_CONFIGURATION_deserialize (struct GNUNET_CONFIGURATION_Handle *cfg, | |||
600 | path, | 703 | path, |
601 | false, | 704 | false, |
602 | secname, | 705 | secname, |
603 | source_filename); | 706 | source_filename, |
707 | nr); | ||
604 | } | 708 | } |
605 | else | 709 | else |
606 | { | 710 | { |
@@ -660,6 +764,14 @@ GNUNET_CONFIGURATION_deserialize (struct GNUNET_CONFIGURATION_Handle *cfg, | |||
660 | value++; | 764 | value++; |
661 | } | 765 | } |
662 | GNUNET_CONFIGURATION_set_value_string (cfg, section, tag, &value[i]); | 766 | GNUNET_CONFIGURATION_set_value_string (cfg, section, tag, &value[i]); |
767 | if (cfg->diagnostics) | ||
768 | { | ||
769 | set_entry_hint (cfg, | ||
770 | section, | ||
771 | tag, | ||
772 | source_filename ? source_filename : "<input>", | ||
773 | nr); | ||
774 | } | ||
663 | GNUNET_free (tag); | 775 | GNUNET_free (tag); |
664 | continue; | 776 | continue; |
665 | } | 777 | } |
@@ -799,6 +911,8 @@ GNUNET_CONFIGURATION_serialize (const struct GNUNET_CONFIGURATION_Handle *cfg, | |||
799 | NULL != sec; | 911 | NULL != sec; |
800 | sec = sec->next) | 912 | sec = sec->next) |
801 | { | 913 | { |
914 | if (sec->inaccessible) | ||
915 | continue; | ||
802 | /* For each section we need to add 3 characters: {'[',']','\n'} */ | 916 | /* For each section we need to add 3 characters: {'[',']','\n'} */ |
803 | m_size += strlen (sec->name) + 3; | 917 | m_size += strlen (sec->name) + 3; |
804 | for (struct ConfigEntry *ent = sec->entries; | 918 | for (struct ConfigEntry *ent = sec->entries; |
@@ -877,6 +991,73 @@ GNUNET_CONFIGURATION_serialize (const struct GNUNET_CONFIGURATION_Handle *cfg, | |||
877 | return mem; | 991 | return mem; |
878 | } | 992 | } |
879 | 993 | ||
994 | char * | ||
995 | GNUNET_CONFIGURATION_serialize_diagnostics (const struct | ||
996 | GNUNET_CONFIGURATION_Handle *cfg) | ||
997 | { | ||
998 | struct GNUNET_Buffer buf = { 0 }; | ||
999 | |||
1000 | for (struct ConfigSection *sec = cfg->sections; | ||
1001 | NULL != sec; | ||
1002 | sec = sec->next) | ||
1003 | { | ||
1004 | if (sec->hint_secret_filename) | ||
1005 | GNUNET_buffer_write_fstr (&buf, | ||
1006 | "# secret section from %s\n", | ||
1007 | sec->hint_secret_filename); | ||
1008 | if (sec->hint_inlined_from_filename) | ||
1009 | { | ||
1010 | GNUNET_buffer_write_fstr (&buf, | ||
1011 | "# inlined from %s:%u\n", | ||
1012 | sec->hint_inlined_from_filename, | ||
1013 | sec->hint_inlined_from_line); | ||
1014 | } | ||
1015 | GNUNET_buffer_write_fstr (&buf, | ||
1016 | "[%s]\n", | ||
1017 | sec->name); | ||
1018 | if (sec->inaccessible) | ||
1019 | { | ||
1020 | GNUNET_buffer_write_fstr (&buf, | ||
1021 | "# <section contents inaccessible>\n\n"); | ||
1022 | continue; | ||
1023 | } | ||
1024 | for (struct ConfigEntry *ent = sec->entries; | ||
1025 | NULL != ent; | ||
1026 | ent = ent->next) | ||
1027 | { | ||
1028 | if (do_skip (sec->name, | ||
1029 | ent->key)) | ||
1030 | continue; | ||
1031 | if (NULL != ent->val) | ||
1032 | { | ||
1033 | char *pos; | ||
1034 | char *val = GNUNET_malloc (strlen (ent->val) * 2 + 1); | ||
1035 | strcpy (val, ent->val); | ||
1036 | while (NULL != (pos = strstr (val, "\n"))) | ||
1037 | { | ||
1038 | memmove (&pos[2], &pos[1], strlen (&pos[1])); | ||
1039 | pos[0] = '\\'; | ||
1040 | pos[1] = 'n'; | ||
1041 | } | ||
1042 | if (NULL != ent->hint_filename) | ||
1043 | { | ||
1044 | GNUNET_buffer_write_fstr (&buf, | ||
1045 | "# %s:%u\n", | ||
1046 | ent->hint_filename, | ||
1047 | ent->hint_lineno); | ||
1048 | } | ||
1049 | GNUNET_buffer_write_fstr (&buf, | ||
1050 | "%s = %s\n", | ||
1051 | ent->key, | ||
1052 | val); | ||
1053 | GNUNET_free (val); | ||
1054 | } | ||
1055 | GNUNET_buffer_write_str (&buf, "\n"); | ||
1056 | } | ||
1057 | GNUNET_buffer_write_str (&buf, "\n"); | ||
1058 | } | ||
1059 | return GNUNET_buffer_reap_str (&buf); | ||
1060 | } | ||
880 | 1061 | ||
881 | enum GNUNET_GenericReturnValue | 1062 | enum GNUNET_GenericReturnValue |
882 | GNUNET_CONFIGURATION_write (struct GNUNET_CONFIGURATION_Handle *cfg, | 1063 | GNUNET_CONFIGURATION_write (struct GNUNET_CONFIGURATION_Handle *cfg, |
@@ -1028,10 +1209,13 @@ GNUNET_CONFIGURATION_remove_section (struct GNUNET_CONFIGURATION_Handle *cfg, | |||
1028 | spos->entries = ent->next; | 1209 | spos->entries = ent->next; |
1029 | GNUNET_free (ent->key); | 1210 | GNUNET_free (ent->key); |
1030 | GNUNET_free (ent->val); | 1211 | GNUNET_free (ent->val); |
1212 | GNUNET_free (ent->hint_filename); | ||
1031 | GNUNET_free (ent); | 1213 | GNUNET_free (ent); |
1032 | cfg->dirty = GNUNET_YES; | 1214 | cfg->dirty = GNUNET_YES; |
1033 | } | 1215 | } |
1034 | GNUNET_free (spos->name); | 1216 | GNUNET_free (spos->name); |
1217 | GNUNET_free (spos->hint_secret_filename); | ||
1218 | GNUNET_free (spos->hint_inlined_from_filename); | ||
1035 | GNUNET_free (spos); | 1219 | GNUNET_free (spos); |
1036 | return; | 1220 | return; |
1037 | } | 1221 | } |
@@ -1074,41 +1258,6 @@ GNUNET_CONFIGURATION_dup (const struct GNUNET_CONFIGURATION_Handle *cfg) | |||
1074 | 1258 | ||
1075 | 1259 | ||
1076 | /** | 1260 | /** |
1077 | * Find an entry from a configuration. | ||
1078 | * | ||
1079 | * @param cfg handle to the configuration | ||
1080 | * @param section section the option is in | ||
1081 | * @param key the option | ||
1082 | * @return matching entry, NULL if not found | ||
1083 | */ | ||
1084 | static struct ConfigEntry * | ||
1085 | find_entry (const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
1086 | const char *section, | ||
1087 | const char *key) | ||
1088 | { | ||
1089 | struct ConfigSection *sec; | ||
1090 | struct ConfigEntry *pos; | ||
1091 | |||
1092 | if (NULL == (sec = find_section (cfg, section))) | ||
1093 | return NULL; | ||
1094 | if (sec->inaccessible) | ||
1095 | { | ||
1096 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
1097 | "Section '%s' is marked as inaccessible, because the configuration " | ||
1098 | " file that contains the section can't be read. Attempts to use " | ||
1099 | "option '%s' will fail.\n", | ||
1100 | section, | ||
1101 | key); | ||
1102 | return NULL; | ||
1103 | } | ||
1104 | pos = sec->entries; | ||
1105 | while ((pos != NULL) && (0 != strcasecmp (key, pos->key))) | ||
1106 | pos = pos->next; | ||
1107 | return pos; | ||
1108 | } | ||
1109 | |||
1110 | |||
1111 | /** | ||
1112 | * A callback function, compares entries from two configurations | 1261 | * A callback function, compares entries from two configurations |
1113 | * (default against a new configuration) and write the diffs in a | 1262 | * (default against a new configuration) and write the diffs in a |
1114 | * diff-configuration object (the callback object). | 1263 | * diff-configuration object (the callback object). |
diff --git a/src/util/gnunet-config.c b/src/util/gnunet-config.c index 3932ff1bf..20fd44c65 100644 --- a/src/util/gnunet-config.c +++ b/src/util/gnunet-config.c | |||
@@ -70,6 +70,12 @@ static int global_ret; | |||
70 | static int rewrite; | 70 | static int rewrite; |
71 | 71 | ||
72 | /** | 72 | /** |
73 | * Should we give extra diagnostics? | ||
74 | */ | ||
75 | static int diagnostics; | ||
76 | |||
77 | |||
78 | /** | ||
73 | * Should the generated configuration file contain the whole configuration? | 79 | * Should the generated configuration file contain the whole configuration? |
74 | */ | 80 | */ |
75 | static int full; | 81 | static int full; |
@@ -162,6 +168,18 @@ run (void *cls, | |||
162 | GNUNET_free (name); | 168 | GNUNET_free (name); |
163 | return; | 169 | return; |
164 | } | 170 | } |
171 | |||
172 | if (diagnostics) | ||
173 | { | ||
174 | struct GNUNET_CONFIGURATION_Handle *ncfg; | ||
175 | /* Re-parse the configuration with diagnostics enabled. */ | ||
176 | GNUNET_assert (NULL != cfgfile); | ||
177 | ncfg = GNUNET_CONFIGURATION_create (); | ||
178 | GNUNET_CONFIGURATION_enable_diagnostics (ncfg); | ||
179 | GNUNET_CONFIGURATION_load (ncfg, cfgfile); | ||
180 | cfg = ncfg; | ||
181 | } | ||
182 | |||
165 | if (full) | 183 | if (full) |
166 | rewrite = GNUNET_YES; | 184 | rewrite = GNUNET_YES; |
167 | if (list_sections) | 185 | if (list_sections) |
@@ -176,16 +194,23 @@ run (void *cls, | |||
176 | if ( (! rewrite) && | 194 | if ( (! rewrite) && |
177 | (NULL == section) ) | 195 | (NULL == section) ) |
178 | { | 196 | { |
179 | fprintf (stderr, | 197 | char *ser; |
180 | _ ("%s or %s argument is required\n"), | 198 | if (! diagnostics) |
181 | "--section", | 199 | { |
182 | "--list-sections"); | 200 | fprintf (stderr, |
183 | global_ret = 1; | 201 | _ ("%s, %s or %s argument is required\n"), |
184 | return; | 202 | "--section", |
203 | "--list-sections", | ||
204 | "--diagnostics"); | ||
205 | global_ret = 1; | ||
206 | return; | ||
207 | } | ||
208 | ser = GNUNET_CONFIGURATION_serialize_diagnostics (cfg); | ||
209 | printf ("%s", ser); | ||
210 | GNUNET_free (ser); | ||
185 | } | 211 | } |
186 | 212 | else if ( (NULL != section) && | |
187 | if ( (NULL != section) && | 213 | (NULL == value) ) |
188 | (NULL == value) ) | ||
189 | { | 214 | { |
190 | if (NULL == option) | 215 | if (NULL == option) |
191 | { | 216 | { |
@@ -348,6 +373,12 @@ main (int argc, char *const *argv) | |||
348 | gettext_noop ( | 373 | gettext_noop ( |
349 | "rewrite the configuration file, even if nothing changed"), | 374 | "rewrite the configuration file, even if nothing changed"), |
350 | &rewrite), | 375 | &rewrite), |
376 | GNUNET_GETOPT_option_flag ( | ||
377 | 'd', | ||
378 | "diagnostics", | ||
379 | gettext_noop ( | ||
380 | "output extra diagnostics"), | ||
381 | &diagnostics), | ||
351 | GNUNET_GETOPT_option_flag ('S', | 382 | GNUNET_GETOPT_option_flag ('S', |
352 | "list-sections", | 383 | "list-sections", |
353 | gettext_noop ( | 384 | gettext_noop ( |