tor  0.4.2.0-alpha-dev
confparse.c
Go to the documentation of this file.
1 /* Copyright (c) 2001 Matej Pfajfar.
2  * Copyright (c) 2001-2004, Roger Dingledine.
3  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
4  * Copyright (c) 2007-2019, The Tor Project, Inc. */
5 /* See LICENSE for licensing information */
6 
24 #define CONFPARSE_PRIVATE
25 #include "orconfig.h"
26 #include "lib/confmgt/confparse.h"
27 
28 #include "lib/confmgt/structvar.h"
29 #include "lib/confmgt/unitparse.h"
30 #include "lib/container/bitarray.h"
32 #include "lib/encoding/confline.h"
33 #include "lib/log/escape.h"
34 #include "lib/log/log.h"
35 #include "lib/log/util_bug.h"
37 #include "lib/string/printf.h"
38 #include "lib/string/util_string.h"
39 
40 #include "ext/siphash.h"
41 
46 typedef struct managed_var_t {
57 
58 static void config_reset(const config_mgr_t *fmt, void *options,
59  const managed_var_t *var, int use_defaults);
60 static void config_mgr_register_fmt(config_mgr_t *mgr,
61  const config_format_t *fmt,
62  int object_idx);
63 
65 static void
67 {
68  if (!mv)
69  return;
70  tor_free(mv);
71 }
72 #define managed_var_free(mv) \
73  FREE_AND_NULL(managed_var_t, managed_var_free_, (mv))
74 
80 };
81 
85 static config_suite_t *
87 {
88  config_suite_t *suite = tor_malloc_zero(sizeof(config_suite_t));
89  suite->configs = smartlist_new();
90  return suite;
91 }
92 
95 static void
97 {
98  if (!suite)
99  return;
100  smartlist_free(suite->configs);
101  tor_free(suite);
102 }
103 
104 #define config_suite_free(suite) \
105  FREE_AND_NULL(config_suite_t, config_suite_free_, (suite))
106 
107 struct config_mgr_t {
131  bool frozen;
138 };
139 
140 #define IDX_TOPLEVEL (-1)
141 
144 config_mgr_t *
145 config_mgr_new(const config_format_t *toplevel_fmt)
146 {
147  config_mgr_t *mgr = tor_malloc_zero(sizeof(config_mgr_t));
148  mgr->subconfigs = smartlist_new();
149  mgr->all_vars = smartlist_new();
150  mgr->all_abbrevs = smartlist_new();
151  mgr->all_deprecations = smartlist_new();
152 
153  config_mgr_register_fmt(mgr, toplevel_fmt, IDX_TOPLEVEL);
154  mgr->toplevel = toplevel_fmt;
155 
156  return mgr;
157 }
158 
160 static void
162  const config_format_t *fmt,
163  int object_idx)
164 {
165  int i;
166 
167  tor_assertf(!mgr->frozen,
168  "Tried to add a format to a configuration manager after "
169  "it had been frozen.");
170 
171  if (object_idx != IDX_TOPLEVEL) {
172  tor_assertf(fmt->config_suite_offset < 0,
173  "Tried to register a toplevel format in a non-toplevel position");
174  }
175  tor_assertf(fmt != mgr->toplevel &&
176  ! smartlist_contains(mgr->subconfigs, fmt),
177  "Tried to register an already-registered format.");
178 
179  /* register variables */
180  for (i = 0; fmt->vars[i].member.name; ++i) {
181  managed_var_t *mv = tor_malloc_zero(sizeof(managed_var_t));
182  mv->cvar = &fmt->vars[i];
183  mv->object_idx = object_idx;
184  smartlist_add(mgr->all_vars, mv);
185  }
186 
187  /* register abbrevs */
188  if (fmt->abbrevs) {
189  for (i = 0; fmt->abbrevs[i].abbreviated; ++i) {
190  smartlist_add(mgr->all_abbrevs, (void*)&fmt->abbrevs[i]);
191  }
192  }
193 
194  /* register deprecations. */
195  if (fmt->deprecations) {
196  const config_deprecation_t *d;
197  for (d = fmt->deprecations; d->name; ++d) {
198  smartlist_add(mgr->all_deprecations, (void*)d);
199  }
200  }
201 }
202 
210 int
212  const config_format_t *fmt)
213 {
214  tor_assert(mgr);
215  int idx = smartlist_len(mgr->subconfigs);
216  config_mgr_register_fmt(mgr, fmt, idx);
217  smartlist_add(mgr->subconfigs, (void *)fmt);
218  return idx;
219 }
220 
223 static inline config_suite_t **
224 config_mgr_get_suite_ptr(const config_mgr_t *mgr, void *toplevel)
225 {
226  if (mgr->toplevel->config_suite_offset < 0)
227  return NULL;
228  return STRUCT_VAR_P(toplevel, mgr->toplevel->config_suite_offset);
229 }
230 
240 STATIC void *
241 config_mgr_get_obj_mutable(const config_mgr_t *mgr, void *toplevel, int idx)
242 {
243  tor_assert(mgr);
244  tor_assert(toplevel);
245  if (idx == IDX_TOPLEVEL)
246  return toplevel;
247 
248  tor_assertf(idx >= 0 && idx < smartlist_len(mgr->subconfigs),
249  "Index %d is out of range.", idx);
250  config_suite_t **suite = config_mgr_get_suite_ptr(mgr, toplevel);
251  tor_assert(suite);
252  tor_assert(smartlist_len(mgr->subconfigs) ==
253  smartlist_len((*suite)->configs));
254 
255  return smartlist_get((*suite)->configs, idx);
256 }
257 
259 STATIC const void *
260 config_mgr_get_obj(const config_mgr_t *mgr, const void *toplevel, int idx)
261 {
262  return config_mgr_get_obj_mutable(mgr, (void*)toplevel, idx);
263 }
264 
266 static int
267 managed_var_cmp(const void **a, const void **b)
268 {
269  const managed_var_t *mv1 = *(const managed_var_t**)a;
270  const managed_var_t *mv2 = *(const managed_var_t**)b;
271 
272  return strcasecmp(mv1->cvar->member.name, mv2->cvar->member.name);
273 }
274 
279 void
281 {
282  static uint64_t mgr_count = 0;
283 
285  memcpy(&mgr->toplevel_magic, &mgr->toplevel->magic,
286  sizeof(struct_magic_decl_t));
287  uint64_t magic_input[3] = { mgr->toplevel_magic.magic_val,
288  (uint64_t) (uintptr_t) mgr,
289  ++mgr_count };
291  (uint32_t)siphash24g(magic_input, sizeof(magic_input));
292  mgr->frozen = true;
293 }
294 
296 void
298 {
299  if (!mgr)
300  return;
301  SMARTLIST_FOREACH(mgr->all_vars, managed_var_t *, mv, managed_var_free(mv));
302  smartlist_free(mgr->all_vars);
303  smartlist_free(mgr->all_abbrevs);
304  smartlist_free(mgr->all_deprecations);
305  smartlist_free(mgr->subconfigs);
306  memset(mgr, 0, sizeof(*mgr));
307  tor_free(mgr);
308 }
309 
313 smartlist_t *
315 {
316  smartlist_t *result = smartlist_new();
317  tor_assert(mgr);
319  smartlist_add(result, (void*) mv->cvar));
320  return result;
321 }
322 
327 smartlist_t *
329 {
330  smartlist_t *result = smartlist_new();
331  tor_assert(mgr);
333  smartlist_add(result, (char*)d->name));
334  return result;
335 }
336 
339 static void
341  const void *options)
342 {
343  tor_assert(mgr);
344  tor_assert(options);
345  tor_assert(mgr->frozen);
346  struct_check_magic(options, &mgr->toplevel_magic);
347 
348  config_suite_t **suitep = config_mgr_get_suite_ptr(mgr, (void*)options);
349  if (suitep == NULL) {
350  tor_assert(smartlist_len(mgr->subconfigs) == 0);
351  return;
352  }
353 
354  tor_assert(smartlist_len((*suitep)->configs) ==
355  smartlist_len(mgr->subconfigs));
357  void *obj = smartlist_get((*suitep)->configs, fmt_sl_idx);
358  tor_assert(obj);
359  struct_check_magic(obj, &fmt->magic);
360  } SMARTLIST_FOREACH_END(fmt);
361 }
362 
365 #define CONFIG_CHECK(mgr, cfg) STMT_BEGIN \
366  config_mgr_assert_magic_ok((mgr), (cfg)); \
367  STMT_END
368 
370 void *
372 {
373  tor_assert(mgr->frozen);
374  void *opts = tor_malloc_zero(mgr->toplevel->size);
375  struct_set_magic(opts, &mgr->toplevel_magic);
376  config_suite_t **suitep = config_mgr_get_suite_ptr(mgr, opts);
377  if (suitep) {
378  *suitep = config_suite_new();
380  void *obj = tor_malloc_zero(fmt->size);
381  struct_set_magic(obj, &fmt->magic);
382  smartlist_add((*suitep)->configs, obj);
383  } SMARTLIST_FOREACH_END(fmt);
384  }
385  CONFIG_CHECK(mgr, opts);
386  return opts;
387 }
388 
389 /*
390  * Functions to parse config options
391  */
392 
398 const char *
399 config_expand_abbrev(const config_mgr_t *mgr, const char *option,
400  int command_line, int warn_obsolete)
401 {
402  SMARTLIST_FOREACH_BEGIN(mgr->all_abbrevs, const config_abbrev_t *, abbrev) {
403  /* Abbreviations are case insensitive. */
404  if (!strcasecmp(option, abbrev->abbreviated) &&
405  (command_line || !abbrev->commandline_only)) {
406  if (warn_obsolete && abbrev->warn) {
407  log_warn(LD_CONFIG,
408  "The configuration option '%s' is deprecated; "
409  "use '%s' instead.",
410  abbrev->abbreviated,
411  abbrev->full);
412  }
413  /* Keep going through the list in case we want to rewrite it more.
414  * (We could imagine recursing here, but I don't want to get the
415  * user into an infinite loop if we craft our list wrong.) */
416  option = abbrev->full;
417  }
418  } SMARTLIST_FOREACH_END(abbrev);
419  return option;
420 }
421 
425 const char *
426 config_find_deprecation(const config_mgr_t *mgr, const char *key)
427 {
428  if (BUG(mgr == NULL) || BUG(key == NULL))
429  return NULL; // LCOV_EXCL_LINE
430 
432  d) {
433  if (!strcasecmp(d->name, key)) {
434  return d->why_deprecated ? d->why_deprecated : "";
435  }
436  } SMARTLIST_FOREACH_END(d);
437  return NULL;
438 }
439 
451 static const managed_var_t *
453  const char *key,
454  bool allow_truncated, int *idx_out)
455 {
456  const size_t keylen = strlen(key);
457  if (idx_out)
458  *idx_out = -1;
459 
460  if (!keylen)
461  return NULL; /* if they say "--" on the command line, it's not an option */
462 
463  /* First, check for an exact (case-insensitive) match */
464  SMARTLIST_FOREACH_BEGIN(mgr->all_vars, const managed_var_t *, mv) {
465  if (!strcasecmp(mv->cvar->member.name, key)) {
466  if (idx_out)
467  *idx_out = mv_sl_idx;
468  return mv;
469  }
470  } SMARTLIST_FOREACH_END(mv);
471 
472  if (!allow_truncated)
473  return NULL;
474 
475  /* If none, check for an abbreviated match */
476  SMARTLIST_FOREACH_BEGIN(mgr->all_vars, const managed_var_t *, mv) {
477  if (!strncasecmp(key, mv->cvar->member.name, keylen)) {
478  log_warn(LD_CONFIG, "The abbreviation '%s' is deprecated. "
479  "Please use '%s' instead",
480  key, mv->cvar->member.name);
481  if (idx_out)
482  *idx_out = mv_sl_idx;
483  return mv;
484  }
485  } SMARTLIST_FOREACH_END(mv);
486 
487  /* Okay, unrecognized option */
488  return NULL;
489 }
490 
496 const char *
497 config_find_option_name(const config_mgr_t *mgr, const char *key)
498 {
499  key = config_expand_abbrev(mgr, key, 0, 0);
500  const managed_var_t *mv = config_mgr_find_var(mgr, key, true, NULL);
501  if (mv)
502  return mv->cvar->member.name;
503  else
504  return NULL;
505 }
506 
508 static int
510 {
511  return smartlist_len(mgr->all_vars);
512 }
513 
518 static bool
519 config_var_has_flag(const config_var_t *var, uint32_t flag)
520 {
521  uint32_t have_flags = var->flags | struct_var_get_flags(&var->member);
522 
523  return (have_flags & flag) != 0;
524 }
525 
531 static bool
533 {
534  return ! config_var_has_flag(var, CFLG_NOREPLACE);
535 }
536 
541 bool
543 {
544  return ! config_var_has_flag(var, CFLG_NOSET);
545 }
546 
551 static bool
553 {
554  /* Arguably, invisible or obsolete options should not be gettable. However,
555  * they have been gettable for a long time, and making them ungettable could
556  * have compatibility effects. For now, let's leave them alone.
557  */
558 
559  // return ! config_var_has_flag(var, CVFLAG_OBSOLETE|CFGLAGS_INVISIBLE);
560  (void)var;
561  return true;
562 }
563 
572 static bool
574 {
575  return ! config_var_has_flag(var, CFLG_NOCMP);
576 }
577 
586 static bool
588 {
589  return ! config_var_has_flag(var, CFLG_NOCOPY);
590 }
591 
602 bool
604 {
605  return ! config_var_has_flag(var, CFLG_NOLIST);
606 }
607 
616 static bool
618 {
619  return ! config_var_has_flag(var, CFLG_NODUMP);
620 }
621 
622 /*
623  * Functions to assign config options.
624  */
625 
631 static int
632 config_assign_value(const config_mgr_t *mgr, void *options,
633  config_line_t *c, char **msg)
634 {
635  const managed_var_t *var;
636 
637  CONFIG_CHECK(mgr, options);
638 
639  var = config_mgr_find_var(mgr, c->key, true, NULL);
640  tor_assert(var);
641  tor_assert(!strcmp(c->key, var->cvar->member.name));
642  void *object = config_mgr_get_obj_mutable(mgr, options, var->object_idx);
643 
644  return struct_var_kvassign(object, c, msg, &var->cvar->member);
645 }
646 
649 static void
650 config_mark_lists_fragile(const config_mgr_t *mgr, void *options)
651 {
652  tor_assert(mgr);
653  tor_assert(options);
654 
655  SMARTLIST_FOREACH_BEGIN(mgr->all_vars, const managed_var_t *, mv) {
656  void *object = config_mgr_get_obj_mutable(mgr, options, mv->object_idx);
657  struct_var_mark_fragile(object, &mv->cvar->member);
658  } SMARTLIST_FOREACH_END(mv);
659 }
660 
667 void
668 warn_deprecated_option(const char *what, const char *why)
669 {
670  const char *space = (why && strlen(why)) ? " " : "";
671  log_warn(LD_CONFIG, "The %s option is deprecated, and will most likely "
672  "be removed in a future version of Tor.%s%s (If you think this is "
673  "a mistake, please let us know!)",
674  what, space, why);
675 }
676 
686 static int
687 config_assign_line(const config_mgr_t *mgr, void *options,
688  config_line_t *c, unsigned flags,
689  bitarray_t *options_seen, char **msg)
690 {
691  const unsigned use_defaults = flags & CAL_USE_DEFAULTS;
692  const unsigned clear_first = flags & CAL_CLEAR_FIRST;
693  const unsigned warn_deprecations = flags & CAL_WARN_DEPRECATIONS;
694  const managed_var_t *mvar;
695 
696  CONFIG_CHECK(mgr, options);
697 
698  int var_index = -1;
699  mvar = config_mgr_find_var(mgr, c->key, true, &var_index);
700  if (!mvar) {
701  const config_format_t *fmt = mgr->toplevel;
702  if (fmt->extra) {
703  void *lvalue = STRUCT_VAR_P(options, fmt->extra->offset);
704  log_info(LD_CONFIG,
705  "Found unrecognized option '%s'; saving it.", c->key);
706  config_line_append((config_line_t**)lvalue, c->key, c->value);
707  return 0;
708  } else {
709  tor_asprintf(msg,
710  "Unknown option '%s'. Failing.", c->key);
711  return -1;
712  }
713  }
714 
715  const config_var_t *cvar = mvar->cvar;
716  tor_assert(cvar);
717 
718  /* Put keyword into canonical case. */
719  if (strcmp(cvar->member.name, c->key)) {
720  tor_free(c->key);
721  c->key = tor_strdup(cvar->member.name);
722  }
723 
724  const char *deprecation_msg;
725  if (warn_deprecations &&
726  (deprecation_msg = config_find_deprecation(mgr, cvar->member.name))) {
727  warn_deprecated_option(cvar->member.name, deprecation_msg);
728  }
729 
730  if (!strlen(c->value)) {
731  /* reset or clear it, then return */
732  if (!clear_first) {
733  if (! config_var_is_replaced_on_set(cvar) &&
734  c->command != CONFIG_LINE_CLEAR) {
735  /* We got an empty linelist from the torrc or command line.
736  As a special case, call this an error. Warn and ignore. */
737  log_warn(LD_CONFIG,
738  "Linelist option '%s' has no value. Skipping.", c->key);
739  } else { /* not already cleared */
740  config_reset(mgr, options, mvar, use_defaults);
741  }
742  }
743  return 0;
744  } else if (c->command == CONFIG_LINE_CLEAR && !clear_first) {
745  // This block is unreachable, since a CLEAR line always has an
746  // empty value, and so will trigger be handled by the previous
747  // "if (!strlen(c->value))" block.
748 
749  // LCOV_EXCL_START
750  tor_assert_nonfatal_unreached();
751  config_reset(mgr, options, mvar, use_defaults);
752  // LCOV_EXCL_STOP
753  }
754 
755  if (options_seen && config_var_is_replaced_on_set(cvar)) {
756  /* We're tracking which options we've seen, and this option is not
757  * supposed to occur more than once. */
758  tor_assert(var_index >= 0);
759  if (bitarray_is_set(options_seen, var_index)) {
760  log_warn(LD_CONFIG, "Option '%s' used more than once; all but the last "
761  "value will be ignored.", cvar->member.name);
762  }
763  bitarray_set(options_seen, var_index);
764  }
765 
766  if (config_assign_value(mgr, options, c, msg) < 0)
767  return -2;
768  return 0;
769 }
770 
773 STATIC void
774 config_reset_line(const config_mgr_t *mgr, void *options,
775  const char *key, int use_defaults)
776 {
777  const managed_var_t *var;
778 
779  CONFIG_CHECK(mgr, options);
780 
781  var = config_mgr_find_var(mgr, key, true, NULL);
782  if (!var)
783  return; /* give error on next pass. */
784 
785  config_reset(mgr, options, var, use_defaults);
786 }
787 
790 static int
791 config_value_needs_escape(const char *value)
792 {
793  if (*value == '\"')
794  return 1;
795  while (*value) {
796  switch (*value)
797  {
798  case '\r':
799  case '\n':
800  case '#':
801  /* Note: quotes and backspaces need special handling when we are using
802  * quotes, not otherwise, so they don't trigger escaping on their
803  * own. */
804  return 1;
805  default:
806  if (!TOR_ISPRINT(*value))
807  return 1;
808  }
809  ++value;
810  }
811  return 0;
812 }
813 
819 config_get_assigned_option(const config_mgr_t *mgr, const void *options,
820  const char *key, int escape_val)
821 {
822  const managed_var_t *var;
823  config_line_t *result;
824 
825  tor_assert(options && key);
826 
827  CONFIG_CHECK(mgr, options);
828 
829  var = config_mgr_find_var(mgr, key, true, NULL);
830  if (!var) {
831  log_warn(LD_CONFIG, "Unknown option '%s'. Failing.", key);
832  return NULL;
833  }
834  if (! config_var_is_gettable(var->cvar)) {
835  log_warn(LD_CONFIG, "Option '%s' is obsolete or unfetchable. Failing.",
836  key);
837  return NULL;
838  }
839  const void *object = config_mgr_get_obj(mgr, options, var->object_idx);
840 
841  result = struct_var_kvencode(object, &var->cvar->member);
842 
843  if (escape_val) {
844  config_line_t *line;
845  for (line = result; line; line = line->next) {
846  if (line->value && config_value_needs_escape(line->value)) {
847  char *newval = esc_for_log(line->value);
848  tor_free(line->value);
849  line->value = newval;
850  }
851  }
852  }
853 
854  return result;
855 }
885 /*
886 There are three call cases for config_assign() currently.
887 
888 Case one: Torrc entry
889 options_init_from_torrc() calls config_assign(0, 0)
890  calls config_assign_line(0, 0).
891  if value is empty, calls config_reset(0) and returns.
892  calls config_assign_value(), appends.
893 
894 Case two: setconf
895 options_trial_assign() calls config_assign(0, 1)
896  calls config_reset_line(0)
897  calls config_reset(0)
898  calls option_clear().
899  calls config_assign_line(0, 1).
900  if value is empty, returns.
901  calls config_assign_value(), appends.
902 
903 Case three: resetconf
904 options_trial_assign() calls config_assign(1, 1)
905  calls config_reset_line(1)
906  calls config_reset(1)
907  calls option_clear().
908  calls config_assign_value(default)
909  calls config_assign_line(1, 1).
910  returns.
911 */
912 int
913 config_assign(const config_mgr_t *mgr, void *options, config_line_t *list,
914  unsigned config_assign_flags, char **msg)
915 {
916  config_line_t *p;
917  bitarray_t *options_seen;
918  const int n_options = config_count_options(mgr);
919  const unsigned clear_first = config_assign_flags & CAL_CLEAR_FIRST;
920  const unsigned use_defaults = config_assign_flags & CAL_USE_DEFAULTS;
921 
922  CONFIG_CHECK(mgr, options);
923 
924  /* pass 1: normalize keys */
925  for (p = list; p; p = p->next) {
926  const char *full = config_expand_abbrev(mgr, p->key, 0, 1);
927  if (strcmp(full,p->key)) {
928  tor_free(p->key);
929  p->key = tor_strdup(full);
930  }
931  }
932 
933  /* pass 2: if we're reading from a resetting source, clear all
934  * mentioned config options, and maybe set to their defaults. */
935  if (clear_first) {
936  for (p = list; p; p = p->next)
937  config_reset_line(mgr, options, p->key, use_defaults);
938  }
939 
940  options_seen = bitarray_init_zero(n_options);
941  /* pass 3: assign. */
942  while (list) {
943  int r;
944  if ((r=config_assign_line(mgr, options, list, config_assign_flags,
945  options_seen, msg))) {
946  bitarray_free(options_seen);
947  return r;
948  }
949  list = list->next;
950  }
951  bitarray_free(options_seen);
952 
956  config_mark_lists_fragile(mgr, options);
957 
958  return 0;
959 }
960 
963 static void
964 config_clear(const config_mgr_t *mgr, void *options, const managed_var_t *var)
965 {
966  void *object = config_mgr_get_obj_mutable(mgr, options, var->object_idx);
967  struct_var_free(object, &var->cvar->member);
968 }
969 
973 static void
974 config_reset(const config_mgr_t *mgr, void *options,
975  const managed_var_t *var, int use_defaults)
976 {
977  config_line_t *c;
978  char *msg = NULL;
979  CONFIG_CHECK(mgr, options);
980  config_clear(mgr, options, var); /* clear it first */
981 
982  if (!use_defaults)
983  return; /* all done */
984 
985  if (var->cvar->initvalue) {
986  c = tor_malloc_zero(sizeof(config_line_t));
987  c->key = tor_strdup(var->cvar->member.name);
988  c->value = tor_strdup(var->cvar->initvalue);
989  if (config_assign_value(mgr, options, c, &msg) < 0) {
990  // LCOV_EXCL_START
991  log_warn(LD_BUG, "Failed to assign default: %s", msg);
992  tor_free(msg); /* if this happens it's a bug */
993  // LCOV_EXCL_STOP
994  }
995  config_free_lines(c);
996  }
997 }
998 
1000 void
1001 config_free_(const config_mgr_t *mgr, void *options)
1002 {
1003  if (!options)
1004  return;
1005 
1006  tor_assert(mgr);
1007 
1008  if (mgr->toplevel->clear_fn) {
1009  mgr->toplevel->clear_fn(mgr, options);
1010  }
1011  config_suite_t **suitep = config_mgr_get_suite_ptr(mgr, options);
1012  if (suitep) {
1013  tor_assert(smartlist_len((*suitep)->configs) ==
1014  smartlist_len(mgr->subconfigs));
1015  SMARTLIST_FOREACH_BEGIN(mgr->subconfigs, const config_format_t *, fmt) {
1016  void *obj = smartlist_get((*suitep)->configs, fmt_sl_idx);
1017  if (fmt->clear_fn) {
1018  fmt->clear_fn(mgr, obj);
1019  }
1020  } SMARTLIST_FOREACH_END(fmt);
1021  }
1022 
1023  SMARTLIST_FOREACH_BEGIN(mgr->all_vars, const managed_var_t *, mv) {
1024  config_clear(mgr, options, mv);
1025  } SMARTLIST_FOREACH_END(mv);
1026 
1027  if (mgr->toplevel->extra) {
1028  config_line_t **linep = STRUCT_VAR_P(options,
1029  mgr->toplevel->extra->offset);
1030  config_free_lines(*linep);
1031  *linep = NULL;
1032  }
1033 
1034  if (suitep) {
1035  SMARTLIST_FOREACH((*suitep)->configs, void *, obj, tor_free(obj));
1036  config_suite_free(*suitep);
1037  }
1038 
1039  tor_free(options);
1040 }
1041 
1045 int
1047  const void *o1, const void *o2,
1048  const char *name)
1049 {
1050  CONFIG_CHECK(mgr, o1);
1051  CONFIG_CHECK(mgr, o2);
1052 
1053  const managed_var_t *var = config_mgr_find_var(mgr, name, true, NULL);
1054  if (!var) {
1055  return true;
1056  }
1057  const void *obj1 = config_mgr_get_obj(mgr, o1, var->object_idx);
1058  const void *obj2 = config_mgr_get_obj(mgr, o2, var->object_idx);
1059 
1060  return struct_var_eq(obj1, obj2, &var->cvar->member);
1061 }
1062 
1071 config_line_t *
1073  const void *options1, const void *options2)
1074 {
1075  config_line_t *result = NULL;
1076  config_line_t **next = &result;
1078  if (! config_var_should_list_changes(mv->cvar)) {
1079  /* something else will check this var, or it doesn't need checking */
1080  continue;
1081  }
1082  const void *obj1 = config_mgr_get_obj(mgr, options1, mv->object_idx);
1083  const void *obj2 = config_mgr_get_obj(mgr, options2, mv->object_idx);
1084 
1085  if (struct_var_eq(obj1, obj2, &mv->cvar->member)) {
1086  continue;
1087  }
1088 
1089  const char *varname = mv->cvar->member.name;
1090  config_line_t *line =
1091  config_get_assigned_option(mgr, options2, varname, 1);
1092 
1093  if (line) {
1094  *next = line;
1095  } else {
1096  *next = tor_malloc_zero(sizeof(config_line_t));
1097  (*next)->key = tor_strdup(varname);
1098  }
1099  while (*next)
1100  next = &(*next)->next;
1101  } SMARTLIST_FOREACH_END(mv);
1102 
1103  return result;
1104 }
1105 
1107 void *
1108 config_dup(const config_mgr_t *mgr, const void *old)
1109 {
1110  void *newopts;
1111 
1112  newopts = config_new(mgr);
1114  if (! config_var_needs_copy(mv->cvar)) {
1115  // Something else will copy this option, or it doesn't need copying.
1116  continue;
1117  }
1118  const void *oldobj = config_mgr_get_obj(mgr, old, mv->object_idx);
1119  void *newobj = config_mgr_get_obj_mutable(mgr, newopts, mv->object_idx);
1120  if (struct_var_copy(newobj, oldobj, &mv->cvar->member) < 0) {
1121  // LCOV_EXCL_START
1122  log_err(LD_BUG, "Unable to copy value for %s.",
1123  mv->cvar->member.name);
1124  tor_assert_unreached();
1125  // LCOV_EXCL_STOP
1126  }
1127  } SMARTLIST_FOREACH_END(mv);
1128 
1129  return newopts;
1130 }
1133 void
1134 config_init(const config_mgr_t *mgr, void *options)
1135 {
1136  CONFIG_CHECK(mgr, options);
1137 
1138  SMARTLIST_FOREACH_BEGIN(mgr->all_vars, const managed_var_t *, mv) {
1139  if (!mv->cvar->initvalue)
1140  continue; /* defaults to NULL or 0 */
1141  config_reset(mgr, options, mv, 1);
1142  } SMARTLIST_FOREACH_END(mv);
1143 }
1144 
1149 char *
1150 config_dump(const config_mgr_t *mgr, const void *default_options,
1151  const void *options, int minimal,
1152  int comment_defaults)
1153 {
1154  const config_format_t *fmt = mgr->toplevel;
1155  smartlist_t *elements;
1156  const void *defaults = default_options;
1157  void *defaults_tmp = NULL;
1158  config_line_t *line, *assigned;
1159  char *result;
1160  char *msg = NULL;
1161 
1162  if (defaults == NULL) {
1163  defaults = defaults_tmp = config_new(mgr);
1164  config_init(mgr, defaults_tmp);
1165  }
1166 
1167  /* XXX use a 1 here so we don't add a new log line while dumping */
1168  if (default_options == NULL) {
1169  if (fmt->validate_fn(NULL, defaults_tmp, defaults_tmp, 1, &msg) < 0) {
1170  // LCOV_EXCL_START
1171  log_err(LD_BUG, "Failed to validate default config: %s", msg);
1172  tor_free(msg);
1173  tor_assert(0);
1174  // LCOV_EXCL_STOP
1175  }
1176  }
1177 
1178  elements = smartlist_new();
1180  int comment_option = 0;
1181  /* Don't save 'hidden' control variables. */
1182  if (! config_var_is_dumpable(mv->cvar))
1183  continue;
1184  const char *name = mv->cvar->member.name;
1185  if (minimal && config_is_same(mgr, options, defaults, name))
1186  continue;
1187  else if (comment_defaults &&
1188  config_is_same(mgr, options, defaults, name))
1189  comment_option = 1;
1190 
1191  line = assigned =
1192  config_get_assigned_option(mgr, options, name, 1);
1193 
1194  for (; line; line = line->next) {
1195  if (!strcmpstart(line->key, "__")) {
1196  /* This check detects "hidden" variables inside LINELIST_V structures.
1197  */
1198  continue;
1199  }
1200  smartlist_add_asprintf(elements, "%s%s %s\n",
1201  comment_option ? "# " : "",
1202  line->key, line->value);
1203  }
1204  config_free_lines(assigned);
1205  } SMARTLIST_FOREACH_END(mv);
1206 
1207  if (fmt->extra) {
1208  line = *(config_line_t**)STRUCT_VAR_P(options, fmt->extra->offset);
1209  for (; line; line = line->next) {
1210  smartlist_add_asprintf(elements, "%s %s\n", line->key, line->value);
1211  }
1212  }
1213 
1214  result = smartlist_join_strings(elements, "", 0, NULL);
1215  SMARTLIST_FOREACH(elements, char *, cp, tor_free(cp));
1216  smartlist_free(elements);
1217  config_free(mgr, defaults_tmp);
1218  return result;
1219 }
1220 
1225 bool
1226 config_check_ok(const config_mgr_t *mgr, const void *options, int severity)
1227 {
1228  bool all_ok = true;
1229 
1230  SMARTLIST_FOREACH_BEGIN(mgr->all_vars, const managed_var_t *, mv) {
1231  if (!struct_var_ok(options, &mv->cvar->member)) {
1232  log_fn(severity, LD_BUG, "Invalid value for %s",
1233  mv->cvar->member.name);
1234  all_ok = false;
1235  }
1236  } SMARTLIST_FOREACH_END(mv);
1237 
1238  return all_ok;
1239 }
static void config_mgr_assert_magic_ok(const config_mgr_t *mgr, const void *options)
Definition: confparse.c:340
const char * name
Definition: confparse.h:39
Header for lib/confmgt/unitparse.c.
Header for confline.c.
static bool config_var_should_list_changes(const config_var_t *var)
Definition: confparse.c:573
static void config_mark_lists_fragile(const config_mgr_t *mgr, void *options)
Definition: confparse.c:650
#define CFLG_NOSET
Definition: conftypes.h:153
ptrdiff_t config_suite_offset
Definition: confparse.h:110
Header for printf.c.
void config_mgr_free_(config_mgr_t *mgr)
Definition: confparse.c:297
Header for smartlist.c.
#define SMARTLIST_FOREACH_BEGIN(sl, type, var)
unsigned int bitarray_t
Definition: bitarray.h:30
bool struct_var_ok(const void *object, const struct_member_t *member)
Definition: structvar.c:141
void config_mgr_freeze(config_mgr_t *mgr)
Definition: confparse.c:280
static bool config_var_is_replaced_on_set(const config_var_t *var)
Definition: confparse.c:532
void config_init(const config_mgr_t *mgr, void *options)
Definition: confparse.c:1134
static int managed_var_cmp(const void **a, const void **b)
Definition: confparse.c:267
smartlist_t * config_mgr_list_vars(const config_mgr_t *mgr)
Definition: confparse.c:314
Implements a variable-sized (but non-resizeable) bit-array.
#define CFLG_NOLIST
Definition: conftypes.h:147
static void config_mgr_register_fmt(config_mgr_t *mgr, const config_format_t *fmt, int object_idx)
Definition: confparse.c:161
void smartlist_add(smartlist_t *sl, void *element)
uint32_t struct_var_get_flags(const struct_member_t *member)
Definition: structvar.c:216
static bool config_var_has_flag(const config_var_t *var, uint32_t flag)
Definition: confparse.c:519
static bool config_var_is_dumpable(const config_var_t *var)
Definition: confparse.c:617
int config_is_same(const config_mgr_t *mgr, const void *o1, const void *o2, const char *name)
Definition: confparse.c:1046
static int config_assign_line(const config_mgr_t *mgr, void *options, config_line_t *c, unsigned flags, bitarray_t *options_seen, char **msg)
Definition: confparse.c:687
int smartlist_contains(const smartlist_t *sl, const void *element)
uint32_t flags
Definition: conftypes.h:193
config_mgr_t * config_mgr_new(const config_format_t *toplevel_fmt)
Definition: confparse.c:145
#define CFLG_NOCMP
Definition: conftypes.h:172
int strcmpstart(const char *s1, const char *s2)
Definition: util_string.c:206
#define tor_free(p)
Definition: malloc.h:52
static bool config_var_needs_copy(const config_var_t *var)
Definition: confparse.c:587
Header for util_string.c.
bool config_check_ok(const config_mgr_t *mgr, const void *options, int severity)
Definition: confparse.c:1226
const config_abbrev_t * abbrevs
Definition: confparse.h:97
bool config_var_is_listable(const config_var_t *var)
Definition: confparse.c:603
static int config_assign_value(const config_mgr_t *mgr, void *options, config_line_t *c, char **msg)
Definition: confparse.c:632
#define CFLG_NODUMP
Definition: conftypes.h:140
smartlist_t * all_abbrevs
Definition: confparse.c:125
int object_idx
Definition: confparse.c:55
struct config_line_t * struct_var_kvencode(const void *object, const struct_member_t *member)
Definition: structvar.c:169
const config_var_t * cvar
Definition: confparse.c:50
static void bitarray_set(bitarray_t *b, int bit)
Definition: bitarray.h:68
STATIC void * config_mgr_get_obj_mutable(const config_mgr_t *mgr, void *toplevel, int idx)
Definition: confparse.c:241
const config_var_t * vars
Definition: confparse.h:100
void config_free_(const config_mgr_t *mgr, void *options)
Definition: confparse.c:1001
const char * config_find_option_name(const config_mgr_t *mgr, const char *key)
Definition: confparse.c:497
tor_assert(buffer)
bool config_var_is_settable(const config_var_t *var)
Definition: confparse.c:542
unsigned int command
Definition: confline.h:35
#define CAL_CLEAR_FIRST
Definition: confparse.h:152
#define CONFIG_CHECK(mgr, cfg)
Definition: confparse.c:365
const char * abbreviated
Definition: confparse.h:25
int struct_var_kvassign(void *object, const struct config_line_t *line, char **errmsg, const struct_member_t *member)
Definition: structvar.c:154
int tor_asprintf(char **strp, const char *fmt,...)
Definition: printf.c:75
#define STRUCT_VAR_P(st, off)
smartlist_t * all_deprecations
Definition: confparse.c:127
Header for lib/confmgt/structvar.c.
ptrdiff_t offset
Definition: conftypes.h:114
static int config_count_options(const config_mgr_t *mgr)
Definition: confparse.c:509
void smartlist_add_asprintf(struct smartlist_t *sl, const char *pattern,...)
Definition: smartlist.c:36
static bool config_var_is_gettable(const config_var_t *var)
Definition: confparse.c:552
smartlist_t * config_mgr_list_deprecated_vars(const config_mgr_t *mgr)
Definition: confparse.c:328
STATIC const void * config_mgr_get_obj(const config_mgr_t *mgr, const void *toplevel, int idx)
Definition: confparse.c:260
void * config_dup(const config_mgr_t *mgr, const void *old)
Definition: confparse.c:1108
static bitarray_t * bitarray_init_zero(unsigned int n_bits)
Definition: bitarray.h:33
int struct_var_copy(void *dest, const void *src, const struct_member_t *member)
Definition: structvar.c:113
#define CAL_WARN_DEPRECATIONS
Definition: confparse.h:156
char * config_dump(const config_mgr_t *mgr, const void *default_options, const void *options, int minimal, int comment_defaults)
Definition: confparse.c:1150
const char * name
Definition: conftypes.h:87
struct managed_var_t managed_var_t
void * config_new(const config_mgr_t *mgr)
Definition: confparse.c:371
uint32_t magic_val
Definition: conftypes.h:128
const char * initvalue
Definition: conftypes.h:192
const struct_member_t * extra
Definition: confparse.h:107
void warn_deprecated_option(const char *what, const char *why)
Definition: confparse.c:668
struct_magic_decl_t magic
Definition: confparse.h:96
smartlist_t * subconfigs
Definition: confparse.c:119
#define CFLG_NOREPLACE
Definition: conftypes.h:180
smartlist_t * configs
Definition: confparse.c:79
void struct_var_mark_fragile(void *object, const struct_member_t *member)
Definition: structvar.c:183
char * smartlist_join_strings(smartlist_t *sl, const char *join, int terminate, size_t *len_out)
Definition: smartlist.c:279
static void config_reset(const config_mgr_t *fmt, void *options, const managed_var_t *var, int use_defaults)
Definition: confparse.c:974
#define SMARTLIST_FOREACH(sl, type, var, cmd)
int config_mgr_add_format(config_mgr_t *mgr, const config_format_t *fmt)
Definition: confparse.c:211
int config_assign(const config_mgr_t *mgr, void *options, config_line_t *list, unsigned config_assign_flags, char **msg)
Definition: confparse.c:913
config_line_t * config_get_changes(const config_mgr_t *mgr, const void *options1, const void *options2)
Definition: confparse.c:1072
Locale-independent character-type inspection (header)
smartlist_t * all_vars
Definition: confparse.c:121
bool struct_var_eq(const void *a, const void *b, const struct_member_t *member)
Definition: structvar.c:127
#define log_fn(severity, domain, args,...)
Definition: log.h:274
config_line_t * config_get_assigned_option(const config_mgr_t *mgr, const void *options, const char *key, int escape_val)
Definition: confparse.c:819
validate_fn_t validate_fn
Definition: confparse.h:103
void config_line_append(config_line_t **lst, const char *key, const char *val)
Definition: confline.c:32
Header for escape.c.
static config_suite_t * config_suite_new(void)
Definition: confparse.c:86
static void config_suite_free_(config_suite_t *suite)
Definition: confparse.c:96
void struct_var_free(void *object, const struct_member_t *member)
Definition: structvar.c:100
void struct_check_magic(const void *object, const struct_magic_decl_t *decl)
Definition: structvar.c:48
const char * config_find_deprecation(const config_mgr_t *mgr, const char *key)
Definition: confparse.c:426
void struct_set_magic(void *object, const struct_magic_decl_t *decl)
Definition: structvar.c:36
char * esc_for_log(const char *s)
Definition: escape.c:30
static const managed_var_t * config_mgr_find_var(const config_mgr_t *mgr, const char *key, bool allow_truncated, int *idx_out)
Definition: confparse.c:452
STATIC void config_reset_line(const config_mgr_t *mgr, void *options, const char *key, int use_defaults)
Definition: confparse.c:774
Headers for log.c.
const char * config_expand_abbrev(const config_mgr_t *mgr, const char *option, int command_line, int warn_obsolete)
Definition: confparse.c:399
#define CAL_USE_DEFAULTS
Definition: confparse.h:143
Macros to manage assertions, fatal and non-fatal.
static config_suite_t ** config_mgr_get_suite_ptr(const config_mgr_t *mgr, void *toplevel)
Definition: confparse.c:224
static int config_value_needs_escape(const char *value)
Definition: confparse.c:791
const config_format_t * toplevel
Definition: confparse.c:114
#define CFLG_NOCOPY
Definition: conftypes.h:162
void smartlist_sort(smartlist_t *sl, int(*compare)(const void **a, const void **b))
Definition: smartlist.c:334
static unsigned int bitarray_is_set(bitarray_t *b, int bit)
Definition: bitarray.h:81
static void config_clear(const config_mgr_t *mgr, void *options, const managed_var_t *var)
Definition: confparse.c:964
struct_magic_decl_t toplevel_magic
Definition: confparse.c:137
static void managed_var_free_(managed_var_t *mv)
Definition: confparse.c:66
#define LD_BUG
Definition: log.h:84
#define LD_CONFIG
Definition: log.h:66
Header for confparse.c.
clear_cfg_fn_t clear_fn
Definition: confparse.h:104