LCOV - code coverage report
Current view: top level - lib/confmgt - confmgt.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 490 497 98.6 %
Date: 2021-11-24 03:28:48 Functions: 50 50 100.0 %

          Line data    Source code
       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-2021, The Tor Project, Inc. */
       5             : /* See LICENSE for licensing information */
       6             : 
       7             : /**
       8             :  * \file confmgt.c
       9             :  *
      10             :  * \brief Back-end for parsing and generating key-value files, used to
      11             :  *   implement the torrc file format and the state file.
      12             :  *
      13             :  * This module is used by config.c to parse and encode torrc
      14             :  * configuration files, and by statefile.c to parse and encode the
      15             :  * $DATADIR/state file.
      16             :  *
      17             :  * To use this module, its callers provide an instance of
      18             :  * config_format_t to describe the mappings from a set of configuration
      19             :  * options to a number of fields in a C structure.  With this mapping,
      20             :  * the functions here can convert back and forth between the C structure
      21             :  * specified, and a linked list of key-value pairs.
      22             :  */
      23             : 
      24             : #define CONFMGT_PRIVATE
      25             : #include "orconfig.h"
      26             : #include "lib/confmgt/confmgt.h"
      27             : 
      28             : #include "lib/confmgt/structvar.h"
      29             : #include "lib/confmgt/unitparse.h"
      30             : #include "lib/container/bitarray.h"
      31             : #include "lib/container/smartlist.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"
      36             : #include "lib/string/compat_ctype.h"
      37             : #include "lib/string/printf.h"
      38             : #include "lib/string/util_string.h"
      39             : 
      40             : #include "ext/siphash.h"
      41             : 
      42             : /**
      43             :  * A managed_var_t is an internal wrapper around a config_var_t in
      44             :  * a config_format_t structure.  It is used by config_mgr_t to
      45             :  * keep track of which option goes with which structure. */
      46             : typedef struct managed_var_t {
      47             :   /**
      48             :    * A pointer to the config_var_t for this option.
      49             :    */
      50             :   const config_var_t *cvar;
      51             :   /**
      52             :    * The index of the object in which this option is stored.  It is
      53             :    * IDX_TOPLEVEL to indicate that the object is the top-level object.
      54             :    **/
      55             :   int object_idx;
      56             : } 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             : 
      64             : /** Release all storage held in a managed_var_t. */
      65             : static void
      66      104654 : managed_var_free_(managed_var_t *mv)
      67             : {
      68      104654 :   if (!mv)
      69             :     return;
      70      104654 :   tor_free(mv);
      71             : }
      72             : #define managed_var_free(mv) \
      73             :   FREE_AND_NULL(managed_var_t, managed_var_free_, (mv))
      74             : 
      75             : struct config_suite_t {
      76             :   /** A list of configuration objects managed by a given configuration
      77             :    * manager. They are stored in the same order as the config_format_t
      78             :    * objects in the manager's list of subformats. */
      79             :   smartlist_t *configs;
      80             : };
      81             : 
      82             : /**
      83             :  * Allocate a new empty config_suite_t.
      84             :  **/
      85             : static config_suite_t *
      86        6722 : config_suite_new(void)
      87             : {
      88        6722 :   config_suite_t *suite = tor_malloc_zero(sizeof(config_suite_t));
      89        6722 :   suite->configs = smartlist_new();
      90        6722 :   return suite;
      91             : }
      92             : 
      93             : /** Release all storage held by a config_suite_t.  (Does not free
      94             :  * any configuration objects it holds; the caller must do that first.) */
      95             : static void
      96        6715 : config_suite_free_(config_suite_t *suite)
      97             : {
      98        6715 :   if (!suite)
      99             :     return;
     100        6715 :   smartlist_free(suite->configs);
     101        6715 :   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 {
     108             :   /** The 'top-level' configuration format.  This one is used for legacy
     109             :    * options that have not yet been assigned to different sub-modules.
     110             :    *
     111             :    * (NOTE: for now, this is the only config_format_t that a config_mgr_t
     112             :    * contains.  A subsequent commit will add more. XXXX)
     113             :    */
     114             :   const config_format_t *toplevel;
     115             :   /**
     116             :    * List of second-level configuration format objects that this manager
     117             :    * also knows about.
     118             :    */
     119             :   smartlist_t *subconfigs;
     120             :   /** A smartlist of managed_var_t objects for all configuration formats. */
     121             :   smartlist_t *all_vars;
     122             :   /** A smartlist of config_abbrev_t objects for all configuration
     123             :    * formats. These objects are used to track synonyms and abbreviations for
     124             :    * different configuration options. */
     125             :   smartlist_t *all_abbrevs;
     126             :   /** A smartlist of config_deprecation_t for all configuration formats. */
     127             :   smartlist_t *all_deprecations;
     128             :   /** True if this manager has been frozen and cannot have any more formats
     129             :    * added to it. A manager must be frozen before it can be used to construct
     130             :    * or manipulate objects. */
     131             :   bool frozen;
     132             :   /** A replacement for the magic number of the toplevel object. We override
     133             :    * that number to make it unique for this particular config_mgr_t, so that
     134             :    * an object constructed with one mgr can't be used with another, even if
     135             :    * those managers' contents are equal.
     136             :    */
     137             :   struct_magic_decl_t toplevel_magic;
     138             : };
     139             : 
     140             : #define IDX_TOPLEVEL (-1)
     141             : 
     142             : /** Create a new config_mgr_t to manage a set of configuration objects to be
     143             :  * wrapped under <b>toplevel_fmt</b>. */
     144             : config_mgr_t *
     145        5744 : config_mgr_new(const config_format_t *toplevel_fmt)
     146             : {
     147        5744 :   config_mgr_t *mgr = tor_malloc_zero(sizeof(config_mgr_t));
     148        5744 :   mgr->subconfigs = smartlist_new();
     149        5744 :   mgr->all_vars = smartlist_new();
     150        5744 :   mgr->all_abbrevs = smartlist_new();
     151        5744 :   mgr->all_deprecations = smartlist_new();
     152             : 
     153        5744 :   config_mgr_register_fmt(mgr, toplevel_fmt, IDX_TOPLEVEL);
     154        5744 :   mgr->toplevel = toplevel_fmt;
     155             : 
     156        5744 :   return mgr;
     157             : }
     158             : 
     159             : /** Add a config_format_t to a manager, with a specified (unique) index. */
     160             : static void
     161       22530 : config_mgr_register_fmt(config_mgr_t *mgr,
     162             :                         const config_format_t *fmt,
     163             :                         int object_idx)
     164             : {
     165       22530 :   int i;
     166             : 
     167       22530 :   tor_assertf(!mgr->frozen,
     168             :               "Tried to add a format to a configuration manager after "
     169             :               "it had been frozen.");
     170             : 
     171       22530 :   if (object_idx != IDX_TOPLEVEL) {
     172       16786 :     tor_assertf(! fmt->has_config_suite,
     173             :           "Tried to register a toplevel format in a non-toplevel position");
     174             :   }
     175       22530 :   if (fmt->config_suite_offset) {
     176        5673 :     tor_assertf(fmt->has_config_suite,
     177             :                 "config_suite_offset was set, but has_config_suite was not.");
     178             :   }
     179             : 
     180       22530 :   tor_assertf(fmt != mgr->toplevel &&
     181             :               ! smartlist_contains(mgr->subconfigs, fmt),
     182             :               "Tried to register an already-registered format.");
     183             : 
     184             :   /* register variables */
     185     2411036 :   for (i = 0; fmt->vars[i].member.name; ++i) {
     186     2388506 :     managed_var_t *mv = tor_malloc_zero(sizeof(managed_var_t));
     187     2388506 :     mv->cvar = &fmt->vars[i];
     188     2388506 :     mv->object_idx = object_idx;
     189     2388506 :     smartlist_add(mgr->all_vars, mv);
     190             :   }
     191             : 
     192             :   /* register abbrevs */
     193       22530 :   if (fmt->abbrevs) {
     194      300104 :     for (i = 0; fmt->abbrevs[i].abbreviated; ++i) {
     195      294395 :       smartlist_add(mgr->all_abbrevs, (void*)&fmt->abbrevs[i]);
     196             :     }
     197             :   }
     198             : 
     199             :   /* register deprecations. */
     200       22530 :   if (fmt->deprecations) {
     201             :     const config_deprecation_t *d;
     202       33418 :     for (d = fmt->deprecations; d->name; ++d) {
     203       27815 :       smartlist_add(mgr->all_deprecations, (void*)d);
     204             :     }
     205             :   }
     206       22530 : }
     207             : 
     208             : /**
     209             :  * Add a new format to this configuration object.  Asserts on failure.
     210             :  *
     211             :  * Returns an internal "index" value used to identify this format within
     212             :  * all of those formats contained in <b>mgr</b>.  This index value
     213             :  * should not generally be used outside of this module.
     214             :  **/
     215             : int
     216       16786 : config_mgr_add_format(config_mgr_t *mgr,
     217             :                       const config_format_t *fmt)
     218             : {
     219       16786 :   tor_assert(mgr);
     220       16786 :   int idx = smartlist_len(mgr->subconfigs);
     221       16786 :   config_mgr_register_fmt(mgr, fmt, idx);
     222       16786 :   smartlist_add(mgr->subconfigs, (void *)fmt);
     223       16786 :   return idx;
     224             : }
     225             : 
     226             : /** Return a pointer to the config_suite_t * pointer inside a
     227             :  * configuration object; returns NULL if there is no such member. */
     228             : static inline config_suite_t **
     229     1038380 : config_mgr_get_suite_ptr(const config_mgr_t *mgr, void *toplevel)
     230             : {
     231     1038380 :   if (! mgr->toplevel->has_config_suite)
     232             :     return NULL;
     233     1031507 :   return STRUCT_VAR_P(toplevel, mgr->toplevel->config_suite_offset);
     234             : }
     235             : 
     236             : /**
     237             :  * Return a pointer to the configuration object within <b>toplevel</b> whose
     238             :  * index is <b>idx</b>.
     239             :  *
     240             :  * NOTE: XXXX Eventually, there will be multiple objects supported within the
     241             :  * toplevel object.  For example, the or_options_t will contain pointers
     242             :  * to configuration objects for other modules.  This function gets
     243             :  * the sub-object for a particular module.
     244             :  */
     245             : void *
     246     4413689 : config_mgr_get_obj_mutable(const config_mgr_t *mgr, void *toplevel, int idx)
     247             : {
     248     4413689 :   tor_assert(mgr);
     249     4413689 :   tor_assert(toplevel);
     250     4413689 :   if (idx == IDX_TOPLEVEL)
     251             :     return toplevel;
     252             : 
     253      457122 :   tor_assertf(idx >= 0 && idx < smartlist_len(mgr->subconfigs),
     254             :               "Index %d is out of range.", idx);
     255      457122 :   config_suite_t **suite = config_mgr_get_suite_ptr(mgr, toplevel);
     256      457122 :   tor_assert(suite);
     257      457122 :   tor_assert(smartlist_len(mgr->subconfigs) ==
     258             :              smartlist_len((*suite)->configs));
     259             : 
     260      457122 :   return smartlist_get((*suite)->configs, idx);
     261             : }
     262             : 
     263             : /** As config_mgr_get_obj_mutable(), but return a const pointer. */
     264             : const void *
     265      171429 : config_mgr_get_obj(const config_mgr_t *mgr, const void *toplevel, int idx)
     266             : {
     267      171429 :   return config_mgr_get_obj_mutable(mgr, (void*)toplevel, idx);
     268             : }
     269             : 
     270             : /** Sorting helper for smartlist of managed_var_t */
     271             : static int
     272    15759720 : managed_var_cmp(const void **a, const void **b)
     273             : {
     274    15759720 :   const managed_var_t *mv1 = *(const managed_var_t**)a;
     275    15759720 :   const managed_var_t *mv2 = *(const managed_var_t**)b;
     276             : 
     277    15759720 :   return strcasecmp(mv1->cvar->member.name, mv2->cvar->member.name);
     278             : }
     279             : 
     280             : /**
     281             :  * Mark a configuration manager as "frozen", so that no more formats can be
     282             :  * added, and so that it can be used for manipulating configuration objects.
     283             :  **/
     284             : void
     285        5741 : config_mgr_freeze(config_mgr_t *mgr)
     286             : {
     287        5741 :   static uint64_t mgr_count = 0;
     288             : 
     289        5741 :   smartlist_sort(mgr->all_vars, managed_var_cmp);
     290        5741 :   memcpy(&mgr->toplevel_magic, &mgr->toplevel->magic,
     291             :          sizeof(struct_magic_decl_t));
     292        5741 :   uint64_t magic_input[3] = { mgr->toplevel_magic.magic_val,
     293        5741 :                               (uint64_t) (uintptr_t) mgr,
     294        5741 :                               ++mgr_count };
     295       11482 :   mgr->toplevel_magic.magic_val =
     296        5741 :     (uint32_t)siphash24g(magic_input, sizeof(magic_input));
     297        5741 :   mgr->frozen = true;
     298        5741 : }
     299             : 
     300             : /** Release all storage held in <b>mgr</b> */
     301             : void
     302        1087 : config_mgr_free_(config_mgr_t *mgr)
     303             : {
     304        1087 :   if (!mgr)
     305             :     return;
     306      104956 :   SMARTLIST_FOREACH(mgr->all_vars, managed_var_t *, mv, managed_var_free(mv));
     307         302 :   smartlist_free(mgr->all_vars);
     308         302 :   smartlist_free(mgr->all_abbrevs);
     309         302 :   smartlist_free(mgr->all_deprecations);
     310         302 :   smartlist_free(mgr->subconfigs);
     311         302 :   memset(mgr, 0, sizeof(*mgr));
     312         302 :   tor_free(mgr);
     313             : }
     314             : 
     315             : /** Return a new smartlist_t containing a config_var_t for every variable that
     316             :  * <b>mgr</b> knows about.  The elements of this smartlist do not need
     317             :  * to be freed; they have the same lifespan as <b>mgr</b>. */
     318             : smartlist_t *
     319         567 : config_mgr_list_vars(const config_mgr_t *mgr)
     320             : {
     321         567 :   smartlist_t *result = smartlist_new();
     322         567 :   tor_assert(mgr);
     323      242985 :   SMARTLIST_FOREACH(mgr->all_vars, managed_var_t *, mv,
     324             :                     smartlist_add(result, (void*) mv->cvar));
     325         567 :   return result;
     326             : }
     327             : 
     328             : /** Return a new smartlist_t containing the names of all deprecated variables.
     329             :  * The elements of this smartlist do not need to be freed; they have the same
     330             :  * lifespan as <b>mgr</b>.
     331             :  */
     332             : smartlist_t *
     333           2 : config_mgr_list_deprecated_vars(const config_mgr_t *mgr)
     334             : {
     335           2 :   smartlist_t *result = smartlist_new();
     336           2 :   tor_assert(mgr);
     337           5 :   SMARTLIST_FOREACH(mgr->all_deprecations, config_deprecation_t *, d,
     338             :                     smartlist_add(result, (char*)d->name));
     339           2 :   return result;
     340             : }
     341             : 
     342             : /**
     343             :  * Check the magic number on <b>object</b> to make sure it's a valid toplevel
     344             :  * object, created with <b>mgr</b>.  Exit with an assertion if it isn't.
     345             :  **/
     346             : void
     347        7193 : config_check_toplevel_magic(const config_mgr_t *mgr,
     348             :                             const void *object)
     349             : {
     350        7193 :   struct_check_magic(object, &mgr->toplevel_magic);
     351        7193 : }
     352             : 
     353             : /** Assert that the magic fields in <b>options</b> and its subsidiary
     354             :  * objects are all okay. */
     355             : static void
     356      566497 : config_mgr_assert_magic_ok(const config_mgr_t *mgr,
     357             :                            const void *options)
     358             : {
     359      566497 :   tor_assert(mgr);
     360      566497 :   tor_assert(options);
     361      566497 :   tor_assert(mgr->frozen);
     362      566497 :   struct_check_magic(options, &mgr->toplevel_magic);
     363             : 
     364      566497 :   config_suite_t **suitep = config_mgr_get_suite_ptr(mgr, (void*)options);
     365      566497 :   if (suitep == NULL) {
     366        6157 :     tor_assert(smartlist_len(mgr->subconfigs) == 0);
     367             :     return;
     368             :   }
     369             : 
     370      560340 :   tor_assert(smartlist_len((*suitep)->configs) ==
     371             :              smartlist_len(mgr->subconfigs));
     372     2230458 :   SMARTLIST_FOREACH_BEGIN(mgr->subconfigs, const config_format_t *, fmt) {
     373     1670118 :     void *obj = smartlist_get((*suitep)->configs, fmt_sl_idx);
     374     1670118 :     tor_assert(obj);
     375     1670118 :     struct_check_magic(obj, &fmt->magic);
     376     1670118 :   } SMARTLIST_FOREACH_END(fmt);
     377             : }
     378             : 
     379             : /** Macro: assert that <b>cfg</b> has the right magic field for
     380             :  * <b>mgr</b>. */
     381             : #define CONFIG_CHECK(mgr, cfg) STMT_BEGIN                               \
     382             :     config_mgr_assert_magic_ok((mgr), (cfg));                           \
     383             :   STMT_END
     384             : 
     385             : /** Allocate an empty configuration object of a given format type. */
     386             : void *
     387        6985 : config_new(const config_mgr_t *mgr)
     388             : {
     389        6985 :   tor_assert(mgr->frozen);
     390        6985 :   void *opts = tor_malloc_zero(mgr->toplevel->size);
     391        6985 :   struct_set_magic(opts, &mgr->toplevel_magic);
     392        6985 :   config_suite_t **suitep = config_mgr_get_suite_ptr(mgr, opts);
     393        6985 :   if (suitep) {
     394        6722 :     *suitep = config_suite_new();
     395       26642 :     SMARTLIST_FOREACH_BEGIN(mgr->subconfigs, const config_format_t *, fmt) {
     396       19920 :       void *obj = tor_malloc_zero(fmt->size);
     397       19920 :       struct_set_magic(obj, &fmt->magic);
     398       19920 :       smartlist_add((*suitep)->configs, obj);
     399       19920 :     } SMARTLIST_FOREACH_END(fmt);
     400             :   }
     401        6985 :   CONFIG_CHECK(mgr, opts);
     402        6985 :   return opts;
     403             : }
     404             : 
     405             : /*
     406             :  * Functions to parse config options
     407             :  */
     408             : 
     409             : /** If <b>option</b> is an official abbreviation for a longer option,
     410             :  * return the longer option.  Otherwise return <b>option</b>.
     411             :  * If <b>command_line</b> is set, apply all abbreviations.  Otherwise, only
     412             :  * apply abbreviations that work for the config file and the command line.
     413             :  * If <b>warn_obsolete</b> is set, warn about deprecated names. */
     414             : const char *
     415        3679 : config_expand_abbrev(const config_mgr_t *mgr, const char *option,
     416             :                      int command_line, int warn_obsolete)
     417             : {
     418      151302 :   SMARTLIST_FOREACH_BEGIN(mgr->all_abbrevs, const config_abbrev_t *, abbrev) {
     419             :     /* Abbreviations are case insensitive. */
     420      147623 :     if (!strcasecmp(option, abbrev->abbreviated) &&
     421          42 :         (command_line || !abbrev->commandline_only)) {
     422          38 :       if (warn_obsolete && abbrev->warn) {
     423           1 :         log_warn(LD_CONFIG,
     424             :                  "The configuration option '%s' is deprecated; "
     425             :                  "use '%s' instead.",
     426             :                  abbrev->abbreviated,
     427             :                  abbrev->full);
     428             :       }
     429             :       /* Keep going through the list in case we want to rewrite it more.
     430             :        * (We could imagine recursing here, but I don't want to get the
     431             :        * user into an infinite loop if we craft our list wrong.) */
     432          38 :       option = abbrev->full;
     433             :     }
     434      147623 :   } SMARTLIST_FOREACH_END(abbrev);
     435        3679 :   return option;
     436             : }
     437             : 
     438             : /** If <b>key</b> is a deprecated configuration option, return the message
     439             :  * explaining why it is deprecated (which may be an empty string). Return NULL
     440             :  * if it is not deprecated. The <b>key</b> field must be fully expanded. */
     441             : const char *
     442        1224 : config_find_deprecation(const config_mgr_t *mgr, const char *key)
     443             : {
     444        1224 :   if (BUG(mgr == NULL) || BUG(key == NULL))
     445             :     return NULL; // LCOV_EXCL_LINE
     446             : 
     447        7311 :   SMARTLIST_FOREACH_BEGIN(mgr->all_deprecations, const config_deprecation_t *,
     448             :                           d) {
     449        6096 :     if (!strcasecmp(d->name, key)) {
     450           9 :       return d->why_deprecated ? d->why_deprecated : "";
     451             :     }
     452        6087 :   } SMARTLIST_FOREACH_END(d);
     453             :   return NULL;
     454             : }
     455             : 
     456             : /**
     457             :  * Find the managed_var_t object for a variable whose name is <b>name</b>
     458             :  * according to <b>mgr</b>.   Return that object, or NULL if none exists.
     459             :  *
     460             :  * If <b>allow_truncated</b> is true, then accept any variable whose
     461             :  * name begins with <b>name</b>.
     462             :  *
     463             :  * If <b>idx_out</b> is not NULL, set *<b>idx_out</b> to the position of
     464             :  * that variable within mgr-&gt;all_vars, or to -1 if the variable is
     465             :  * not found.
     466             :  */
     467             : static const managed_var_t *
     468      285950 : config_mgr_find_var(const config_mgr_t *mgr,
     469             :                     const char *key,
     470             :                     bool allow_truncated, int *idx_out)
     471             : {
     472      285950 :   const size_t keylen = strlen(key);
     473      285950 :   if (idx_out)
     474        3266 :     *idx_out = -1;
     475             : 
     476      285950 :   if (!keylen)
     477             :     return NULL; /* if they say "--" on the command line, it's not an option */
     478             : 
     479             :   /* First, check for an exact (case-insensitive) match */
     480    61786044 :   SMARTLIST_FOREACH_BEGIN(mgr->all_vars, const managed_var_t *, mv) {
     481    61785982 :     if (!strcasecmp(mv->cvar->member.name, key)) {
     482      285888 :       if (idx_out)
     483        3211 :         *idx_out = mv_sl_idx;
     484      285888 :       return mv;
     485             :     }
     486    61500094 :   } SMARTLIST_FOREACH_END(mv);
     487             : 
     488          62 :   if (!allow_truncated)
     489             :     return NULL;
     490             : 
     491             :   /* If none, check for an abbreviated match */
     492       23237 :   SMARTLIST_FOREACH_BEGIN(mgr->all_vars, const managed_var_t *, mv) {
     493       23226 :     if (!strncasecmp(key, mv->cvar->member.name, keylen)) {
     494          51 :       log_warn(LD_CONFIG, "The abbreviation '%s' is deprecated. "
     495             :                "Please use '%s' instead",
     496             :                key, mv->cvar->member.name);
     497          51 :       if (idx_out)
     498          50 :         *idx_out = mv_sl_idx;
     499          51 :       return mv;
     500             :     }
     501       23175 :   } SMARTLIST_FOREACH_END(mv);
     502             : 
     503             :   /* Okay, unrecognized option */
     504             :   return NULL;
     505             : }
     506             : 
     507             : /**
     508             :  * If <b>key</b> is a name or an abbreviation configuration option, return
     509             :  * the corresponding canonical name for it.  Warn if the abbreviation is
     510             :  * non-standard.  Return NULL if the option does not exist.
     511             :  */
     512             : const char *
     513          18 : config_find_option_name(const config_mgr_t *mgr, const char *key)
     514             : {
     515          18 :   key = config_expand_abbrev(mgr, key, 0, 0);
     516          18 :   const managed_var_t *mv = config_mgr_find_var(mgr, key, true, NULL);
     517          18 :   if (mv)
     518          13 :     return mv->cvar->member.name;
     519             :   else
     520             :     return NULL;
     521             : }
     522             : 
     523             : /** Return the number of option entries in <b>fmt</b>. */
     524             : static int
     525        2143 : config_count_options(const config_mgr_t *mgr)
     526             : {
     527        2143 :   return smartlist_len(mgr->all_vars);
     528             : }
     529             : 
     530             : /**
     531             :  * Return true iff at least one bit from <b>flag</b> is set on <b>var</b>,
     532             :  * either in <b>var</b>'s flags, or on the flags of its type.
     533             :  **/
     534             : static bool
     535      621234 : config_var_has_flag(const config_var_t *var, uint32_t flag)
     536             : {
     537      621234 :   uint32_t have_flags = var->flags | struct_var_get_flags(&var->member);
     538             : 
     539      621234 :   return (have_flags & flag) != 0;
     540             : }
     541             : 
     542             : /**
     543             :  * Return true if assigning a value to <b>var</b> replaces the previous
     544             :  * value.  Return false if assigning a value to <b>var</b> appends
     545             :  * to the previous value.
     546             :  **/
     547             : static bool
     548        3261 : config_var_is_replaced_on_set(const config_var_t *var)
     549             : {
     550        3261 :   return ! config_var_has_flag(var, CFLG_NOREPLACE);
     551             : }
     552             : 
     553             : /**
     554             :  * Return true iff <b>var</b> may be assigned by name (e.g., via the
     555             :  * CLI, the configuration files, or the controller API).
     556             :  **/
     557             : bool
     558         429 : config_var_is_settable(const config_var_t *var)
     559             : {
     560         429 :   return ! config_var_has_flag(var, CFLG_NOSET);
     561             : }
     562             : 
     563             : /**
     564             :  * Return true iff the controller is allowed to fetch the value of
     565             :  * <b>var</b>.
     566             :  **/
     567             : static bool
     568       10192 : config_var_is_gettable(const config_var_t *var)
     569             : {
     570             :   /* Arguably, invisible or obsolete options should not be gettable.  However,
     571             :    * they have been gettable for a long time, and making them ungettable could
     572             :    * have compatibility effects.  For now, let's leave them alone.
     573             :    */
     574             : 
     575             :   // return ! config_var_has_flag(var, CVFLAG_OBSOLETE|CFGLAGS_INVISIBLE);
     576       10192 :   (void)var;
     577       10192 :   return true;
     578             : }
     579             : 
     580             : /**
     581             :  * Return true iff we need to check <b>var</b> for changes when we are
     582             :  * comparing config options for changes.
     583             :  *
     584             :  * A false result might mean that the variable is a derived variable, and that
     585             :  * comparing the variable it derives from compares this one too-- or it might
     586             :  * mean that there is no data to compare.
     587             :  **/
     588             : static bool
     589        2145 : config_var_should_list_changes(const config_var_t *var)
     590             : {
     591        2145 :   return ! config_var_has_flag(var, CFLG_NOCMP);
     592             : }
     593             : 
     594             : /**
     595             :  * Return true iff we need to copy the data for <b>var</b> when we are
     596             :  * copying a config option.
     597             :  *
     598             :  * A false option might mean that the variable is a derived variable, and that
     599             :  * copying the variable it derives from copies it-- or it might mean that
     600             :  * there is no data to copy.
     601             :  **/
     602             : static bool
     603      100815 : config_var_needs_copy(const config_var_t *var)
     604             : {
     605      100815 :   return ! config_var_has_flag(var, CFLG_NOCOPY);
     606             : }
     607             : 
     608             : /**
     609             :  * Return true iff variable <b>var</b> should appear on list of variable
     610             :  * names given to the controller or the CLI.
     611             :  *
     612             :  * (Note that this option is imperfectly obeyed. The
     613             :  * --list-torrc-options command looks at the "settable" flag, whereas
     614             :  * "GETINFO config/defaults" and "list_deprecated_*()" do not filter
     615             :  * their results. It would be good for consistency to try to converge
     616             :  * these behaviors in the future.)
     617             :  **/
     618             : bool
     619         429 : config_var_is_listable(const config_var_t *var)
     620             : {
     621         429 :   return ! config_var_has_flag(var, CFLG_NOLIST);
     622             : }
     623             : 
     624             : /**
     625             :  * Return true iff variable <b>var</b> should be written out when we
     626             :  * are writing our configuration to disk, to a controller, or via the
     627             :  * --dump-config command.
     628             :  *
     629             :  * This option may be set because a variable is hidden, or because it is
     630             :  * derived from another variable which will already be written out.
     631             :  **/
     632             : static bool
     633       48834 : config_var_is_dumpable(const config_var_t *var)
     634             : {
     635       48834 :   return ! config_var_has_flag(var, CFLG_NODUMP);
     636             : }
     637             : 
     638             : /*
     639             :  * Functions to assign config options.
     640             :  */
     641             : 
     642             : /** <b>c</b>-\>key is known to be a real key. Update <b>options</b>
     643             :  * with <b>c</b>-\>value and return 0, or return -1 if bad value.
     644             :  *
     645             :  * Called from config_assign_line() and option_reset().
     646             :  */
     647             : static int
     648      231416 : config_assign_value(const config_mgr_t *mgr, void *options,
     649             :                     config_line_t *c, char **msg)
     650             : {
     651      231416 :   const managed_var_t *var;
     652             : 
     653      231416 :   CONFIG_CHECK(mgr, options);
     654             : 
     655      231416 :   var = config_mgr_find_var(mgr, c->key, true, NULL);
     656      231416 :   tor_assert(var);
     657      231416 :   tor_assert(!strcmp(c->key, var->cvar->member.name));
     658      231416 :   void *object = config_mgr_get_obj_mutable(mgr, options, var->object_idx);
     659             : 
     660      231416 :   if (config_var_has_flag(var->cvar, CFLG_WARN_OBSOLETE)) {
     661         141 :     log_warn(LD_GENERAL, "Skipping obsolete configuration option \"%s\".",
     662             :              var->cvar->member.name);
     663      231275 :   } else if (config_var_has_flag(var->cvar, CFLG_WARN_DISABLED)) {
     664           0 :     log_warn(LD_GENERAL, "This copy of Tor was built without support for "
     665             :              "the option \"%s\". Skipping.", var->cvar->member.name);
     666             :   }
     667             : 
     668      231416 :   return struct_var_kvassign(object, c, msg, &var->cvar->member);
     669             : }
     670             : 
     671             : /** Mark every linelist in <b>options</b> "fragile", so that fresh assignments
     672             :  * to it will replace old ones. */
     673             : static void
     674        2113 : config_mark_lists_fragile(const config_mgr_t *mgr, void *options)
     675             : {
     676        2113 :   tor_assert(mgr);
     677        2113 :   tor_assert(options);
     678             : 
     679      872808 :   SMARTLIST_FOREACH_BEGIN(mgr->all_vars, const managed_var_t *, mv) {
     680      870695 :     void *object = config_mgr_get_obj_mutable(mgr, options, mv->object_idx);
     681      870695 :     struct_var_mark_fragile(object, &mv->cvar->member);
     682      870695 :   } SMARTLIST_FOREACH_END(mv);
     683        2113 : }
     684             : 
     685             : /**
     686             :  * Log a warning that declaring that the option called <b>what</b>
     687             :  * is deprecated because of the reason in <b>why</b>.
     688             :  *
     689             :  * (Both arguments must be non-NULL.)
     690             :  **/
     691             : void
     692          13 : warn_deprecated_option(const char *what, const char *why)
     693             : {
     694          13 :   const char *space = (why && strlen(why)) ? " " : "";
     695          13 :   log_warn(LD_CONFIG, "The %s option is deprecated, and will most likely "
     696             :            "be removed in a future version of Tor.%s%s (If you think this is "
     697             :            "a mistake, please let us know!)",
     698             :            what, space, why);
     699          13 : }
     700             : 
     701             : /** If <b>c</b> is a syntactically valid configuration line, update
     702             :  * <b>options</b> with its value and return 0.  Otherwise return -1 for bad
     703             :  * key, -2 for bad value.
     704             :  *
     705             :  * If <b>clear_first</b> is set, clear the value first. Then if
     706             :  * <b>use_defaults</b> is set, set the value to the default.
     707             :  *
     708             :  * Called from config_assign().
     709             :  */
     710             : static int
     711        3266 : config_assign_line(const config_mgr_t *mgr, void *options,
     712             :                    config_line_t *c, unsigned flags,
     713             :                    bitarray_t *options_seen, char **msg)
     714             : {
     715        3266 :   const unsigned use_defaults = flags & CAL_USE_DEFAULTS;
     716        3266 :   const unsigned clear_first = flags & CAL_CLEAR_FIRST;
     717        3266 :   const unsigned warn_deprecations = flags & CAL_WARN_DEPRECATIONS;
     718        3266 :   const managed_var_t *mvar;
     719             : 
     720        3266 :   CONFIG_CHECK(mgr, options);
     721             : 
     722        3266 :   int var_index = -1;
     723        3266 :   mvar = config_mgr_find_var(mgr, c->key, true, &var_index);
     724        3266 :   if (!mvar) {
     725           5 :     const config_format_t *fmt = mgr->toplevel;
     726           5 :     if (fmt->extra) {
     727           3 :       void *lvalue = STRUCT_VAR_P(options, fmt->extra->offset);
     728           3 :       log_info(LD_CONFIG,
     729             :                "Found unrecognized option '%s'; saving it.", c->key);
     730           3 :       config_line_append((config_line_t**)lvalue, c->key, c->value);
     731           3 :       return 0;
     732             :     } else {
     733           2 :       tor_asprintf(msg,
     734             :                 "Unknown option '%s'.  Failing.", c->key);
     735           2 :       return -1;
     736             :     }
     737             :   }
     738             : 
     739        3261 :   const config_var_t *cvar = mvar->cvar;
     740        3261 :   tor_assert(cvar);
     741             : 
     742             :   /* Put keyword into canonical case. */
     743        3261 :   if (strcmp(cvar->member.name, c->key)) {
     744         338 :     tor_free(c->key);
     745         338 :     c->key = tor_strdup(cvar->member.name);
     746             :   }
     747             : 
     748        3261 :   const char *deprecation_msg;
     749        3261 :   if (warn_deprecations &&
     750        1222 :       (deprecation_msg = config_find_deprecation(mgr, cvar->member.name))) {
     751           7 :     warn_deprecated_option(cvar->member.name, deprecation_msg);
     752             :   }
     753             : 
     754        3261 :   if (!strlen(c->value)) {
     755             :     /* reset or clear it, then return */
     756          32 :     if (!clear_first) {
     757          32 :       if (! config_var_is_replaced_on_set(cvar) &&
     758          25 :           c->command != CONFIG_LINE_CLEAR) {
     759             :         /* We got an empty linelist from the torrc or command line.
     760             :            As a special case, call this an error. Warn and ignore. */
     761          15 :         log_warn(LD_CONFIG,
     762             :                  "Linelist option '%s' has no value. Skipping.", c->key);
     763             :       } else { /* not already cleared */
     764          17 :         config_reset(mgr, options, mvar, use_defaults);
     765             :       }
     766             :     }
     767          32 :     return 0;
     768        3229 :   } else if (c->command == CONFIG_LINE_CLEAR && !clear_first) {
     769             :     // This block is unreachable, since a CLEAR line always has an
     770             :     // empty value, and so will trigger be handled by the previous
     771             :     // "if (!strlen(c->value))" block.
     772             : 
     773             :     // LCOV_EXCL_START
     774             :     tor_assert_nonfatal_unreached();
     775             :     config_reset(mgr, options, mvar, use_defaults);
     776             :     // LCOV_EXCL_STOP
     777             :   }
     778             : 
     779        3229 :   if (options_seen && config_var_is_replaced_on_set(cvar)) {
     780             :     /* We're tracking which options we've seen, and this option is not
     781             :      * supposed to occur more than once. */
     782        2096 :     tor_assert(var_index >= 0);
     783        2096 :     if (bitarray_is_set(options_seen, var_index)) {
     784           1 :       log_warn(LD_CONFIG, "Option '%s' used more than once; all but the last "
     785             :                "value will be ignored.", cvar->member.name);
     786             :     }
     787        2096 :     bitarray_set(options_seen, var_index);
     788             :   }
     789             : 
     790        3229 :   if (config_assign_value(mgr, options, c, msg) < 0)
     791          28 :     return -2;
     792             :   return 0;
     793             : }
     794             : 
     795             : /** Restore the option named <b>key</b> in options to its default value.
     796             :  * Called from config_assign(). */
     797             : STATIC void
     798           8 : config_reset_line(const config_mgr_t *mgr, void *options,
     799             :                   const char *key, int use_defaults)
     800             : {
     801           8 :   const managed_var_t *var;
     802             : 
     803           8 :   CONFIG_CHECK(mgr, options);
     804             : 
     805           8 :   var = config_mgr_find_var(mgr, key, true, NULL);
     806           8 :   if (!var)
     807             :     return; /* give error on next pass. */
     808             : 
     809           8 :   config_reset(mgr, options, var, use_defaults);
     810             : }
     811             : 
     812             : /** Return true iff value needs to be quoted and escaped to be used in
     813             :  * a configuration file. */
     814             : static int
     815        1581 : config_value_needs_escape(const char *value)
     816             : {
     817        1581 :   if (*value == '\"')
     818             :     return 1;
     819       35894 :   while (*value) {
     820       34314 :     switch (*value)
     821             :     {
     822             :     case '\r':
     823             :     case '\n':
     824             :     case '#':
     825             :       /* Note: quotes and backspaces need special handling when we are using
     826             :        * quotes, not otherwise, so they don't trigger escaping on their
     827             :        * own. */
     828             :       return 1;
     829       34313 :     default:
     830       34313 :       if (!TOR_ISPRINT(*value))
     831             :         return 1;
     832             :     }
     833       34313 :     ++value;
     834             :   }
     835             :   return 0;
     836             : }
     837             : 
     838             : /** Return newly allocated line or lines corresponding to <b>key</b> in the
     839             :  * configuration <b>options</b>.  If <b>escape_val</b> is true and a
     840             :  * value needs to be quoted before it's put in a config file, quote and
     841             :  * escape that value. Return NULL if no such key exists. */
     842             : config_line_t *
     843       10193 : config_get_assigned_option(const config_mgr_t *mgr, const void *options,
     844             :                            const char *key, int escape_val)
     845             : {
     846       10193 :   const managed_var_t *var;
     847       10193 :   config_line_t *result;
     848             : 
     849       10193 :   tor_assert(options && key);
     850             : 
     851       10193 :   CONFIG_CHECK(mgr, options);
     852             : 
     853       10193 :   var = config_mgr_find_var(mgr, key, true, NULL);
     854       10193 :   if (!var) {
     855           1 :     log_warn(LD_CONFIG, "Unknown option '%s'.  Failing.", key);
     856           1 :     return NULL;
     857             :   }
     858       10192 :   if (! config_var_is_gettable(var->cvar)) {
     859           0 :     log_warn(LD_CONFIG, "Option '%s' is obsolete or unfetchable. Failing.",
     860             :              key);
     861           0 :     return NULL;
     862             :   }
     863       10192 :   const void *object = config_mgr_get_obj(mgr, options, var->object_idx);
     864             : 
     865       10192 :   result = struct_var_kvencode(object, &var->cvar->member);
     866             : 
     867       10192 :   if (escape_val) {
     868             :     config_line_t *line;
     869        3328 :     for (line = result; line; line = line->next) {
     870        1581 :       if (line->value && config_value_needs_escape(line->value)) {
     871           1 :         char *newval = esc_for_log(line->value);
     872           1 :         tor_free(line->value);
     873           1 :         line->value = newval;
     874             :       }
     875             :     }
     876             :   }
     877             : 
     878             :   return result;
     879             : }
     880             : /** Iterate through the linked list of requested options <b>list</b>.
     881             :  * For each item, convert as appropriate and assign to <b>options</b>.
     882             :  * If an item is unrecognized, set *msg and return -1 immediately,
     883             :  * else return 0 for success.
     884             :  *
     885             :  * If <b>clear_first</b>, interpret config options as replacing (not
     886             :  * extending) their previous values. If <b>clear_first</b> is set,
     887             :  * then <b>use_defaults</b> to decide if you set to defaults after
     888             :  * clearing, or make the value 0 or NULL.
     889             :  *
     890             :  * Here are the use cases:
     891             :  * 1. A non-empty AllowInvalid line in your torrc. Appends to current
     892             :  *    if linelist, replaces current if csv.
     893             :  * 2. An empty AllowInvalid line in your torrc. Should clear it.
     894             :  * 3. "RESETCONF AllowInvalid" sets it to default.
     895             :  * 4. "SETCONF AllowInvalid" makes it NULL.
     896             :  * 5. "SETCONF AllowInvalid=foo" clears it and sets it to "foo".
     897             :  *
     898             :  * Use_defaults   Clear_first
     899             :  *    0                0       "append"
     900             :  *    1                0       undefined, don't use
     901             :  *    0                1       "set to null first"
     902             :  *    1                1       "set to defaults first"
     903             :  * Return 0 on success, -1 on bad key, -2 on bad value.
     904             :  *
     905             :  * As an additional special case, if a LINELIST config option has
     906             :  * no value and clear_first is 0, then warn and ignore it.
     907             :  */
     908             : 
     909             : /*
     910             : There are three call cases for config_assign() currently.
     911             : 
     912             : Case one: Torrc entry
     913             : options_init_from_torrc() calls config_assign(0, 0)
     914             :   calls config_assign_line(0, 0).
     915             :     if value is empty, calls config_reset(0) and returns.
     916             :     calls config_assign_value(), appends.
     917             : 
     918             : Case two: setconf
     919             : options_trial_assign() calls config_assign(0, 1)
     920             :   calls config_reset_line(0)
     921             :     calls config_reset(0)
     922             :       calls option_clear().
     923             :   calls config_assign_line(0, 1).
     924             :     if value is empty, returns.
     925             :     calls config_assign_value(), appends.
     926             : 
     927             : Case three: resetconf
     928             : options_trial_assign() calls config_assign(1, 1)
     929             :   calls config_reset_line(1)
     930             :     calls config_reset(1)
     931             :       calls option_clear().
     932             :       calls config_assign_value(default)
     933             :   calls config_assign_line(1, 1).
     934             :     returns.
     935             : */
     936             : int
     937        2143 : config_assign(const config_mgr_t *mgr, void *options, config_line_t *list,
     938             :               unsigned config_assign_flags, char **msg)
     939             : {
     940        2143 :   config_line_t *p;
     941        2143 :   bitarray_t *options_seen;
     942        2143 :   const int n_options = config_count_options(mgr);
     943        2143 :   const unsigned clear_first = config_assign_flags & CAL_CLEAR_FIRST;
     944        2143 :   const unsigned use_defaults = config_assign_flags & CAL_USE_DEFAULTS;
     945             : 
     946        2143 :   CONFIG_CHECK(mgr, options);
     947             : 
     948             :   /* pass 1: normalize keys */
     949        7555 :   for (p = list; p; p = p->next) {
     950        3269 :     const char *full = config_expand_abbrev(mgr, p->key, 0, 1);
     951        3269 :     if (strcmp(full,p->key)) {
     952          35 :       tor_free(p->key);
     953          35 :       p->key = tor_strdup(full);
     954             :     }
     955             :   }
     956             : 
     957             :   /* pass 2: if we're reading from a resetting source, clear all
     958             :    * mentioned config options, and maybe set to their defaults. */
     959        2143 :   if (clear_first) {
     960           6 :     for (p = list; p; p = p->next)
     961           5 :       config_reset_line(mgr, options, p->key, use_defaults);
     962             :   }
     963             : 
     964        2143 :   options_seen = bitarray_init_zero(n_options);
     965             :   /* pass 3: assign. */
     966        5379 :   while (list) {
     967        3266 :     int r;
     968        3266 :     if ((r=config_assign_line(mgr, options, list, config_assign_flags,
     969             :                               options_seen, msg))) {
     970          30 :       bitarray_free(options_seen);
     971          30 :       return r;
     972             :     }
     973        3236 :     list = list->next;
     974             :   }
     975        2113 :   bitarray_free(options_seen);
     976             : 
     977             :   /** Now we're done assigning a group of options to the configuration.
     978             :    * Subsequent group assignments should _replace_ linelists, not extend
     979             :    * them. */
     980        2113 :   config_mark_lists_fragile(mgr, options);
     981             : 
     982        2113 :   return 0;
     983             : }
     984             : 
     985             : /** Reset config option <b>var</b> to 0, 0.0, NULL, or the equivalent.
     986             :  * Called from config_reset() and config_free(). */
     987             : static void
     988     3063579 : config_clear(const config_mgr_t *mgr, void *options, const managed_var_t *var)
     989             : {
     990     3063579 :   void *object = config_mgr_get_obj_mutable(mgr, options, var->object_idx);
     991     3063579 :   struct_var_free(object, &var->cvar->member);
     992     3063579 : }
     993             : 
     994             : /** Clear the option indexed by <b>var</b> in <b>options</b>. Then if
     995             :  * <b>use_defaults</b>, set it to its default value.
     996             :  * Called by config_init() and option_reset_line() and option_assign_line(). */
     997             : static void
     998      228209 : config_reset(const config_mgr_t *mgr, void *options,
     999             :              const managed_var_t *var, int use_defaults)
    1000             : {
    1001      228209 :   config_line_t *c;
    1002      228209 :   char *msg = NULL;
    1003      228209 :   CONFIG_CHECK(mgr, options);
    1004      228209 :   config_clear(mgr, options, var); /* clear it first */
    1005             : 
    1006      228209 :   if (!use_defaults)
    1007          19 :     return; /* all done */
    1008             : 
    1009      228190 :   if (var->cvar->initvalue) {
    1010      228187 :     c = tor_malloc_zero(sizeof(config_line_t));
    1011      228187 :     c->key = tor_strdup(var->cvar->member.name);
    1012      228187 :     c->value = tor_strdup(var->cvar->initvalue);
    1013      228187 :     if (config_assign_value(mgr, options, c, &msg) < 0) {
    1014             :       // LCOV_EXCL_START
    1015             :       log_warn(LD_BUG, "Failed to assign default: %s", msg);
    1016             :       tor_free(msg); /* if this happens it's a bug */
    1017             :       // LCOV_EXCL_STOP
    1018             :     }
    1019      228190 :     config_free_lines(c);
    1020             :   }
    1021             : }
    1022             : 
    1023             : /** Release storage held by <b>options</b>. */
    1024             : void
    1025        7833 : config_free_(const config_mgr_t *mgr, void *options)
    1026             : {
    1027        7833 :   if (!options)
    1028             :     return;
    1029             : 
    1030        6965 :   tor_assert(mgr);
    1031             : 
    1032        6965 :   if (mgr->toplevel->clear_fn) {
    1033        6591 :     mgr->toplevel->clear_fn(mgr, options);
    1034             :   }
    1035        6965 :   config_suite_t **suitep = config_mgr_get_suite_ptr(mgr, options);
    1036        6965 :   if (suitep) {
    1037        6715 :     tor_assert(smartlist_len((*suitep)->configs) ==
    1038             :                smartlist_len(mgr->subconfigs));
    1039       26624 :     SMARTLIST_FOREACH_BEGIN(mgr->subconfigs, const config_format_t *, fmt) {
    1040       19909 :       void *obj = smartlist_get((*suitep)->configs, fmt_sl_idx);
    1041       19909 :       if (fmt->clear_fn) {
    1042          12 :         fmt->clear_fn(mgr, obj);
    1043             :       }
    1044       19909 :     } SMARTLIST_FOREACH_END(fmt);
    1045             :   }
    1046             : 
    1047     2842335 :   SMARTLIST_FOREACH_BEGIN(mgr->all_vars, const managed_var_t *, mv) {
    1048     2835370 :     config_clear(mgr, options, mv);
    1049     2835370 :   } SMARTLIST_FOREACH_END(mv);
    1050             : 
    1051        6965 :   if (mgr->toplevel->extra) {
    1052         291 :     config_line_t **linep = STRUCT_VAR_P(options,
    1053             :                                          mgr->toplevel->extra->offset);
    1054         291 :     config_free_lines(*linep);
    1055         291 :     *linep = NULL;
    1056             :   }
    1057             : 
    1058        6965 :   if (suitep) {
    1059       26624 :     SMARTLIST_FOREACH((*suitep)->configs, void *, obj, tor_free(obj));
    1060        6715 :     config_suite_free(*suitep);
    1061             :   }
    1062             : 
    1063        6965 :   tor_free(options);
    1064             : }
    1065             : 
    1066             : /** Return true iff the option <b>name</b> has the same value in <b>o1</b>
    1067             :  * and <b>o2</b>.  Must not be called for LINELIST_S or OBSOLETE options.
    1068             :  */
    1069             : int
    1070       41049 : config_is_same(const config_mgr_t *mgr,
    1071             :                const void *o1, const void *o2,
    1072             :                const char *name)
    1073             : {
    1074       41049 :   CONFIG_CHECK(mgr, o1);
    1075       41049 :   CONFIG_CHECK(mgr, o2);
    1076             : 
    1077       41049 :   const managed_var_t *var = config_mgr_find_var(mgr, name, true, NULL);
    1078       41049 :   if (!var) {
    1079             :     return true;
    1080             :   }
    1081       41049 :   const void *obj1 = config_mgr_get_obj(mgr, o1, var->object_idx);
    1082       41049 :   const void *obj2 = config_mgr_get_obj(mgr, o2, var->object_idx);
    1083             : 
    1084       41049 :   return struct_var_eq(obj1, obj2, &var->cvar->member);
    1085             : }
    1086             : 
    1087             : /**
    1088             :  * Return a list of the options which have changed between <b>options1</b> and
    1089             :  * <b>options2</b>. If an option has reverted to its default value, it has a
    1090             :  * value entry of NULL.
    1091             :  *
    1092             :  * <b>options1</b> and <b>options2</b> must be top-level configuration objects
    1093             :  * of the type managed by <b>mgr</b>.
    1094             :  **/
    1095             : config_line_t *
    1096           5 : config_get_changes(const config_mgr_t *mgr,
    1097             :                    const void *options1, const void *options2)
    1098             : {
    1099           5 :   config_line_t *result = NULL;
    1100           5 :   config_line_t **next = &result;
    1101        2150 :   SMARTLIST_FOREACH_BEGIN(mgr->all_vars, managed_var_t *, mv) {
    1102        2145 :     if (! config_var_should_list_changes(mv->cvar)) {
    1103             :       /* something else will check this var, or it doesn't need checking */
    1104         530 :       continue;
    1105             :     }
    1106        1615 :     const void *obj1 = config_mgr_get_obj(mgr, options1, mv->object_idx);
    1107        1615 :     const void *obj2 = config_mgr_get_obj(mgr, options2, mv->object_idx);
    1108             : 
    1109        1615 :     if (struct_var_eq(obj1, obj2, &mv->cvar->member)) {
    1110        1611 :       continue;
    1111             :     }
    1112             : 
    1113           4 :     const char *varname = mv->cvar->member.name;
    1114           4 :     config_line_t *line =
    1115           4 :       config_get_assigned_option(mgr, options2, varname, 1);
    1116             : 
    1117           4 :     if (line) {
    1118           4 :       *next = line;
    1119             :     } else {
    1120           0 :       *next = tor_malloc_zero(sizeof(config_line_t));
    1121           0 :       (*next)->key = tor_strdup(varname);
    1122             :     }
    1123           8 :     while (*next)
    1124           4 :       next = &(*next)->next;
    1125        2145 :   } SMARTLIST_FOREACH_END(mv);
    1126             : 
    1127           5 :   return result;
    1128             : }
    1129             : 
    1130             : /** Copy storage held by <b>old</b> into a new or_options_t and return it. */
    1131             : void *
    1132         235 : config_dup(const config_mgr_t *mgr, const void *old)
    1133             : {
    1134         235 :   void *newopts;
    1135             : 
    1136         235 :   newopts = config_new(mgr);
    1137      101050 :   SMARTLIST_FOREACH_BEGIN(mgr->all_vars, managed_var_t *, mv) {
    1138      100815 :     if (! config_var_needs_copy(mv->cvar)) {
    1139             :       // Something else will copy this option, or it doesn't need copying.
    1140       24910 :       continue;
    1141             :     }
    1142       75905 :     const void *oldobj = config_mgr_get_obj(mgr, old, mv->object_idx);
    1143       75905 :     void *newobj = config_mgr_get_obj_mutable(mgr, newopts, mv->object_idx);
    1144       75905 :     if (struct_var_copy(newobj, oldobj, &mv->cvar->member) < 0) {
    1145             :       // LCOV_EXCL_START
    1146             :       log_err(LD_BUG, "Unable to copy value for %s.",
    1147             :               mv->cvar->member.name);
    1148             :       tor_assert_unreached();
    1149             :       // LCOV_EXCL_STOP
    1150             :     }
    1151      100815 :   } SMARTLIST_FOREACH_END(mv);
    1152             : 
    1153         235 :   return newopts;
    1154             : }
    1155             : /** Set all vars in the configuration object <b>options</b> to their default
    1156             :  * values. */
    1157             : void
    1158        1368 : config_init(const config_mgr_t *mgr, void *options)
    1159             : {
    1160        1368 :   CONFIG_CHECK(mgr, options);
    1161             : 
    1162      420198 :   SMARTLIST_FOREACH_BEGIN(mgr->all_vars, const managed_var_t *, mv) {
    1163      418830 :     if (!mv->cvar->initvalue)
    1164      190646 :       continue; /* defaults to NULL or 0 */
    1165      228184 :     config_reset(mgr, options, mv, 1);
    1166      418830 :   } SMARTLIST_FOREACH_END(mv);
    1167        1368 : }
    1168             : 
    1169             : /**
    1170             :  * Helper for config_validate_single: see whether any immutable option
    1171             :  * has changed between old_options and new_options.
    1172             :  *
    1173             :  * On success return 0; on failure set *msg_out to a newly allocated
    1174             :  * string explaining what is wrong, and return -1.
    1175             :  */
    1176             : static int
    1177          37 : config_check_immutable_flags(const config_format_t *fmt,
    1178             :                              const void *old_options,
    1179             :                              const void *new_options,
    1180             :                              char **msg_out)
    1181             : {
    1182          37 :   tor_assert(fmt);
    1183          37 :   tor_assert(new_options);
    1184          37 :   if (BUG(! old_options))
    1185           0 :     return 0;
    1186             : 
    1187             :   unsigned i;
    1188        2666 :   for (i = 0; fmt->vars[i].member.name; ++i) {
    1189        2630 :     const config_var_t *v = &fmt->vars[i];
    1190        2630 :     if (! config_var_has_flag(v, CFLG_IMMUTABLE))
    1191        2500 :       continue;
    1192             : 
    1193         130 :     if (! struct_var_eq(old_options, new_options, &v->member)) {
    1194           1 :       tor_asprintf(msg_out,
    1195             :                    "While Tor is running, changing %s is not allowed",
    1196           1 :                    v->member.name);
    1197           1 :       return -1;
    1198             :     }
    1199             :   }
    1200             : 
    1201             :   return 0;
    1202             : }
    1203             : 
    1204             : /**
    1205             :  * Normalize and validate a single object `options` within a configuration
    1206             :  * suite, according to its format.  `options` may be modified as appropriate
    1207             :  * in order to set ancillary data.  If `old_options` is provided, make sure
    1208             :  * that the transition from `old_options` to `options` is permitted.
    1209             :  *
    1210             :  * On success return VSTAT_OK; on failure set *msg_out to a newly allocated
    1211             :  * string explaining what is wrong, and return a different validation_status_t
    1212             :  * to describe which step failed.
    1213             :  **/
    1214             : static validation_status_t
    1215        2549 : config_validate_single(const config_format_t *fmt,
    1216             :                        const void *old_options, void *options,
    1217             :                        char **msg_out)
    1218             : {
    1219        2549 :   tor_assert(fmt);
    1220        2549 :   tor_assert(options);
    1221             : 
    1222        2549 :   if (fmt->pre_normalize_fn) {
    1223         584 :     if (fmt->pre_normalize_fn(options, msg_out) < 0) {
    1224             :       return VSTAT_PRE_NORMALIZE_ERR;
    1225             :     }
    1226             :   }
    1227             : 
    1228        2547 :   if (fmt->legacy_validate_fn) {
    1229         591 :     if (fmt->legacy_validate_fn(old_options, options, msg_out) < 0) {
    1230             :       return VSTAT_LEGACY_ERR;
    1231             :     }
    1232             :   }
    1233             : 
    1234        2356 :   if (fmt->validate_fn) {
    1235        1165 :     if (fmt->validate_fn(options, msg_out) < 0) {
    1236             :       return VSTAT_VALIDATE_ERR;
    1237             :     }
    1238             :   }
    1239             : 
    1240        2351 :   if (old_options) {
    1241          37 :     if (config_check_immutable_flags(fmt, old_options, options, msg_out) < 0) {
    1242             :       return VSTAT_TRANSITION_ERR;
    1243             :     }
    1244             : 
    1245          36 :     if (fmt->check_transition_fn) {
    1246           8 :       if (fmt->check_transition_fn(old_options, options, msg_out) < 0) {
    1247             :         return VSTAT_TRANSITION_ERR;
    1248             :       }
    1249             :     }
    1250             :   }
    1251             : 
    1252        2349 :   if (fmt->post_normalize_fn) {
    1253           4 :     if (fmt->post_normalize_fn(options, msg_out) < 0) {
    1254           0 :       return VSTAT_POST_NORMALIZE_ERR;
    1255             :     }
    1256             :   }
    1257             : 
    1258             :   return VSTAT_OK;
    1259             : }
    1260             : 
    1261             : /**
    1262             :  * Normalize and validate all the options in configuration object `options`
    1263             :  * and its sub-objects. `options` may be modified as appropriate in order to
    1264             :  * set ancillary data.  If `old_options` is provided, make sure that the
    1265             :  * transition from `old_options` to `options` is permitted.
    1266             :  *
    1267             :  * On success return VSTAT_OK; on failure set *msg_out to a newly allocated
    1268             :  * string explaining what is wrong, and return a different validation_status_t
    1269             :  * to describe which step failed.
    1270             :  **/
    1271             : validation_status_t
    1272         798 : config_validate(const config_mgr_t *mgr,
    1273             :                 const void *old_options, void *options,
    1274             :                 char **msg_out)
    1275             : {
    1276         798 :   validation_status_t rv;
    1277         798 :   CONFIG_CHECK(mgr, options);
    1278         798 :   if (old_options) {
    1279          13 :     CONFIG_CHECK(mgr, old_options);
    1280             :   }
    1281             : 
    1282         798 :   config_suite_t **suitep_new = config_mgr_get_suite_ptr(mgr, options);
    1283         798 :   config_suite_t **suitep_old = NULL;
    1284         798 :   if (old_options)
    1285          13 :     suitep_old = config_mgr_get_suite_ptr(mgr, (void*) old_options);
    1286             : 
    1287             :   /* Validate the sub-objects */
    1288         798 :   if (suitep_new) {
    1289        2346 :     SMARTLIST_FOREACH_BEGIN(mgr->subconfigs, const config_format_t *, fmt) {
    1290        1759 :       void *obj = smartlist_get((*suitep_new)->configs, fmt_sl_idx);
    1291        1759 :       const void *obj_old=NULL;
    1292        1759 :       if (suitep_old)
    1293          32 :         obj_old = smartlist_get((*suitep_old)->configs, fmt_sl_idx);
    1294             : 
    1295        1759 :       rv = config_validate_single(fmt, obj_old, obj, msg_out);
    1296        1759 :       if (rv < 0)
    1297           8 :         return rv;
    1298        1751 :     } SMARTLIST_FOREACH_END(fmt);
    1299             :   }
    1300             : 
    1301             :   /* Validate the top-level object. */
    1302         790 :   rv = config_validate_single(mgr->toplevel, old_options, options, msg_out);
    1303         790 :   if (rv < 0)
    1304             :     return rv;
    1305             : 
    1306             :   return VSTAT_OK;
    1307             : }
    1308             : 
    1309             : /** Allocate and return a new string holding the written-out values of the vars
    1310             :  * in 'options'.  If 'minimal', do not write out any default-valued vars.
    1311             :  * Else, if comment_defaults, write default values as comments.
    1312             :  */
    1313             : char *
    1314         289 : config_dump(const config_mgr_t *mgr, const void *default_options,
    1315             :             const void *options, int minimal,
    1316             :             int comment_defaults)
    1317             : {
    1318         289 :   const config_format_t *fmt = mgr->toplevel;
    1319         289 :   smartlist_t *elements;
    1320         289 :   const void *defaults = default_options;
    1321         289 :   void *defaults_tmp = NULL;
    1322         289 :   config_line_t *line, *assigned;
    1323         289 :   char *result;
    1324         289 :   char *msg = NULL;
    1325             : 
    1326         289 :   if (defaults == NULL) {
    1327         178 :     defaults = defaults_tmp = config_new(mgr);
    1328         178 :     config_init(mgr, defaults_tmp);
    1329             :   }
    1330             : 
    1331             :   /* XXX use a 1 here so we don't add a new log line while dumping */
    1332         289 :   if (default_options == NULL) {
    1333         178 :     if (config_validate(mgr, NULL, defaults_tmp, &msg) < 0) {
    1334             :       // LCOV_EXCL_START
    1335             :       log_err(LD_BUG, "Failed to validate default config: %s", msg);
    1336             :       tor_free(msg);
    1337             :       tor_assert(0);
    1338             :       // LCOV_EXCL_STOP
    1339             :     }
    1340             :   }
    1341             : 
    1342         289 :   elements = smartlist_new();
    1343       49123 :   SMARTLIST_FOREACH_BEGIN(mgr->all_vars, managed_var_t *, mv) {
    1344       48834 :     int comment_option = 0;
    1345             :     /* Don't save 'hidden' control variables. */
    1346       48834 :     if (! config_var_is_dumpable(mv->cvar))
    1347       13018 :       continue;
    1348       35816 :     const char *name = mv->cvar->member.name;
    1349       35816 :     if (minimal && config_is_same(mgr, options, defaults, name))
    1350       34083 :       continue;
    1351        1753 :     else if (comment_defaults &&
    1352          20 :              config_is_same(mgr, options, defaults, name))
    1353           1 :       comment_option = 1;
    1354             : 
    1355        1733 :     line = assigned =
    1356        1733 :       config_get_assigned_option(mgr, options, name, 1);
    1357             : 
    1358        5034 :     for (; line; line = line->next) {
    1359        1568 :       if (!strcmpstart(line->key, "__")) {
    1360             :         /* This check detects "hidden" variables inside LINELIST_V structures.
    1361             :          */
    1362           6 :         continue;
    1363             :       }
    1364        1562 :       int value_exists = line->value && *(line->value);
    1365        3123 :       smartlist_add_asprintf(elements, "%s%s%s%s\n",
    1366             :                    comment_option ? "# " : "",
    1367             :                    line->key, value_exists ? " " : "", line->value);
    1368             :     }
    1369        1733 :     config_free_lines(assigned);
    1370       48834 :   } SMARTLIST_FOREACH_END(mv);
    1371             : 
    1372         289 :   if (fmt->extra) {
    1373         175 :     line = *(config_line_t**)STRUCT_VAR_P(options, fmt->extra->offset);
    1374         177 :     for (; line; line = line->next) {
    1375           2 :       int value_exists = line->value && *(line->value);
    1376           2 :       smartlist_add_asprintf(elements, "%s%s%s\n",
    1377             :                              line->key, value_exists ? " " : "", line->value);
    1378             :     }
    1379             :   }
    1380             : 
    1381         289 :   result = smartlist_join_strings(elements, "", 0, NULL);
    1382        1853 :   SMARTLIST_FOREACH(elements, char *, cp, tor_free(cp));
    1383         289 :   smartlist_free(elements);
    1384         289 :   config_free(mgr, defaults_tmp);
    1385         289 :   return result;
    1386             : }
    1387             : 
    1388             : /**
    1389             :  * Return true if every member of <b>options</b> is in-range and well-formed.
    1390             :  * Return false otherwise.  Log errors at level <b>severity</b>.
    1391             :  */
    1392             : bool
    1393           3 : config_check_ok(const config_mgr_t *mgr, const void *options, int severity)
    1394             : {
    1395           3 :   bool all_ok = true;
    1396             : 
    1397          78 :   SMARTLIST_FOREACH_BEGIN(mgr->all_vars, const managed_var_t *, mv) {
    1398          75 :     if (!struct_var_ok(options, &mv->cvar->member)) {
    1399           1 :       log_fn(severity, LD_BUG, "Invalid value for %s",
    1400             :              mv->cvar->member.name);
    1401           1 :       all_ok = false;
    1402             :     }
    1403          75 :   } SMARTLIST_FOREACH_END(mv);
    1404             : 
    1405           3 :   return all_ok;
    1406             : }

Generated by: LCOV version 1.14