[tor-commits] [tor/master] Add a config_mgr_t type to wrap config_format_t

dgoulet at torproject.org dgoulet at torproject.org
Wed Sep 4 14:39:08 UTC 2019


commit e8dc513bd012c9d7e1a5908c72056d5be52e760e
Author: Nick Mathewson <nickm at torproject.org>
Date:   Fri Jul 19 06:45:54 2019 -0400

    Add a config_mgr_t type to wrap config_format_t
    
    Remember that our goal in the present refactoring is to allow each
    subsystem to declare its own configuration structure and
    variables.  To do this, each module will get its own
    config_format_t, and so we'll want a different structure that wraps
    several config_format_t objects.  This is a "config_mgr_t".
---
 src/app/config/config.c                   |  60 ++++++----
 src/app/config/config.h                   |   5 +-
 src/app/config/confparse.c                | 145 +++++++++++++++--------
 src/app/config/confparse.h                |  47 +++++---
 src/app/config/statefile.c                |  33 ++++--
 src/feature/dirauth/shared_random_state.c |  27 ++++-
 src/test/test_confparse.c                 | 183 +++++++++++++++++-------------
 src/test/test_helpers.c                   |   2 +-
 src/test/test_options.c                   |  14 +--
 9 files changed, 327 insertions(+), 189 deletions(-)

diff --git a/src/app/config/config.c b/src/app/config/config.c
index 4bc807a6f..76feed000 100644
--- a/src/app/config/config.c
+++ b/src/app/config/config.c
@@ -843,7 +843,7 @@ static void config_maybe_load_geoip_files_(const or_options_t *options,
 static int options_validate_cb(void *old_options, void *options,
                                void *default_options,
                                int from_setconf, char **msg);
-static void options_free_cb(void *options);
+static void options_free_cb(const config_mgr_t *, void *options);
 static void cleanup_protocol_warning_severity_level(void);
 static void set_protocol_warning_severity_level(int warning_severity);
 
@@ -851,7 +851,7 @@ static void set_protocol_warning_severity_level(int warning_severity);
 #define OR_OPTIONS_MAGIC 9090909
 
 /** Configuration format for or_options_t. */
-STATIC const config_format_t options_format = {
+static const config_format_t options_format = {
   sizeof(or_options_t),
   {
    "or_options_t",
@@ -895,6 +895,19 @@ static int in_option_validation = 0;
 /* True iff we've initialized libevent */
 static int libevent_initialized = 0;
 
+/* A global configuration manager to handle all configuration objects. */
+static config_mgr_t *options_mgr = NULL;
+
+/** Return the global configuration manager object for torrc options. */
+STATIC const config_mgr_t *
+get_options_mgr(void)
+{
+  if (PREDICT_UNLIKELY(options_mgr == NULL)) {
+    options_mgr = config_mgr_new(&options_format);
+  }
+  return options_mgr;
+}
+
 /** Return the contents of our frontpage string, or NULL if not configured. */
 MOCK_IMPL(const char*,
 get_dirportfrontpage, (void))
@@ -977,14 +990,14 @@ set_options(or_options_t *new_val, char **msg)
   if (old_options && old_options != global_options) {
     elements = smartlist_new();
     for (i=0; options_format.vars[i].member.name; ++i) {
-      const config_var_t *var = &options_format.vars[i];
+      const config_var_t *var = &options_format.vars[i]; // XXXX 29211
       const char *var_name = var->member.name;
       if (config_var_is_contained(var)) {
         /* something else will check this var, or it doesn't need checking */
         continue;
       }
-      if (!config_is_same(&options_format, new_val, old_options, var_name)) {
-        line = config_get_assigned_option(&options_format, new_val,
+      if (!config_is_same(get_options_mgr(), new_val, old_options, var_name)) {
+        line = config_get_assigned_option(get_options_mgr(), new_val,
                                           var_name, 1);
 
         if (line) {
@@ -1046,7 +1059,7 @@ or_options_free_(or_options_t *options)
   tor_free(options->command_arg);
   tor_free(options->master_key_fname);
   config_free_lines(options->MyFamily);
-  config_free(&options_format, options);
+  config_free(get_options_mgr(), options);
 }
 
 /** Release all memory and resources held by global configuration structures.
@@ -1080,6 +1093,8 @@ config_free_all(void)
 
   have_parsed_cmdline = 0;
   libevent_initialized = 0;
+
+  config_mgr_free(options_mgr);
 }
 
 /** Make <b>address</b> -- a piece of information related to our operation as
@@ -2547,7 +2562,7 @@ config_parse_commandline(int argc, char **argv, int ignore_errors,
 
     param = tor_malloc_zero(sizeof(config_line_t));
     param->key = is_cmdline ? tor_strdup(argv[i]) :
-                   tor_strdup(config_expand_abbrev(&options_format, s, 1, 1));
+                 tor_strdup(config_expand_abbrev(get_options_mgr(), s, 1, 1));
     param->value = arg;
     param->command = command;
     param->next = NULL;
@@ -2573,7 +2588,7 @@ config_parse_commandline(int argc, char **argv, int ignore_errors,
 int
 option_is_recognized(const char *key)
 {
-  const config_var_t *var = config_find_option(&options_format, key);
+  const config_var_t *var = config_find_option(get_options_mgr(), key);
   return (var != NULL);
 }
 
@@ -2582,7 +2597,7 @@ option_is_recognized(const char *key)
 const char *
 option_get_canonical_name(const char *key)
 {
-  const config_var_t *var = config_find_option(&options_format, key);
+  const config_var_t *var = config_find_option(get_options_mgr(), key);
   return var ? var->member.name : NULL;
 }
 
@@ -2591,7 +2606,7 @@ option_get_canonical_name(const char *key)
 config_line_t *
 option_get_assignment(const or_options_t *options, const char *key)
 {
-  return config_get_assigned_option(&options_format, options, key, 1);
+  return config_get_assigned_option(get_options_mgr(), options, key, 1);
 }
 
 /** Try assigning <b>list</b> to the global options. You do this by duping
@@ -2607,9 +2622,9 @@ setopt_err_t
 options_trial_assign(config_line_t *list, unsigned flags, char **msg)
 {
   int r;
-  or_options_t *trial_options = config_dup(&options_format, get_options());
+  or_options_t *trial_options = config_dup(get_options_mgr(), get_options());
 
-  if ((r=config_assign(&options_format, trial_options,
+  if ((r=config_assign(get_options_mgr(), trial_options,
                        list, flags, msg)) < 0) {
     or_options_free(trial_options);
     return r;
@@ -2992,7 +3007,7 @@ is_local_addr, (const tor_addr_t *addr))
 or_options_t *
 options_new(void)
 {
-  return config_new(&options_format);
+  return config_new(get_options_mgr());
 }
 
 /** Set <b>options</b> to hold reasonable defaults for most options.
@@ -3000,10 +3015,10 @@ options_new(void)
 void
 options_init(or_options_t *options)
 {
-  config_init(&options_format, options);
+  config_init(get_options_mgr(), options);
   config_line_t *dflts = get_options_defaults();
   char *msg=NULL;
-  if (config_assign(&options_format, options, dflts,
+  if (config_assign(get_options_mgr(), options, dflts,
                     CAL_WARN_DEPRECATIONS, &msg)<0) {
     log_err(LD_BUG, "Unable to set default options: %s", msg);
     tor_free(msg);
@@ -3040,7 +3055,7 @@ options_dump(const or_options_t *options, int how_to_dump)
       return NULL;
   }
 
-  return config_dump(&options_format, use_defaults, options, minimal, 0);
+  return config_dump(get_options_mgr(), use_defaults, options, minimal, 0);
 }
 
 /** Return 0 if every element of sl is a string holding a decimal
@@ -3174,8 +3189,9 @@ options_validate_cb(void *old_options, void *options, void *default_options,
 
 /** Callback to free an or_options_t */
 static void
-options_free_cb(void *options)
+options_free_cb(const config_mgr_t *mgr, void *options)
 {
+  (void)mgr;
   or_options_free_(options);
 }
 
@@ -4435,7 +4451,7 @@ options_validate(or_options_t *old_options, or_options_t *options,
   STMT_BEGIN                                                            \
     if (!options->TestingTorNetwork &&                                  \
         !options->UsingTestNetworkDefaults_ &&                          \
-        !config_is_same(&options_format,options,                        \
+        !config_is_same(get_options_mgr(),options,                        \
                         default_options,#arg)) {                        \
       REJECT(#arg " may only be changed in testing Tor "                \
              "networks!");                                              \
@@ -5431,7 +5447,7 @@ options_init_from_string(const char *cf_defaults, const char *cf,
       err = SETOPT_ERR_PARSE;
       goto err;
     }
-    retval = config_assign(&options_format, newoptions, cl,
+    retval = config_assign(get_options_mgr(), newoptions, cl,
                            CAL_WARN_DEPRECATIONS, msg);
     config_free_lines(cl);
     if (retval < 0) {
@@ -5439,15 +5455,15 @@ options_init_from_string(const char *cf_defaults, const char *cf,
       goto err;
     }
     if (i==0)
-      newdefaultoptions = config_dup(&options_format, newoptions);
+      newdefaultoptions = config_dup(get_options_mgr(), newoptions);
   }
 
   if (newdefaultoptions == NULL) {
-    newdefaultoptions = config_dup(&options_format, global_default_options);
+    newdefaultoptions = config_dup(get_options_mgr(), global_default_options);
   }
 
   /* Go through command-line variables too */
-  retval = config_assign(&options_format, newoptions,
+  retval = config_assign(get_options_mgr(), newoptions,
                          global_cmdline_options, CAL_WARN_DEPRECATIONS, msg);
   if (retval < 0) {
     err = SETOPT_ERR_PARSE;
diff --git a/src/app/config/config.h b/src/app/config/config.h
index c6feb89fe..44f09e5ee 100644
--- a/src/app/config/config.h
+++ b/src/app/config/config.h
@@ -247,9 +247,8 @@ int options_any_client_port_set(const or_options_t *options);
 #define CL_PORT_DFLT_GROUP_WRITABLE (1u<<7)
 
 STATIC int options_act(const or_options_t *old_options);
-#ifdef TOR_UNIT_TESTS
-extern const struct config_format_t options_format;
-#endif
+struct config_mgr_t;
+STATIC const struct config_mgr_t *get_options_mgr(void);
 
 STATIC port_cfg_t *port_cfg_new(size_t namelen);
 #define port_cfg_free(port) \
diff --git a/src/app/config/confparse.c b/src/app/config/confparse.c
index 699fc0e3d..9c4c6a277 100644
--- a/src/app/config/confparse.c
+++ b/src/app/config/confparse.c
@@ -37,13 +37,44 @@
 #include "lib/string/printf.h"
 #include "lib/string/util_string.h"
 
-static void config_reset(const config_format_t *fmt, void *options,
+static void config_reset(const config_mgr_t *fmt, void *options,
                          const config_var_t *var, int use_defaults);
 
+struct config_mgr_t {
+  /** The 'top-level' configuration format.  This one is used for legacy
+   * options that have not yet been assigned to different sub-modules.
+   *
+   * (NOTE: for now, this is the only config_format_t that a config_mgr_t
+   * contains.  A subsequent commit will add more. XXXX)
+   */
+  const config_format_t *toplevel;
+};
+
+/** Create a new config_mgr_t to manage a set of configuration objects to be
+ * wrapped under <b>toplevel_fmt</b>. */
+config_mgr_t *
+config_mgr_new(const config_format_t *toplevel_fmt)
+{
+  config_mgr_t *mgr = tor_malloc_zero(sizeof(config_mgr_t));
+  mgr->toplevel = toplevel_fmt;
+  return mgr;
+}
+
+/** Release all storage held in <b>mgr</b> */
+void
+config_mgr_free_(config_mgr_t *mgr)
+{
+  if (!mgr)
+    return;
+  memset(mgr, 0, sizeof(*mgr));
+  tor_free(mgr);
+}
+
 /** Allocate an empty configuration object of a given format type. */
 void *
-config_new(const config_format_t *fmt)
+config_new(const config_mgr_t *mgr)
 {
+  const config_format_t *fmt = mgr->toplevel;
   void *opts = tor_malloc_zero(fmt->size);
   struct_set_magic(opts, &fmt->magic);
   CONFIG_CHECK(fmt, opts);
@@ -60,9 +91,10 @@ config_new(const config_format_t *fmt)
  * apply abbreviations that work for the config file and the command line.
  * If <b>warn_obsolete</b> is set, warn about deprecated names. */
 const char *
-config_expand_abbrev(const config_format_t *fmt, const char *option,
+config_expand_abbrev(const config_mgr_t *mgr, const char *option,
                      int command_line, int warn_obsolete)
 {
+  const config_format_t *fmt = mgr->toplevel;
   int i;
   if (! fmt->abbrevs)
     return option;
@@ -90,8 +122,9 @@ config_expand_abbrev(const config_format_t *fmt, const char *option,
  * explaining why it is deprecated (which may be an empty string). Return NULL
  * if it is not deprecated. The <b>key</b> field must be fully expanded. */
 const char *
-config_find_deprecation(const config_format_t *fmt, const char *key)
+config_find_deprecation(const config_mgr_t *mgr, const char *key)
 {
+  const config_format_t *fmt = mgr->toplevel;
   if (BUG(fmt == NULL) || BUG(key == NULL))
     return NULL; // LCOV_EXCL_LINE
   if (fmt->deprecations == NULL)
@@ -112,8 +145,9 @@ config_find_deprecation(const config_format_t *fmt, const char *key)
  * NULL.
  */
 const config_var_t *
-config_find_option(const config_format_t *fmt, const char *key)
+config_find_option(const config_mgr_t *mgr, const char *key)
 {
+  const config_format_t *fmt = mgr->toplevel;
   int i;
   size_t keylen = strlen(key);
   if (!keylen)
@@ -139,8 +173,9 @@ config_find_option(const config_format_t *fmt, const char *key)
 
 /** Return the number of option entries in <b>fmt</b>. */
 static int
-config_count_options(const config_format_t *fmt)
+config_count_options(const config_mgr_t *mgr)
 {
+  const config_format_t *fmt = mgr->toplevel;
   int i;
   for (i=0; fmt->vars[i].member.name; ++i)
     ;
@@ -175,14 +210,15 @@ config_var_is_contained(const config_var_t *var)
  * Called from config_assign_line() and option_reset().
  */
 static int
-config_assign_value(const config_format_t *fmt, void *options,
+config_assign_value(const config_mgr_t *mgr, void *options,
                     config_line_t *c, char **msg)
 {
   const config_var_t *var;
+  const config_format_t *fmt = mgr->toplevel;
 
   CONFIG_CHECK(fmt, options);
 
-  var = config_find_option(fmt, c->key);
+  var = config_find_option(mgr, c->key);
   tor_assert(var);
   tor_assert(!strcmp(c->key, var->member.name));
 
@@ -192,9 +228,11 @@ config_assign_value(const config_format_t *fmt, void *options,
 /** Mark every linelist in <b>options</b> "fragile", so that fresh assignments
  * to it will replace old ones. */
 static void
-config_mark_lists_fragile(const config_format_t *fmt, void *options)
+config_mark_lists_fragile(const config_mgr_t *mgr, void *options)
 {
   int i;
+  const config_format_t *fmt = mgr->toplevel;
+
   tor_assert(fmt);
   tor_assert(options);
 
@@ -224,10 +262,11 @@ warn_deprecated_option(const char *what, const char *why)
  * Called from config_assign().
  */
 static int
-config_assign_line(const config_format_t *fmt, void *options,
+config_assign_line(const config_mgr_t *mgr, void *options,
                    config_line_t *c, unsigned flags,
                    bitarray_t *options_seen, char **msg)
 {
+  const config_format_t *fmt = mgr->toplevel;
   const unsigned use_defaults = flags & CAL_USE_DEFAULTS;
   const unsigned clear_first = flags & CAL_CLEAR_FIRST;
   const unsigned warn_deprecations = flags & CAL_WARN_DEPRECATIONS;
@@ -235,7 +274,7 @@ config_assign_line(const config_format_t *fmt, void *options,
 
   CONFIG_CHECK(fmt, options);
 
-  var = config_find_option(fmt, c->key);
+  var = config_find_option(mgr, c->key);
   if (!var) {
     if (fmt->extra) {
       void *lvalue = STRUCT_VAR_P(options, fmt->extra->offset);
@@ -258,7 +297,7 @@ config_assign_line(const config_format_t *fmt, void *options,
 
   const char *deprecation_msg;
   if (warn_deprecations &&
-      (deprecation_msg = config_find_deprecation(fmt, var->member.name))) {
+      (deprecation_msg = config_find_deprecation(mgr, var->member.name))) {
     warn_deprecated_option(var->member.name, deprecation_msg);
   }
 
@@ -271,14 +310,14 @@ config_assign_line(const config_format_t *fmt, void *options,
         log_warn(LD_CONFIG,
                  "Linelist option '%s' has no value. Skipping.", c->key);
       } else { /* not already cleared */
-        config_reset(fmt, options, var, use_defaults);
+        config_reset(mgr, options, var, use_defaults);
       }
     }
     return 0;
   } else if (c->command == CONFIG_LINE_CLEAR && !clear_first) {
     // XXXX This is unreachable, since a CLEAR line always has an
     // XXXX empty value.
-    config_reset(fmt, options, var, use_defaults); // LCOV_EXCL_LINE
+    config_reset(mgr, options, var, use_defaults); // LCOV_EXCL_LINE
   }
 
   if (options_seen && ! config_var_is_cumulative(var)) {
@@ -292,7 +331,7 @@ config_assign_line(const config_format_t *fmt, void *options,
     bitarray_set(options_seen, var_index);
   }
 
-  if (config_assign_value(fmt, options, c, msg) < 0)
+  if (config_assign_value(mgr, options, c, msg) < 0)
     return -2;
   return 0;
 }
@@ -300,18 +339,19 @@ config_assign_line(const config_format_t *fmt, void *options,
 /** Restore the option named <b>key</b> in options to its default value.
  * Called from config_assign(). */
 STATIC void
-config_reset_line(const config_format_t *fmt, void *options,
+config_reset_line(const config_mgr_t *mgr, void *options,
                   const char *key, int use_defaults)
 {
+  const config_format_t *fmt = mgr->toplevel;
   const config_var_t *var;
 
   CONFIG_CHECK(fmt, options);
 
-  var = config_find_option(fmt, key);
+  var = config_find_option(mgr, key);
   if (!var)
     return; /* give error on next pass. */
 
-  config_reset(fmt, options, var, use_defaults);
+  config_reset(mgr, options, var, use_defaults);
 }
 
 /** Return true iff value needs to be quoted and escaped to be used in
@@ -345,16 +385,18 @@ config_value_needs_escape(const char *value)
  * value needs to be quoted before it's put in a config file, quote and
  * escape that value. Return NULL if no such key exists. */
 config_line_t *
-config_get_assigned_option(const config_format_t *fmt, const void *options,
+config_get_assigned_option(const config_mgr_t *mgr, const void *options,
                            const char *key, int escape_val)
 {
   const config_var_t *var;
   config_line_t *result;
+  const config_format_t *fmt = mgr->toplevel;
+
   tor_assert(options && key);
 
   CONFIG_CHECK(fmt, options);
 
-  var = config_find_option(fmt, key);
+  var = config_find_option(mgr, key);
   if (!var) {
     log_warn(LD_CONFIG, "Unknown option '%s'.  Failing.", key);
     return NULL;
@@ -432,12 +474,13 @@ options_trial_assign() calls config_assign(1, 1)
     returns.
 */
 int
-config_assign(const config_format_t *fmt, void *options, config_line_t *list,
+config_assign(const config_mgr_t *mgr, void *options, config_line_t *list,
               unsigned config_assign_flags, char **msg)
 {
   config_line_t *p;
   bitarray_t *options_seen;
-  const int n_options = config_count_options(fmt);
+  const config_format_t *fmt = mgr->toplevel;
+  const int n_options = config_count_options(mgr);
   const unsigned clear_first = config_assign_flags & CAL_CLEAR_FIRST;
   const unsigned use_defaults = config_assign_flags & CAL_USE_DEFAULTS;
 
@@ -445,7 +488,7 @@ config_assign(const config_format_t *fmt, void *options, config_line_t *list,
 
   /* pass 1: normalize keys */
   for (p = list; p; p = p->next) {
-    const char *full = config_expand_abbrev(fmt, p->key, 0, 1);
+    const char *full = config_expand_abbrev(mgr, p->key, 0, 1);
     if (strcmp(full,p->key)) {
       tor_free(p->key);
       p->key = tor_strdup(full);
@@ -456,14 +499,14 @@ config_assign(const config_format_t *fmt, void *options, config_line_t *list,
    * mentioned config options, and maybe set to their defaults. */
   if (clear_first) {
     for (p = list; p; p = p->next)
-      config_reset_line(fmt, options, p->key, use_defaults);
+      config_reset_line(mgr, options, p->key, use_defaults);
   }
 
   options_seen = bitarray_init_zero(n_options);
   /* pass 3: assign. */
   while (list) {
     int r;
-    if ((r=config_assign_line(fmt, options, list, config_assign_flags,
+    if ((r=config_assign_line(mgr, options, list, config_assign_flags,
                               options_seen, msg))) {
       bitarray_free(options_seen);
       return r;
@@ -475,7 +518,7 @@ config_assign(const config_format_t *fmt, void *options, config_line_t *list,
   /** Now we're done assigning a group of options to the configuration.
    * Subsequent group assignments should _replace_ linelists, not extend
    * them. */
-  config_mark_lists_fragile(fmt, options);
+  config_mark_lists_fragile(mgr, options);
 
   return 0;
 }
@@ -483,12 +526,9 @@ config_assign(const config_format_t *fmt, void *options, config_line_t *list,
 /** Reset config option <b>var</b> to 0, 0.0, NULL, or the equivalent.
  * Called from config_reset() and config_free(). */
 static void
-config_clear(const config_format_t *fmt, void *options,
+config_clear(void *options,
              const config_var_t *var)
 {
-
-  (void)fmt; /* unused */
-
   struct_var_free(options, &var->member);
 }
 
@@ -496,20 +536,21 @@ config_clear(const config_format_t *fmt, void *options,
  * <b>use_defaults</b>, set it to its default value.
  * Called by config_init() and option_reset_line() and option_assign_line(). */
 static void
-config_reset(const config_format_t *fmt, void *options,
+config_reset(const config_mgr_t *mgr, void *options,
              const config_var_t *var, int use_defaults)
 {
+  const config_format_t *fmt = mgr->toplevel;
   config_line_t *c;
   char *msg = NULL;
   CONFIG_CHECK(fmt, options);
-  config_clear(fmt, options, var); /* clear it first */
+  config_clear(options, var); /* clear it first */
   if (!use_defaults)
     return; /* all done */
   if (var->initvalue) {
     c = tor_malloc_zero(sizeof(config_line_t));
     c->key = tor_strdup(var->member.name);
     c->value = tor_strdup(var->initvalue);
-    if (config_assign_value(fmt, options, c, &msg) < 0) {
+    if (config_assign_value(mgr, options, c, &msg) < 0) {
       // LCOV_EXCL_START
       log_warn(LD_BUG, "Failed to assign default: %s", msg);
       tor_free(msg); /* if this happens it's a bug */
@@ -521,9 +562,10 @@ config_reset(const config_format_t *fmt, void *options,
 
 /** Release storage held by <b>options</b>. */
 void
-config_free_(const config_format_t *fmt, void *options)
+config_free_(const config_mgr_t *mgr, void *options)
 {
   int i;
+  const config_format_t *fmt = mgr->toplevel;
 
   if (!options)
     return;
@@ -531,7 +573,7 @@ config_free_(const config_format_t *fmt, void *options)
   tor_assert(fmt);
 
   for (i=0; fmt->vars[i].member.name; ++i)
-    config_clear(fmt, options, &(fmt->vars[i]));
+    config_clear(options, &(fmt->vars[i]));
 
   if (fmt->extra) {
     config_line_t **linep = STRUCT_VAR_P(options, fmt->extra->offset);
@@ -545,14 +587,15 @@ config_free_(const config_format_t *fmt, void *options)
  * and <b>o2</b>.  Must not be called for LINELIST_S or OBSOLETE options.
  */
 int
-config_is_same(const config_format_t *fmt,
+config_is_same(const config_mgr_t *mgr,
                const void *o1, const void *o2,
                const char *name)
 {
+  const config_format_t *fmt = mgr->toplevel;
   CONFIG_CHECK(fmt, o1);
   CONFIG_CHECK(fmt, o2);
 
-  const config_var_t *var = config_find_option(fmt, name);
+  const config_var_t *var = config_find_option(mgr, name);
   if (!var) {
     return true;
   }
@@ -562,12 +605,13 @@ config_is_same(const config_format_t *fmt,
 
 /** Copy storage held by <b>old</b> into a new or_options_t and return it. */
 void *
-config_dup(const config_format_t *fmt, const void *old)
+config_dup(const config_mgr_t *mgr, const void *old)
 {
+  const config_format_t *fmt = mgr->toplevel;
   void *newopts;
   int i;
 
-  newopts = config_new(fmt);
+  newopts = config_new(mgr);
   for (i=0; fmt->vars[i].member.name; ++i) {
     if (config_var_is_contained(&fmt->vars[i])) {
       // Something else will copy this option, or it doesn't need copying.
@@ -586,9 +630,10 @@ config_dup(const config_format_t *fmt, const void *old)
 /** Set all vars in the configuration object <b>options</b> to their default
  * values. */
 void
-config_init(const config_format_t *fmt, void *options)
+config_init(const config_mgr_t *mgr, void *options)
 {
   int i;
+  const config_format_t *fmt = mgr->toplevel;
   const config_var_t *var;
   CONFIG_CHECK(fmt, options);
 
@@ -596,7 +641,7 @@ config_init(const config_format_t *fmt, void *options)
     var = &fmt->vars[i];
     if (!var->initvalue)
       continue; /* defaults to NULL or 0 */
-    config_reset(fmt, options, var, 1);
+    config_reset(mgr, options, var, 1);
   }
 }
 
@@ -605,11 +650,12 @@ config_init(const config_format_t *fmt, void *options)
  * Else, if comment_defaults, write default values as comments.
  */
 char *
-config_dump(const config_format_t *fmt, const void *default_options,
+config_dump(const config_mgr_t *mgr, const void *default_options,
             const void *options, int minimal,
             int comment_defaults)
 {
   smartlist_t *elements;
+  const config_format_t *fmt = mgr->toplevel;
   const void *defaults = default_options;
   void *defaults_tmp = NULL;
   config_line_t *line, *assigned;
@@ -618,8 +664,8 @@ config_dump(const config_format_t *fmt, const void *default_options,
   char *msg = NULL;
 
   if (defaults == NULL) {
-    defaults = defaults_tmp = config_new(fmt);
-    config_init(fmt, defaults_tmp);
+    defaults = defaults_tmp = config_new(mgr);
+    config_init(mgr, defaults_tmp);
   }
 
   /* XXX use a 1 here so we don't add a new log line while dumping */
@@ -643,15 +689,15 @@ config_dump(const config_format_t *fmt, const void *default_options,
     /* Don't save 'hidden' control variables. */
     if (fmt->vars[i].flags & CVFLAG_NODUMP)
       continue;
-    if (minimal && config_is_same(fmt, options, defaults,
+    if (minimal && config_is_same(mgr, options, defaults,
                                   fmt->vars[i].member.name))
       continue;
     else if (comment_defaults &&
-             config_is_same(fmt, options, defaults, fmt->vars[i].member.name))
+             config_is_same(mgr, options, defaults, fmt->vars[i].member.name))
       comment_option = 1;
 
     line = assigned =
-      config_get_assigned_option(fmt, options, fmt->vars[i].member.name, 1);
+      config_get_assigned_option(mgr, options, fmt->vars[i].member.name, 1);
 
     for (; line; line = line->next) {
       if (!strcmpstart(line->key, "__")) {
@@ -677,7 +723,7 @@ config_dump(const config_format_t *fmt, const void *default_options,
   SMARTLIST_FOREACH(elements, char *, cp, tor_free(cp));
   smartlist_free(elements);
   if (defaults_tmp) {
-    fmt->free_fn(defaults_tmp);
+    fmt->free_fn(mgr, defaults_tmp);
   }
   return result;
 }
@@ -687,8 +733,9 @@ config_dump(const config_format_t *fmt, const void *default_options,
  * Return false otherwise.  Log errors at level <b>severity</b>.
  */
 bool
-config_check_ok(const config_format_t *fmt, const void *options, int severity)
+config_check_ok(const config_mgr_t *mgr, const void *options, int severity)
 {
+  const config_format_t *fmt = mgr->toplevel;
   bool all_ok = true;
   for (int i=0; fmt->vars[i].member.name; ++i) {
     if (!struct_var_ok(options, &fmt->vars[i].member)) {
diff --git a/src/app/config/confparse.h b/src/app/config/confparse.h
index 3633c2a80..a6a2450ae 100644
--- a/src/app/config/confparse.h
+++ b/src/app/config/confparse.h
@@ -39,8 +39,10 @@ typedef struct config_deprecation_t {
  * of arguments. */
 typedef int (*validate_fn_t)(void*,void*,void*,int,char**);
 
+struct config_mgr_t;
+
 /** Callback to free a configuration object. */
-typedef void (*free_cfg_fn_t)(void*);
+typedef void (*free_cfg_fn_t)(const struct config_mgr_t *mgr, void*);
 
 /** Information on the keys, value types, key-to-struct-member mappings,
  * variable descriptions, validation functions, and abbreviations for a
@@ -61,6 +63,19 @@ typedef struct config_format_t {
   const struct_member_t *extra;
 } config_format_t;
 
+/**
+ * A collection of config_format_t objects to describe several objects
+ * that are all configured with the same configuration file.
+ *
+ * (NOTE: for now, this only handles a single config_format_t.)
+ **/
+typedef struct config_mgr_t config_mgr_t;
+
+config_mgr_t *config_mgr_new(const config_format_t *toplevel_fmt);
+void config_mgr_free_(config_mgr_t *mgr);
+#define config_mgr_free(mgr) \
+  FREE_AND_NULL(config_mgr_t, config_mgr_free_, (mgr))
+
 /** Macro: assert that <b>cfg</b> has the right magic field for format
  * <b>fmt</b>. */
 #define CONFIG_CHECK(fmt, cfg) STMT_BEGIN                               \
@@ -72,34 +87,34 @@ typedef struct config_format_t {
 #define CAL_CLEAR_FIRST       (1u<<1)
 #define CAL_WARN_DEPRECATIONS (1u<<2)
 
-void *config_new(const config_format_t *fmt);
-void config_free_(const config_format_t *fmt, void *options);
-#define config_free(fmt, options) do {                \
-    config_free_((fmt), (options));                   \
+void *config_new(const config_mgr_t *fmt);
+void config_free_(const config_mgr_t *fmt, void *options);
+#define config_free(mgr, options) do {                \
+    config_free_((mgr), (options));                   \
     (options) = NULL;                                 \
   } while (0)
 
-struct config_line_t *config_get_assigned_option(const config_format_t *fmt,
+struct config_line_t *config_get_assigned_option(const config_mgr_t *mgr,
                                           const void *options, const char *key,
                                           int escape_val);
-int config_is_same(const config_format_t *fmt,
+int config_is_same(const config_mgr_t *fmt,
                    const void *o1, const void *o2,
                    const char *name);
-void config_init(const config_format_t *fmt, void *options);
-void *config_dup(const config_format_t *fmt, const void *old);
-char *config_dump(const config_format_t *fmt, const void *default_options,
+void config_init(const config_mgr_t *mgr, void *options);
+void *config_dup(const config_mgr_t *mgr, const void *old);
+char *config_dump(const config_mgr_t *mgr, const void *default_options,
                   const void *options, int minimal,
                   int comment_defaults);
-bool config_check_ok(const config_format_t *fmt, const void *options,
+bool config_check_ok(const config_mgr_t *mgr, const void *options,
                      int severity);
-int config_assign(const config_format_t *fmt, void *options,
+int config_assign(const config_mgr_t *mgr, void *options,
                   struct config_line_t *list,
                   unsigned flags, char **msg);
-const char *config_find_deprecation(const config_format_t *fmt,
+const char *config_find_deprecation(const config_mgr_t *mgr,
                                      const char *key);
-const config_var_t *config_find_option(const config_format_t *fmt,
+const config_var_t *config_find_option(const config_mgr_t *mgr,
                                        const char *key);
-const char *config_expand_abbrev(const config_format_t *fmt,
+const char *config_expand_abbrev(const config_mgr_t *mgr,
                                  const char *option,
                                  int command_line, int warn_obsolete);
 void warn_deprecated_option(const char *what, const char *why);
@@ -117,7 +132,7 @@ bool config_var_is_contained(const config_var_t *var);
 #define CFG_EQ_ROUTERSET(a,b,opt) routerset_equal((a)->opt, (b)->opt)
 
 #ifdef CONFPARSE_PRIVATE
-STATIC void config_reset_line(const config_format_t *fmt, void *options,
+STATIC void config_reset_line(const config_mgr_t *mgr, void *options,
                               const char *key, int use_defaults);
 #endif
 
diff --git a/src/app/config/statefile.c b/src/app/config/statefile.c
index d997d3932..a44bcf6fb 100644
--- a/src/app/config/statefile.c
+++ b/src/app/config/statefile.c
@@ -145,7 +145,7 @@ static int or_state_validate_cb(void *old_options, void *options,
                                 void *default_options,
                                 int from_setconf, char **msg);
 
-static void or_state_free_cb(void *state);
+static void or_state_free_cb(const config_mgr_t *mgr, void *state);
 
 /** Magic value for or_state_t. */
 #define OR_STATE_MAGIC 0x57A73f57
@@ -174,6 +174,19 @@ static const config_format_t state_format = {
   &state_extra_var,
 };
 
+/* A global configuration manager for state-file objects */
+static config_mgr_t *state_mgr = NULL;
+
+/** Return the configuration manager for state-file objects. */
+static const config_mgr_t *
+get_state_mgr(void)
+{
+  if (PREDICT_UNLIKELY(state_mgr == NULL)) {
+    state_mgr = config_mgr_new(&state_format);
+  }
+  return state_mgr;
+}
+
 /** Persistent serialized state. */
 static or_state_t *global_state = NULL;
 
@@ -269,8 +282,9 @@ or_state_validate_cb(void *old_state, void *state, void *default_state,
 }
 
 static void
-or_state_free_cb(void *state)
+or_state_free_cb(const config_mgr_t *mgr, void *state)
 {
+  (void)mgr;
   or_state_free_(state);
 }
 
@@ -298,7 +312,7 @@ or_state_set(or_state_t *new_state)
   char *err = NULL;
   int ret = 0;
   tor_assert(new_state);
-  config_free(&state_format, global_state);
+  config_free(get_state_mgr(), global_state);
   global_state = new_state;
   if (entry_guards_parse_state(global_state, 1, &err)<0) {
     log_warn(LD_GENERAL,"%s",err);
@@ -363,7 +377,7 @@ or_state_new(void)
 {
   or_state_t *new_state = tor_malloc_zero(sizeof(or_state_t));
   new_state->magic_ = OR_STATE_MAGIC;
-  config_init(&state_format, new_state);
+  config_init(get_state_mgr(), new_state);
 
   return new_state;
 }
@@ -404,7 +418,7 @@ or_state_load(void)
     int assign_retval;
     if (config_get_lines(contents, &lines, 0)<0)
       goto done;
-    assign_retval = config_assign(&state_format, new_state,
+    assign_retval = config_assign(get_state_mgr(), new_state,
                                   lines, 0, &errmsg);
     config_free_lines(lines);
     if (assign_retval<0)
@@ -431,7 +445,7 @@ or_state_load(void)
     or_state_save_broken(fname);
 
     tor_free(contents);
-    config_free(&state_format, new_state);
+    config_free(get_state_mgr(), new_state);
 
     new_state = or_state_new();
   } else if (contents) {
@@ -464,7 +478,7 @@ or_state_load(void)
   tor_free(fname);
   tor_free(contents);
   if (new_state)
-    config_free(&state_format, new_state);
+    config_free(get_state_mgr(), new_state);
 
   return r;
 }
@@ -517,7 +531,7 @@ or_state_save(time_t now)
   tor_free(global_state->TorVersion);
   tor_asprintf(&global_state->TorVersion, "Tor %s", get_version());
 
-  state = config_dump(&state_format, NULL, global_state, 1, 0);
+  state = config_dump(get_state_mgr(), NULL, global_state, 1, 0);
   format_local_iso_time(tbuf, now);
   tor_asprintf(&contents,
                "# Tor state file last generated on %s local time\n"
@@ -727,7 +741,7 @@ or_state_free_(or_state_t *state)
   if (!state)
     return;
 
-  config_free(&state_format, state);
+  config_free(get_state_mgr(), state);
 }
 
 void
@@ -735,4 +749,5 @@ or_state_free_all(void)
 {
   or_state_free(global_state);
   global_state = NULL;
+  config_mgr_free(state_mgr);
 }
diff --git a/src/feature/dirauth/shared_random_state.c b/src/feature/dirauth/shared_random_state.c
index c2ad3e7cc..a552e621c 100644
--- a/src/feature/dirauth/shared_random_state.c
+++ b/src/feature/dirauth/shared_random_state.c
@@ -62,7 +62,7 @@ DUMMY_TYPECHECK_INSTANCE(sr_disk_state_t);
 static int
 disk_state_validate_cb(void *old_state, void *state, void *default_state,
                        int from_setconf, char **msg);
-static void disk_state_free_cb(void *);
+static void disk_state_free_cb(const config_mgr_t *mgr, void *);
 
 /* Array of variables that are saved to disk as a persistent state. */
 static const config_var_t state_vars[] = {
@@ -103,6 +103,19 @@ static const config_format_t state_format = {
   &state_extra_var,
 };
 
+/* Global configuration manager for the shared-random state file */
+static config_mgr_t *shared_random_state_mgr = NULL;
+
+/** Return the configuration manager for the shared-random state file. */
+static const config_mgr_t *
+get_srs_mgr(void)
+{
+  if (PREDICT_UNLIKELY(shared_random_state_mgr == NULL)) {
+    shared_random_state_mgr = config_mgr_new(&state_format);
+  }
+  return shared_random_state_mgr;
+}
+
 static void state_query_del_(sr_state_object_t obj_type, void *data);
 
 /* Return a string representation of a protocol phase. */
@@ -264,7 +277,7 @@ disk_state_free_(sr_disk_state_t *state)
   if (state == NULL) {
     return;
   }
-  config_free(&state_format, state);
+  config_free(get_srs_mgr(), state);
 }
 
 /* Allocate a new disk state, initialize it and return it. */
@@ -280,7 +293,7 @@ disk_state_new(time_t now)
   new_state->ValidAfter = now;
 
   /* Init config format. */
-  config_init(&state_format, new_state);
+  config_init(get_srs_mgr(), new_state);
   return new_state;
 }
 
@@ -349,8 +362,9 @@ disk_state_validate_cb(void *old_state, void *state, void *default_state,
 }
 
 static void
-disk_state_free_cb(void *state)
+disk_state_free_cb(const config_mgr_t *mgr, void *state)
 {
+  (void)mgr;
   disk_state_free_(state);
 }
 
@@ -683,7 +697,7 @@ disk_state_load_from_disk_impl(const char *fname)
     }
 
     disk_state = disk_state_new(time(NULL));
-    config_assign(&state_format, disk_state, lines, 0, &errmsg);
+    config_assign(get_srs_mgr(), disk_state, lines, 0, &errmsg);
     config_free_lines(lines);
     if (errmsg) {
       log_warn(LD_DIR, "SR: Reading state error: %s", errmsg);
@@ -736,7 +750,7 @@ disk_state_save_to_disk(void)
   /* Make sure that our disk state is up to date with our memory state
    * before saving it to disk. */
   disk_state_update();
-  state = config_dump(&state_format, NULL, sr_disk_state, 0, 0);
+  state = config_dump(get_srs_mgr(), NULL, sr_disk_state, 0, 0);
   format_local_iso_time(tbuf, now);
   tor_asprintf(&content,
                "# Tor shared random state file last generated on %s "
@@ -1278,6 +1292,7 @@ sr_state_free_all(void)
   /* Nullify our global state. */
   sr_state = NULL;
   sr_disk_state = NULL;
+  config_mgr_free(shared_random_state_mgr);
 }
 
 /* Save our current state in memory to disk. */
diff --git a/src/test/test_confparse.c b/src/test/test_confparse.c
index ec018f0c5..8a921531f 100644
--- a/src/test/test_confparse.c
+++ b/src/test/test_confparse.c
@@ -119,7 +119,7 @@ test_validate_cb(void *old_options, void *options, void *default_options,
   return 0;
 }
 
-static void test_free_cb(void *options);
+static void test_free_cb(const config_mgr_t *mgr, void *options);
 
 #define TEST_MAGIC 0x1337
 
@@ -139,12 +139,12 @@ static const config_format_t test_fmt = {
 };
 
 static void
-test_free_cb(void *options)
+test_free_cb(const config_mgr_t *mgr, void *options)
 {
   if (!options)
     return;
 
-  config_free(&test_fmt, options);
+  config_free(mgr, options);
 }
 
 /* Make sure that config_init sets everything to the right defaults. */
@@ -152,8 +152,9 @@ static void
 test_confparse_init(void *arg)
 {
   (void)arg;
-  test_struct_t *tst = config_new(&test_fmt);
-  config_init(&test_fmt, tst);
+  config_mgr_t *mgr = config_mgr_new(&test_fmt);
+  test_struct_t *tst = config_new(mgr);
+  config_init(mgr, tst);
 
   // Make sure that options are initialized right. */
   tt_uint_op(tst->magic, OP_EQ, TEST_MAGIC);
@@ -178,7 +179,8 @@ test_confparse_init(void *arg)
   tt_int_op(tst->hidden_int, OP_EQ, 0);
 
  done:
-  config_free(&test_fmt, tst);
+  config_free(mgr, tst);
+  config_mgr_free(mgr);
 }
 
 static const char simple_settings[] =
@@ -207,18 +209,18 @@ static const char simple_settings[] =
 
 /* Return a configuration object set up from simple_settings above. */
 static test_struct_t *
-get_simple_config(void)
+get_simple_config(const config_mgr_t *mgr)
 {
   test_struct_t *result = NULL;
-  test_struct_t *tst = config_new(&test_fmt);
+  test_struct_t *tst = config_new(mgr);
   config_line_t *lines = NULL;
   char *msg = NULL;
 
-  config_init(&test_fmt, tst);
+  config_init(mgr, tst);
 
   int r = config_get_lines(simple_settings, &lines, 0);
   tt_int_op(r, OP_EQ, 0);
-  r = config_assign(&test_fmt, tst, lines, 0, &msg);
+  r = config_assign(mgr, tst, lines, 0, &msg);
   tt_int_op(r, OP_EQ, 0);
   tt_ptr_op(msg, OP_EQ, NULL);
 
@@ -227,7 +229,7 @@ get_simple_config(void)
  done:
   tor_free(msg);
   config_free_lines(lines);
-  config_free(&test_fmt, tst);
+  config_free(mgr, tst);
   return result;
 }
 
@@ -236,7 +238,8 @@ static void
 test_confparse_assign_simple(void *arg)
 {
   (void)arg;
-  test_struct_t *tst = get_simple_config();
+  config_mgr_t *mgr = config_mgr_new(&test_fmt);
+  test_struct_t *tst = get_simple_config(mgr);
 
   tt_str_op(tst->s, OP_EQ, "this is a");
   tt_str_op(tst->fn, OP_EQ, "/simple/test of the");
@@ -284,10 +287,11 @@ test_confparse_assign_simple(void *arg)
   tt_str_op(tst->mixed_hidden_lines->next->value, OP_EQ, "ABC");
   tt_assert(!tst->mixed_hidden_lines->next->next);
 
-  tt_assert(config_check_ok(&test_fmt, tst, LOG_ERR));
+  tt_assert(config_check_ok(mgr, tst, LOG_ERR));
 
  done:
-  config_free(&test_fmt, tst);
+  config_free(mgr, tst);
+  config_mgr_free(mgr);
 }
 
 /* Try to assign to an obsolete option, and make sure we get a warning. */
@@ -295,26 +299,28 @@ static void
 test_confparse_assign_obsolete(void *arg)
 {
   (void)arg;
-  test_struct_t *tst = config_new(&test_fmt);
+  config_mgr_t *mgr = config_mgr_new(&test_fmt);
+  test_struct_t *tst = get_simple_config(mgr);
   config_line_t *lines = NULL;
   char *msg = NULL;
 
-  config_init(&test_fmt, tst);
+  config_init(mgr, tst);
 
   int r = config_get_lines("obsolete option here",
                            &lines, 0);
   tt_int_op(r, OP_EQ, 0);
   setup_capture_of_logs(LOG_WARN);
-  r = config_assign(&test_fmt, tst, lines, 0, &msg);
+  r = config_assign(mgr, tst, lines, 0, &msg);
   tt_int_op(r, OP_EQ, 0);
   tt_ptr_op(msg, OP_EQ, NULL);
   expect_single_log_msg_containing("Skipping obsolete configuration option");
 
  done:
   teardown_capture_of_logs();
-  config_free(&test_fmt, tst);
+  config_free(mgr, tst);
   config_free_lines(lines);
   tor_free(msg);
+  config_mgr_free(mgr);
 }
 
 /* Try to assign to an deprecated option, and make sure we get a warning
@@ -323,30 +329,32 @@ static void
 test_confparse_assign_deprecated(void *arg)
 {
   (void)arg;
-  test_struct_t *tst = config_new(&test_fmt);
+  config_mgr_t *mgr = config_mgr_new(&test_fmt);
+  test_struct_t *tst = get_simple_config(mgr);
   config_line_t *lines = NULL;
   char *msg = NULL;
 
-  config_init(&test_fmt, tst);
+  config_init(mgr, tst);
 
   int r = config_get_lines("deprecated_int 7",
                            &lines, 0);
   tt_int_op(r, OP_EQ, 0);
   setup_capture_of_logs(LOG_WARN);
-  r = config_assign(&test_fmt, tst, lines, CAL_WARN_DEPRECATIONS, &msg);
+  r = config_assign(mgr, tst, lines, CAL_WARN_DEPRECATIONS, &msg);
   tt_int_op(r, OP_EQ, 0);
   tt_ptr_op(msg, OP_EQ, NULL);
   expect_single_log_msg_containing("This integer is deprecated.");
 
   tt_int_op(tst->deprecated_int, OP_EQ, 7);
 
-  tt_assert(config_check_ok(&test_fmt, tst, LOG_ERR));
+  tt_assert(config_check_ok(mgr, tst, LOG_ERR));
 
  done:
   teardown_capture_of_logs();
-  config_free(&test_fmt, tst);
+  config_free(mgr, tst);
   config_free_lines(lines);
   tor_free(msg);
+  config_mgr_free(mgr);
 }
 
 /* Try to re-assign an option name that has been depreacted in favor of
@@ -355,16 +363,17 @@ static void
 test_confparse_assign_replaced(void *arg)
 {
   (void)arg;
-  test_struct_t *tst = config_new(&test_fmt);
+  config_mgr_t *mgr = config_mgr_new(&test_fmt);
+  test_struct_t *tst = get_simple_config(mgr);
   config_line_t *lines = NULL;
   char *msg = NULL;
 
-  config_init(&test_fmt, tst);
+  config_init(mgr, tst);
 
   int r = config_get_lines("float 1000\n", &lines, 0);
   tt_int_op(r, OP_EQ, 0);
   setup_capture_of_logs(LOG_WARN);
-  r = config_assign(&test_fmt, tst, lines, CAL_WARN_DEPRECATIONS, &msg);
+  r = config_assign(mgr, tst, lines, CAL_WARN_DEPRECATIONS, &msg);
   tt_int_op(r, OP_EQ, 0);
   tt_ptr_op(msg, OP_EQ, NULL);
   expect_single_log_msg_containing("use 'dbl' instead.");
@@ -374,9 +383,10 @@ test_confparse_assign_replaced(void *arg)
 
  done:
   teardown_capture_of_logs();
-  config_free(&test_fmt, tst);
+  config_free(mgr, tst);
   config_free_lines(lines);
   tor_free(msg);
+  config_mgr_free(mgr);
 }
 
 /* Try to set a linelist value with no option. */
@@ -384,25 +394,27 @@ static void
 test_confparse_assign_emptystring(void *arg)
 {
   (void)arg;
-  test_struct_t *tst = config_new(&test_fmt);
+  config_mgr_t *mgr = config_mgr_new(&test_fmt);
+  test_struct_t *tst = get_simple_config(mgr);
   config_line_t *lines = NULL;
   char *msg = NULL;
 
-  config_init(&test_fmt, tst);
+  config_init(mgr, tst);
 
   int r = config_get_lines("lines\n", &lines, 0);
   tt_int_op(r, OP_EQ, 0);
   setup_capture_of_logs(LOG_WARN);
-  r = config_assign(&test_fmt, tst, lines, 0, &msg);
+  r = config_assign(mgr, tst, lines, 0, &msg);
   tt_int_op(r, OP_EQ, 0);
   tt_ptr_op(msg, OP_EQ, NULL);
   expect_single_log_msg_containing("has no value");
 
  done:
   teardown_capture_of_logs();
-  config_free(&test_fmt, tst);
+  config_free(mgr, tst);
   config_free_lines(lines);
   tor_free(msg);
+  config_mgr_free(mgr);
 }
 
 /* Try to set a the same option twice; make sure we get a warning. */
@@ -410,26 +422,28 @@ static void
 test_confparse_assign_twice(void *arg)
 {
   (void)arg;
-  test_struct_t *tst = config_new(&test_fmt);
+  config_mgr_t *mgr = config_mgr_new(&test_fmt);
+  test_struct_t *tst = get_simple_config(mgr);
   config_line_t *lines = NULL;
   char *msg = NULL;
 
-  config_init(&test_fmt, tst);
+  config_init(mgr, tst);
 
   int r = config_get_lines("pos 10\n"
                            "pos 99\n", &lines, 0);
   tt_int_op(r, OP_EQ, 0);
   setup_capture_of_logs(LOG_WARN);
-  r = config_assign(&test_fmt, tst, lines, 0, &msg);
+  r = config_assign(mgr, tst, lines, 0, &msg);
   tt_int_op(r, OP_EQ, 0);
   tt_ptr_op(msg, OP_EQ, NULL);
   expect_single_log_msg_containing("used more than once");
 
  done:
   teardown_capture_of_logs();
-  config_free(&test_fmt, tst);
+  config_free(mgr, tst);
   config_free_lines(lines);
   tor_free(msg);
+  config_mgr_free(mgr);
 }
 
 typedef struct badval_test_t {
@@ -443,16 +457,17 @@ static void
 test_confparse_assign_badval(void *arg)
 {
   const badval_test_t *bt = arg;
-  test_struct_t *tst = config_new(&test_fmt);
+  config_mgr_t *mgr = config_mgr_new(&test_fmt);
+  test_struct_t *tst = get_simple_config(mgr);
   config_line_t *lines = NULL;
   char *msg = NULL;
 
-  config_init(&test_fmt, tst);
+  config_init(mgr, tst);
 
   int r = config_get_lines(bt->cfg, &lines, 0);
   tt_int_op(r, OP_EQ, 0);
   setup_capture_of_logs(LOG_WARN);
-  r = config_assign(&test_fmt, tst, lines, 0, &msg);
+  r = config_assign(mgr, tst, lines, 0, &msg);
   tt_int_op(r, OP_LT, 0);
   tt_ptr_op(msg, OP_NE, NULL);
   if (! strstr(msg, bt->expect_msg)) {
@@ -461,9 +476,10 @@ test_confparse_assign_badval(void *arg)
 
  done:
   teardown_capture_of_logs();
-  config_free(&test_fmt, tst);
+  config_free(mgr, tst);
   config_free_lines(lines);
   tor_free(msg);
+  config_mgr_free(mgr);
 }
 
 /* Various arguments for badval test.
@@ -495,11 +511,12 @@ static void
 test_confparse_dump(void *arg)
 {
   (void)arg;
-  test_struct_t *tst = get_simple_config();
+  config_mgr_t *mgr = config_mgr_new(&test_fmt);
+  test_struct_t *tst = get_simple_config(mgr);
   char *dumped = NULL;
 
   /* Minimal version. */
-  dumped = config_dump(&test_fmt, NULL, tst, 1, 0);
+  dumped = config_dump(mgr, NULL, tst, 1, 0);
   tt_str_op(dumped, OP_EQ,
             "s this is a\n"
             "fn /simple/test of the\n"
@@ -524,7 +541,7 @@ test_confparse_dump(void *arg)
 
   /* Maximal */
   tor_free(dumped);
-  dumped = config_dump(&test_fmt, NULL, tst, 0, 0);
+  dumped = config_dump(mgr, NULL, tst, 0, 0);
   tt_str_op(dumped, OP_EQ,
             "s this is a\n"
             "fn /simple/test of the\n"
@@ -550,7 +567,7 @@ test_confparse_dump(void *arg)
 
   /* commented */
   tor_free(dumped);
-  dumped = config_dump(&test_fmt, NULL, tst, 0, 1);
+  dumped = config_dump(mgr, NULL, tst, 0, 1);
   tt_str_op(dumped, OP_EQ,
             "s this is a\n"
             "fn /simple/test of the\n"
@@ -575,8 +592,9 @@ test_confparse_dump(void *arg)
                         "VisibleLineB ABC\n");
 
  done:
-  config_free(&test_fmt, tst);
+  config_free(mgr, tst);
   tor_free(dumped);
+  config_mgr_free(mgr);
 }
 
 /* Try confparse_reset_line(), and make sure it behaves correctly */
@@ -584,16 +602,18 @@ static void
 test_confparse_reset(void *arg)
 {
   (void)arg;
-  test_struct_t *tst = get_simple_config();
+  config_mgr_t *mgr = config_mgr_new(&test_fmt);
+  test_struct_t *tst = get_simple_config(mgr);
 
-  config_reset_line(&test_fmt, tst, "interval", 0);
+  config_reset_line(mgr, tst, "interval", 0);
   tt_int_op(tst->interval, OP_EQ, 0);
 
-  config_reset_line(&test_fmt, tst, "interval", 1);
+  config_reset_line(mgr, tst, "interval", 1);
   tt_int_op(tst->interval, OP_EQ, 10);
 
  done:
-  config_free(&test_fmt, tst);
+  config_free(mgr, tst);
+  config_mgr_free(mgr);
 }
 
 /* Try setting options a second time on a config object, and make sure
@@ -602,7 +622,8 @@ static void
 test_confparse_reassign(void *arg)
 {
   (void)arg;
-  test_struct_t *tst = get_simple_config();
+  config_mgr_t *mgr = config_mgr_new(&test_fmt);
+  test_struct_t *tst = get_simple_config(mgr);
   config_line_t *lines = NULL;
   char *msg = NULL, *rs = NULL;
 
@@ -613,7 +634,7 @@ test_confparse_reassign(void *arg)
          "csv 14,15\n"
          "routerset 127.0.0.1\n",
          &lines, 0);
-  r = config_assign(&test_fmt, tst,lines, 0, &msg);
+  r = config_assign(mgr, tst,lines, 0, &msg);
   tt_int_op(r, OP_EQ, 0);
   tt_ptr_op(msg, OP_EQ, NULL);
 
@@ -633,7 +654,7 @@ test_confparse_reassign(void *arg)
   tt_str_op(rs, OP_EQ, "127.0.0.1");
 
   // Try again with the CLEAR_FIRST and USE_DEFAULTS flags
-  r = config_assign(&test_fmt, tst, lines,
+  r = config_assign(mgr, tst, lines,
                     CAL_CLEAR_FIRST|CAL_USE_DEFAULTS, &msg);
   tt_int_op(r, OP_EQ, 0);
 
@@ -644,10 +665,11 @@ test_confparse_reassign(void *arg)
   tt_int_op(tst->i, OP_EQ, 12);
 
  done:
-  config_free(&test_fmt, tst);
+  config_free(mgr, tst);
   config_free_lines(lines);
   tor_free(msg);
   tor_free(rs);
+  config_mgr_free(mgr);
 }
 
 /* Try setting options a second time on a config object, using the +foo
@@ -656,7 +678,8 @@ static void
 test_confparse_reassign_extend(void *arg)
 {
   (void)arg;
-  test_struct_t *tst = get_simple_config();
+  config_mgr_t *mgr = config_mgr_new(&test_fmt);
+  test_struct_t *tst = get_simple_config(mgr);
   config_line_t *lines = NULL;
   char *msg = NULL;
 
@@ -664,7 +687,7 @@ test_confparse_reassign_extend(void *arg)
          "+lines 13\n",
          &lines, 1); // allow extended format.
   tt_int_op(r, OP_EQ, 0);
-  r = config_assign(&test_fmt, tst,lines, 0, &msg);
+  r = config_assign(mgr, tst,lines, 0, &msg);
   tt_int_op(r, OP_EQ, 0);
   tt_ptr_op(msg, OP_EQ, NULL);
 
@@ -684,27 +707,28 @@ test_confparse_reassign_extend(void *arg)
          "/lines\n",
          &lines, 1); // allow extended format.
   tt_int_op(r, OP_EQ, 0);
-  r = config_assign(&test_fmt, tst, lines, 0, &msg);
+  r = config_assign(mgr, tst, lines, 0, &msg);
   tt_int_op(r, OP_EQ, 0);
   tt_ptr_op(msg, OP_EQ, NULL);
   tt_assert(tst->lines == NULL);
   config_free_lines(lines);
 
-  config_free(&test_fmt, tst);
-  tst = get_simple_config();
+  config_free(mgr, tst);
+  tst = get_simple_config(mgr);
   r = config_get_lines(
          "/lines away!\n",
          &lines, 1); // allow extended format.
   tt_int_op(r, OP_EQ, 0);
-  r = config_assign(&test_fmt, tst, lines, 0, &msg);
+  r = config_assign(mgr, tst, lines, 0, &msg);
   tt_int_op(r, OP_EQ, 0);
   tt_ptr_op(msg, OP_EQ, NULL);
   tt_assert(tst->lines == NULL);
 
  done:
-  config_free(&test_fmt, tst);
+  config_free(mgr, tst);
   config_free_lines(lines);
   tor_free(msg);
+  config_mgr_free(mgr);
 }
 
 /* Test out confparse_get_assigned(). */
@@ -712,30 +736,32 @@ static void
 test_confparse_get_assigned(void *arg)
 {
   (void)arg;
-  test_struct_t *tst = get_simple_config();
+
+  config_mgr_t *mgr = config_mgr_new(&test_fmt);
+  test_struct_t *tst = get_simple_config(mgr);
   config_line_t *lines = NULL;
 
-  lines = config_get_assigned_option(&test_fmt, tst, "I", 1);
+  lines = config_get_assigned_option(mgr, tst, "I", 1);
   tt_assert(lines);
   tt_str_op(lines->key, OP_EQ, "i");
   tt_str_op(lines->value, OP_EQ, "3");
   tt_assert(lines->next == NULL);
   config_free_lines(lines);
 
-  lines = config_get_assigned_option(&test_fmt, tst, "s", 1);
+  lines = config_get_assigned_option(mgr, tst, "s", 1);
   tt_assert(lines);
   tt_str_op(lines->key, OP_EQ, "s");
   tt_str_op(lines->value, OP_EQ, "this is a");
   tt_assert(lines->next == NULL);
   config_free_lines(lines);
 
-  lines = config_get_assigned_option(&test_fmt, tst, "obsolete", 1);
+  lines = config_get_assigned_option(mgr, tst, "obsolete", 1);
   tt_assert(!lines);
 
-  lines = config_get_assigned_option(&test_fmt, tst, "nonesuch", 1);
+  lines = config_get_assigned_option(mgr, tst, "nonesuch", 1);
   tt_assert(!lines);
 
-  lines = config_get_assigned_option(&test_fmt, tst, "mixedlines", 1);
+  lines = config_get_assigned_option(mgr, tst, "mixedlines", 1);
   tt_assert(lines);
   tt_str_op(lines->key, OP_EQ, "LineTypeA");
   tt_str_op(lines->value, OP_EQ, "i d");
@@ -745,7 +771,7 @@ test_confparse_get_assigned(void *arg)
   tt_assert(lines->next->next == NULL);
   config_free_lines(lines);
 
-  lines = config_get_assigned_option(&test_fmt, tst, "linetypeb", 1);
+  lines = config_get_assigned_option(mgr, tst, "linetypeb", 1);
   tt_assert(lines);
   tt_str_op(lines->key, OP_EQ, "LineTypeB");
   tt_str_op(lines->value, OP_EQ, "i c");
@@ -754,7 +780,7 @@ test_confparse_get_assigned(void *arg)
 
   tor_free(tst->s);
   tst->s = tor_strdup("Hello\nWorld");
-  lines = config_get_assigned_option(&test_fmt, tst, "s", 1);
+  lines = config_get_assigned_option(mgr, tst, "s", 1);
   tt_assert(lines);
   tt_str_op(lines->key, OP_EQ, "s");
   tt_str_op(lines->value, OP_EQ, "\"Hello\\nWorld\"");
@@ -762,8 +788,9 @@ test_confparse_get_assigned(void *arg)
   config_free_lines(lines);
 
  done:
-  config_free(&test_fmt, tst);
+  config_free(mgr, tst);
   config_free_lines(lines);
+  config_mgr_free(mgr);
 }
 
 /* Another variant, which accepts and stores unrecognized lines.*/
@@ -796,24 +823,25 @@ static void
 test_confparse_extra_lines(void *arg)
 {
   (void)arg;
-  test_struct_t *tst = config_new(&etest_fmt);
+  config_mgr_t *mgr = config_mgr_new(&etest_fmt);
+  test_struct_t *tst = config_new(mgr);
   config_line_t *lines = NULL;
   char *msg = NULL, *dump = NULL;
 
-  config_init(&etest_fmt, tst);
+  config_init(mgr, tst);
 
   int r = config_get_lines(
       "unknotty addita\n"
       "pos 99\n"
       "wombat knish\n", &lines, 0);
   tt_int_op(r, OP_EQ, 0);
-  r = config_assign(&etest_fmt, tst, lines, 0, &msg);
+  r = config_assign(mgr, tst, lines, 0, &msg);
   tt_int_op(r, OP_EQ, 0);
   tt_ptr_op(msg, OP_EQ, NULL);
 
   tt_assert(tst->extra_lines);
 
-  dump = config_dump(&etest_fmt, NULL, tst, 1, 0);
+  dump = config_dump(mgr, NULL, tst, 1, 0);
   tt_str_op(dump, OP_EQ,
       "pos 99\n"
       "unknotty addita\n"
@@ -823,7 +851,8 @@ test_confparse_extra_lines(void *arg)
   tor_free(msg);
   tor_free(dump);
   config_free_lines(lines);
-  config_free(&etest_fmt, tst);
+  config_free(mgr, tst);
+  config_mgr_free(mgr);
 }
 
 static void
@@ -889,12 +918,14 @@ static void
 test_confparse_check_ok_fail(void *arg)
 {
   (void)arg;
-  test_struct_t *tst = config_new(&test_fmt);
+  config_mgr_t *mgr = config_mgr_new(&test_fmt);
+  test_struct_t *tst = config_new(mgr);
   tst->pos = -10;
-  tt_assert(! config_check_ok(&test_fmt, tst, LOG_INFO));
+  tt_assert(! config_check_ok(mgr, tst, LOG_INFO));
 
  done:
-  config_free(&test_fmt, tst);
+  config_free(mgr, tst);
+  config_mgr_free(mgr);
 }
 
 #define CONFPARSE_TEST(name, flags)                          \
diff --git a/src/test/test_helpers.c b/src/test/test_helpers.c
index b4389f2d1..31a6540ef 100644
--- a/src/test/test_helpers.c
+++ b/src/test/test_helpers.c
@@ -295,7 +295,7 @@ helper_parse_options(const char *conf)
   if (ret != 0) {
     goto done;
   }
-  ret = config_assign(&options_format, opt, line, 0, &msg);
+  ret = config_assign(get_options_mgr(), opt, line, 0, &msg);
   if (ret != 0) {
     goto done;
   }
diff --git a/src/test/test_options.c b/src/test/test_options.c
index b39cd4f1e..b6ab97b4a 100644
--- a/src/test/test_options.c
+++ b/src/test/test_options.c
@@ -96,7 +96,7 @@ clear_log_messages(void)
     opt->command = CMD_RUN_TOR;              \
     options_init(opt);                       \
                                              \
-    dflt = config_dup(&options_format, opt); \
+    dflt = config_dup(get_options_mgr(), opt); \
     clear_log_messages();                    \
   } while (0)
 
@@ -196,7 +196,7 @@ test_options_validate_impl(const char *configuration,
   if (r)
     goto done;
 
-  r = config_assign(&options_format, opt, cl, 0, &msg);
+  r = config_assign(get_options_mgr(), opt, cl, 0, &msg);
   if (phase == PH_ASSIGN) {
     if (test_options_checkmsgs(configuration, expect_errmsg,
                                expect_log_severity,
@@ -304,7 +304,7 @@ test_have_enough_mem_for_dircache(void *arg)
   r = config_get_lines(configuration, &cl, 1);
   tt_int_op(r, OP_EQ, 0);
 
-  r = config_assign(&options_format, opt, cl, 0, &msg);
+  r = config_assign(get_options_mgr(), opt, cl, 0, &msg);
   tt_int_op(r, OP_EQ, 0);
 
   /* 300 MB RAM available, DirCache enabled */
@@ -327,7 +327,7 @@ test_have_enough_mem_for_dircache(void *arg)
   r = config_get_lines(configuration, &cl, 1);
   tt_int_op(r, OP_EQ, 0);
 
-  r = config_assign(&options_format, opt, cl, 0, &msg);
+  r = config_assign(get_options_mgr(), opt, cl, 0, &msg);
   tt_int_op(r, OP_EQ, 0);
 
   /* 300 MB RAM available, DirCache enabled, Bridge */
@@ -350,7 +350,7 @@ test_have_enough_mem_for_dircache(void *arg)
   r = config_get_lines(configuration, &cl, 1);
   tt_int_op(r, OP_EQ, 0);
 
-  r = config_assign(&options_format, opt, cl, 0, &msg);
+  r = config_assign(get_options_mgr(), opt, cl, 0, &msg);
   tt_int_op(r, OP_EQ, 0);
 
   /* 200 MB RAM available, DirCache disabled */
@@ -438,7 +438,7 @@ get_options_test_data(const char *conf)
 
   rv = config_get_lines(conf, &cl, 1);
   tt_int_op(rv, OP_EQ, 0);
-  rv = config_assign(&options_format, result->opt, cl, 0, &msg);
+  rv = config_assign(get_options_mgr(), result->opt, cl, 0, &msg);
   if (msg) {
     /* Display the parse error message by comparing it with an empty string */
     tt_str_op(msg, OP_EQ, "");
@@ -449,7 +449,7 @@ get_options_test_data(const char *conf)
   result->opt->TokenBucketRefillInterval = 1;
   rv = config_get_lines(TEST_OPTIONS_OLD_VALUES, &cl, 1);
   tt_int_op(rv, OP_EQ, 0);
-  rv = config_assign(&options_format, result->def_opt, cl, 0, &msg);
+  rv = config_assign(get_options_mgr(), result->def_opt, cl, 0, &msg);
   if (msg) {
     /* Display the parse error message by comparing it with an empty string */
     tt_str_op(msg, OP_EQ, "");





More information about the tor-commits mailing list