aboutsummaryrefslogtreecommitdiff
path: root/src/util/configuration.c
diff options
context:
space:
mode:
authorFlorian Dold <florian@dold.me>2021-07-28 17:34:44 +0200
committerFlorian Dold <florian@dold.me>2021-07-28 17:35:15 +0200
commit7a0caef7a7b1a3fe2949b6a0462125471905540b (patch)
treec1bcd66710e7aa7cc8a264016609b8a4a9f85ddd /src/util/configuration.c
parent8593b269709c6c328cad98e5f494e0339def8e62 (diff)
downloadgnunet-7a0caef7a7b1a3fe2949b6a0462125471905540b.tar.gz
gnunet-7a0caef7a7b1a3fe2949b6a0462125471905540b.zip
diagnostics mode for gnunet-config
Diffstat (limited to 'src/util/configuration.c')
-rw-r--r--src/util/configuration.c271
1 files changed, 210 insertions, 61 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
156void
157GNUNET_CONFIGURATION_enable_diagnostics (struct
158 GNUNET_CONFIGURATION_Handle *cfg)
159{
160 cfg->diagnostics = true;
161}
162
163
125struct GNUNET_CONFIGURATION_Handle * 164struct GNUNET_CONFIGURATION_Handle *
126GNUNET_CONFIGURATION_create () 165GNUNET_CONFIGURATION_create ()
127{ 166{
@@ -300,27 +339,6 @@ find_section (const struct GNUNET_CONFIGURATION_Handle *cfg,
300} 339}
301 340
302 341
303static void
304set_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 */
498static struct ConfigEntry *
499find_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 */
534static void
535set_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
450enum GNUNET_GenericReturnValue 551enum GNUNET_GenericReturnValue
451GNUNET_CONFIGURATION_deserialize (struct GNUNET_CONFIGURATION_Handle *cfg, 552GNUNET_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
994char *
995GNUNET_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
881enum GNUNET_GenericReturnValue 1062enum GNUNET_GenericReturnValue
882GNUNET_CONFIGURATION_write (struct GNUNET_CONFIGURATION_Handle *cfg, 1063GNUNET_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 */
1084static struct ConfigEntry *
1085find_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).