tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

type_defs.c (20912B)


      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 type_defs.c
      9 * @brief Definitions for various low-level configuration types.
     10 *
     11 * This module creates a number of var_type_def_t objects, to be used by
     12 * typedvar.c in manipulating variables.
     13 *
     14 * The types here are common types that can be implemented with Tor's
     15 * low-level functionality.  To define new types, see var_type_def_st.h.
     16 **/
     17 
     18 #include "orconfig.h"
     19 #include "lib/conf/conftypes.h"
     20 #include "lib/conf/confdecl.h"
     21 #include "lib/confmgt/typedvar.h"
     22 #include "lib/confmgt/type_defs.h"
     23 #include "lib/confmgt/unitparse.h"
     24 
     25 #include "lib/cc/compat_compiler.h"
     26 #include "lib/container/smartlist.h"
     27 #include "lib/encoding/confline.h"
     28 #include "lib/encoding/time_fmt.h"
     29 #include "lib/log/escape.h"
     30 #include "lib/log/log.h"
     31 #include "lib/log/util_bug.h"
     32 #include "lib/malloc/malloc.h"
     33 #include "lib/string/parse_int.h"
     34 #include "lib/string/printf.h"
     35 
     36 #include "lib/confmgt/var_type_def_st.h"
     37 
     38 #include <stddef.h>
     39 #include <string.h>
     40 #include <errno.h>
     41 
     42 //////
     43 // CONFIG_TYPE_STRING
     44 // CONFIG_TYPE_FILENAME
     45 //
     46 // These two types are the same for now, but they have different names.
     47 //
     48 // Warning: For this type, the default value (NULL) and "" are considered
     49 // different values.  That is generally risky, and best avoided for other
     50 // types in the future.
     51 //////
     52 
     53 static int
     54 string_parse(void *target, const char *value, char **errmsg,
     55             const void *params)
     56 {
     57  (void)params;
     58  (void)errmsg;
     59  char **p = (char**)target;
     60  *p = tor_strdup(value);
     61  return 0;
     62 }
     63 
     64 static char *
     65 string_encode(const void *value, const void *params)
     66 {
     67  (void)params;
     68  const char **p = (const char**)value;
     69  return *p ? tor_strdup(*p) : NULL;
     70 }
     71 
     72 static void
     73 string_clear(void *value, const void *params)
     74 {
     75  (void)params;
     76  char **p = (char**)value;
     77  tor_free(*p); // sets *p to NULL.
     78 }
     79 
     80 static const var_type_fns_t string_fns = {
     81  .parse = string_parse,
     82  .encode = string_encode,
     83  .clear = string_clear,
     84 };
     85 
     86 /////
     87 // CONFIG_TYPE_INT
     88 // CONFIG_TYPE_POSINT
     89 //
     90 // These types are implemented as int, possibly with a restricted range.
     91 /////
     92 
     93 /**
     94 * Parameters for parsing an integer type.
     95 **/
     96 typedef struct int_type_params_t {
     97  int minval; /**< Lowest allowed value */
     98  int maxval; /**< Highest allowed value */
     99 } int_parse_params_t;
    100 
    101 static const int_parse_params_t INT_PARSE_UNRESTRICTED = {
    102  .minval = INT_MIN,
    103  .maxval = INT_MAX,
    104 };
    105 
    106 static const int_parse_params_t INT_PARSE_POSINT = {
    107  .minval = 0,
    108  .maxval = INT_MAX,
    109 };
    110 
    111 static int
    112 int_parse(void *target, const char *value, char **errmsg, const void *params)
    113 {
    114  const int_parse_params_t *pp;
    115  if (params) {
    116    pp = params;
    117  } else {
    118    pp = &INT_PARSE_UNRESTRICTED;
    119  }
    120  int *p = target;
    121  int ok=0;
    122  *p = (int)tor_parse_long(value, 10, pp->minval, pp->maxval, &ok, NULL);
    123  if (!ok) {
    124    tor_asprintf(errmsg, "Integer %s is malformed or out of bounds. "
    125                 "Allowed values are between %d and %d.",
    126                 value, pp->minval, pp->maxval);
    127    return -1;
    128  }
    129  return 0;
    130 }
    131 
    132 static char *
    133 int_encode(const void *value, const void *params)
    134 {
    135  (void)params;
    136  int v = *(int*)value;
    137  char *result;
    138  tor_asprintf(&result, "%d", v);
    139  return result;
    140 }
    141 
    142 static void
    143 int_clear(void *value, const void *params)
    144 {
    145  (void)params;
    146  *(int*)value = 0;
    147 }
    148 
    149 static bool
    150 int_ok(const void *value, const void *params)
    151 {
    152  const int_parse_params_t *pp = params;
    153  if (pp) {
    154    int v = *(int*)value;
    155    return pp->minval <= v && v <= pp->maxval;
    156  } else {
    157    return true;
    158  }
    159 }
    160 
    161 static const var_type_fns_t int_fns = {
    162  .parse = int_parse,
    163  .encode = int_encode,
    164  .clear = int_clear,
    165  .ok = int_ok,
    166 };
    167 
    168 /////
    169 // CONFIG_TYPE_UINT64
    170 //
    171 // This type is an unrestricted u64.
    172 /////
    173 
    174 static int
    175 uint64_parse(void *target, const char *value, char **errmsg,
    176             const void *params)
    177 {
    178  (void)params;
    179  (void)errmsg;
    180  uint64_t *p = target;
    181  int ok=0;
    182  *p = tor_parse_uint64(value, 10, 0, UINT64_MAX, &ok, NULL);
    183  if (!ok) {
    184    tor_asprintf(errmsg, "Integer %s is malformed or out of bounds.",
    185                 value);
    186    return -1;
    187  }
    188  return 0;
    189 }
    190 
    191 static char *
    192 uint64_encode(const void *value, const void *params)
    193 {
    194  (void)params;
    195  uint64_t v = *(uint64_t*)value;
    196  char *result;
    197  tor_asprintf(&result, "%"PRIu64, v);
    198  return result;
    199 }
    200 
    201 static void
    202 uint64_clear(void *value, const void *params)
    203 {
    204  (void)params;
    205  *(uint64_t*)value = 0;
    206 }
    207 
    208 static const var_type_fns_t uint64_fns = {
    209  .parse = uint64_parse,
    210  .encode = uint64_encode,
    211  .clear = uint64_clear,
    212 };
    213 
    214 /////
    215 // CONFIG_TYPE_INTERVAL
    216 // CONFIG_TYPE_MSEC_INTERVAL
    217 // CONFIG_TYPE_MEMUNIT
    218 //
    219 // These types are implemented using the config_parse_units() function.
    220 // The intervals are stored as ints, whereas memory units are stored as
    221 // uint64_ts.
    222 /////
    223 
    224 static int
    225 units_parse_u64(void *target, const char *value, char **errmsg,
    226                const void *params)
    227 {
    228  const unit_table_t *table = params;
    229  tor_assert(table);
    230  uint64_t *v = (uint64_t*)target;
    231  int ok=1;
    232  char *msg = NULL;
    233  *v = config_parse_units(value, table, &ok, &msg);
    234  if (!ok) {
    235    tor_asprintf(errmsg, "Provided value is malformed or out of bounds: %s",
    236                 msg);
    237    tor_free(msg);
    238    return -1;
    239  }
    240  if (BUG(msg)) {
    241    tor_free(msg);
    242  }
    243  return 0;
    244 }
    245 
    246 static int
    247 units_parse_int(void *target, const char *value, char **errmsg,
    248               const void *params)
    249 {
    250  const unit_table_t *table = params;
    251  tor_assert(table);
    252  int *v = (int*)target;
    253  int ok=1;
    254  char *msg = NULL;
    255  uint64_t u64 = config_parse_units(value, table, &ok, &msg);
    256  if (!ok) {
    257    tor_asprintf(errmsg, "Provided value is malformed or out of bounds: %s",
    258                 msg);
    259    tor_free(msg);
    260    return -1;
    261  }
    262  if (BUG(msg)) {
    263    tor_free(msg);
    264  }
    265  if (u64 > INT_MAX) {
    266    tor_asprintf(errmsg, "Provided value %s is too large", value);
    267    return -1;
    268  }
    269  *v = (int) u64;
    270  return 0;
    271 }
    272 
    273 static bool
    274 units_ok_int(const void *value, const void *params)
    275 {
    276  (void)params;
    277  int v = *(int*)value;
    278  return v >= 0;
    279 }
    280 
    281 static const var_type_fns_t memunit_fns = {
    282  .parse = units_parse_u64,
    283  .encode = uint64_encode, // doesn't use params
    284  .clear = uint64_clear, // doesn't use params
    285 };
    286 
    287 static const var_type_fns_t interval_fns = {
    288  .parse = units_parse_int,
    289  .encode = int_encode, // doesn't use params
    290  .clear = int_clear, // doesn't use params,
    291  .ok = units_ok_int // can't use int_ok, since that expects int params.
    292 };
    293 
    294 /////
    295 // CONFIG_TYPE_DOUBLE
    296 //
    297 // This is a nice simple double.
    298 /////
    299 
    300 static int
    301 double_parse(void *target, const char *value, char **errmsg,
    302             const void *params)
    303 {
    304  (void)params;
    305  (void)errmsg;
    306  double *v = (double*)target;
    307  char *endptr=NULL;
    308  errno = 0;
    309  *v = strtod(value, &endptr);
    310  if (endptr == value || *endptr != '\0') {
    311    // Either there are no converted characters, or there were some characters
    312    // that didn't get converted.
    313    tor_asprintf(errmsg, "Could not convert %s to a number.", escaped(value));
    314    return -1;
    315  }
    316  if (errno == ERANGE) {
    317    // strtod will set errno to ERANGE on underflow or overflow.
    318    bool underflow = -.00001 < *v && *v < .00001;
    319    tor_asprintf(errmsg,
    320                 "%s is too %s to express as a floating-point number.",
    321                 escaped(value), underflow ? "small" : "large");
    322    return -1;
    323  }
    324  return 0;
    325 }
    326 
    327 static char *
    328 double_encode(const void *value, const void *params)
    329 {
    330  (void)params;
    331  double v = *(double*)value;
    332  char *result;
    333  tor_asprintf(&result, "%f", v);
    334  return result;
    335 }
    336 
    337 static void
    338 double_clear(void *value, const void *params)
    339 {
    340  (void)params;
    341  double *v = (double *)value;
    342  *v = 0.0;
    343 }
    344 
    345 static const var_type_fns_t double_fns = {
    346  .parse = double_parse,
    347  .encode = double_encode,
    348  .clear = double_clear,
    349 };
    350 
    351 /////
    352 // CONFIG_TYPE_BOOL
    353 // CONFIG_TYPE_AUTOBOOL
    354 //
    355 // These types are implemented as a case-insensitive string-to-integer
    356 // mapping.
    357 /////
    358 
    359 typedef struct enumeration_table_t {
    360  const char *name;
    361  int value;
    362 } enumeration_table_t;
    363 
    364 typedef struct enumeration_params_t {
    365  const char *allowed_val_string;
    366  const enumeration_table_t *table;
    367 } enumeration_params_t;
    368 
    369 static int
    370 enum_parse(void *target, const char *value, char **errmsg,
    371           const void *params_)
    372 {
    373  const enumeration_params_t *params = params_;
    374  const enumeration_table_t *table = params->table;
    375  int *p = (int *)target;
    376  for (; table->name; ++table) {
    377    if (!strcasecmp(value, table->name)) {
    378      *p = table->value;
    379      return 0;
    380    }
    381  }
    382  tor_asprintf(errmsg, "Unrecognized value %s. %s",
    383               value, params->allowed_val_string);
    384  return -1;
    385 }
    386 
    387 static char *
    388 enum_encode(const void *value, const void *params_)
    389 {
    390  int v = *(const int*)value;
    391  const enumeration_params_t *params = params_;
    392  const enumeration_table_t *table = params->table;
    393  for (; table->name; ++table) {
    394    if (v == table->value)
    395      return tor_strdup(table->name);
    396  }
    397  return NULL; // error.
    398 }
    399 
    400 static void
    401 enum_clear(void *value, const void *params_)
    402 {
    403  int *p = (int*)value;
    404  const enumeration_params_t *params = params_;
    405  const enumeration_table_t *table = params->table;
    406  tor_assert(table->name);
    407  *p = table->value;
    408 }
    409 
    410 static bool
    411 enum_ok(const void *value, const void *params_)
    412 {
    413  int v = *(const int*)value;
    414  const enumeration_params_t *params = params_;
    415  const enumeration_table_t *table = params->table;
    416  for (; table->name; ++table) {
    417    if (v == table->value)
    418      return true;
    419  }
    420  return false;
    421 }
    422 
    423 static const enumeration_table_t enum_table_bool[] = {
    424  { "0", 0 },
    425  { "1", 1 },
    426  { NULL, 0 },
    427 };
    428 
    429 static const enumeration_params_t enum_params_bool = {
    430  "Allowed values are 0 and 1.",
    431  enum_table_bool
    432 };
    433 
    434 static const enumeration_table_t enum_table_autobool[] = {
    435  { "0", 0 },
    436  { "1", 1 },
    437  { "auto", -1 },
    438  { NULL, 0 },
    439 };
    440 
    441 static const enumeration_params_t enum_params_autobool = {
    442  "Allowed values are 0, 1, and auto.",
    443  enum_table_autobool
    444 };
    445 
    446 static const var_type_fns_t enum_fns = {
    447  .parse = enum_parse,
    448  .encode = enum_encode,
    449  .clear = enum_clear,
    450  .ok = enum_ok,
    451 };
    452 
    453 /////
    454 // CONFIG_TYPE_ISOTIME
    455 //
    456 // This is a time_t, encoded in ISO8601 format.
    457 /////
    458 
    459 static int
    460 time_parse(void *target, const char *value, char **errmsg,
    461           const void *params)
    462 {
    463  (void) params;
    464  time_t *p = target;
    465  if (parse_iso_time(value, p) < 0) {
    466    tor_asprintf(errmsg, "Invalid time %s", escaped(value));
    467    return -1;
    468  }
    469  return 0;
    470 }
    471 
    472 static char *
    473 time_encode(const void *value, const void *params)
    474 {
    475  (void)params;
    476  time_t v = *(const time_t *)value;
    477  char *result = tor_malloc(ISO_TIME_LEN+1);
    478  format_iso_time(result, v);
    479  return result;
    480 }
    481 
    482 static void
    483 time_clear(void *value, const void *params)
    484 {
    485  (void)params;
    486  time_t *t = value;
    487  *t = 0;
    488 }
    489 
    490 static const var_type_fns_t time_fns = {
    491  .parse = time_parse,
    492  .encode = time_encode,
    493  .clear = time_clear,
    494 };
    495 
    496 /////
    497 // CONFIG_TYPE_CSV
    498 //
    499 // This type is a comma-separated list of strings, stored in a smartlist_t.
    500 // An empty list may be encoded either as an empty smartlist, or as NULL.
    501 /////
    502 
    503 static int
    504 csv_parse(void *target, const char *value, char **errmsg,
    505          const void *params)
    506 {
    507  (void)params;
    508  (void)errmsg;
    509  smartlist_t **sl = (smartlist_t**)target;
    510  *sl = smartlist_new();
    511  smartlist_split_string(*sl, value, ",",
    512                         SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
    513  return 0;
    514 }
    515 
    516 static char *
    517 csv_encode(const void *value, const void *params)
    518 {
    519  (void)params;
    520  const smartlist_t *sl = *(const smartlist_t **)value;
    521  if (! sl)
    522    return tor_strdup("");
    523 
    524  return smartlist_join_strings(*(smartlist_t**)value, ",", 0, NULL);
    525 }
    526 
    527 static void
    528 csv_clear(void *value, const void *params)
    529 {
    530  (void)params;
    531  smartlist_t **sl = (smartlist_t**)value;
    532  if (!*sl)
    533    return;
    534  SMARTLIST_FOREACH(*sl, char *, cp, tor_free(cp));
    535  smartlist_free(*sl); // clears pointer.
    536 }
    537 
    538 static const var_type_fns_t csv_fns = {
    539  .parse = csv_parse,
    540  .encode = csv_encode,
    541  .clear = csv_clear,
    542 };
    543 
    544 /////
    545 // CONFIG_TYPE_CSV_INTERVAL
    546 //
    547 // This type used to be a list of time intervals, used to determine a download
    548 // schedule.  Now, only the first interval counts: everything after the first
    549 // comma is discarded.
    550 /////
    551 
    552 static int
    553 legacy_csv_interval_parse(void *target, const char *value, char **errmsg,
    554                          const void *params)
    555 {
    556  (void)params;
    557  /* We used to have entire smartlists here.  But now that all of our
    558   * download schedules use exponential backoff, only the first part
    559   * matters. */
    560  const char *comma = strchr(value, ',');
    561  const char *val = value;
    562  char *tmp = NULL;
    563  if (comma) {
    564    tmp = tor_strndup(val, comma - val);
    565    val = tmp;
    566  }
    567 
    568  int rv = units_parse_int(target, val, errmsg, &time_units);
    569  tor_free(tmp);
    570  return rv;
    571 }
    572 
    573 static const var_type_fns_t legacy_csv_interval_fns = {
    574  .parse = legacy_csv_interval_parse,
    575  .encode = int_encode,
    576  .clear = int_clear,
    577 };
    578 
    579 /////
    580 // CONFIG_TYPE_LINELIST
    581 // CONFIG_TYPE_LINELIST_S
    582 // CONFIG_TYPE_LINELIST_V
    583 //
    584 // A linelist is a raw config_line_t list.  Order is preserved.
    585 //
    586 // The LINELIST type is used for homogeneous lists, where all the lines
    587 // have the same key.
    588 //
    589 // The LINELIST_S and LINELIST_V types are used for the case where multiple
    590 // lines of different keys are kept in a single list, to preserve their
    591 // relative order.  The unified list is stored as a "virtual" variable whose
    592 // type is LINELIST_V; the individual sublists are treated as variables of
    593 // type LINELIST_S.
    594 //
    595 // A linelist may be fragile or non-fragile. Assigning a line to a fragile
    596 // linelist replaces the list with the line.  If the line has the "APPEND"
    597 // command set on it, or if the list is non-fragile, the line is appended.
    598 // Either way, the new list is non-fragile.
    599 /////
    600 
    601 static int
    602 linelist_kv_parse(void *target, const struct config_line_t *line,
    603                  char **errmsg, const void *params)
    604 {
    605  (void)params;
    606  (void)errmsg;
    607  config_line_t **lines = target;
    608 
    609  if (*lines && (*lines)->fragile) {
    610    if (line->command == CONFIG_LINE_APPEND) {
    611      (*lines)->fragile = 0;
    612    } else {
    613      config_free_lines(*lines); // sets it to NULL
    614    }
    615  }
    616 
    617  config_line_append(lines, line->key, line->value);
    618  return 0;
    619 }
    620 
    621 static int
    622 linelist_kv_virt_noparse(void *target, const struct config_line_t *line,
    623                         char **errmsg, const void *params)
    624 {
    625  (void)target;
    626  (void)line;
    627  (void)params;
    628  *errmsg = tor_strdup("Cannot assign directly to virtual option.");
    629  return -1;
    630 }
    631 
    632 static struct config_line_t *
    633 linelist_kv_encode(const char *key, const void *value,
    634                   const void *params)
    635 {
    636  (void)key;
    637  (void)params;
    638  config_line_t *lines = *(config_line_t **)value;
    639  return config_lines_dup(lines);
    640 }
    641 
    642 static struct config_line_t *
    643 linelist_s_kv_encode(const char *key, const void *value,
    644                     const void *params)
    645 {
    646  (void)params;
    647  config_line_t *lines = *(config_line_t **)value;
    648  return config_lines_dup_and_filter(lines, key);
    649 }
    650 
    651 static void
    652 linelist_clear(void *target, const void *params)
    653 {
    654  (void)params;
    655  config_line_t **lines = target;
    656  config_free_lines(*lines); // sets it to NULL
    657 }
    658 
    659 static bool
    660 linelist_eq(const void *a, const void *b, const void *params)
    661 {
    662  (void)params;
    663  const config_line_t *lines_a = *(const config_line_t **)a;
    664  const config_line_t *lines_b = *(const config_line_t **)b;
    665  return config_lines_eq(lines_a, lines_b);
    666 }
    667 
    668 static int
    669 linelist_copy(void *target, const void *value, const void *params)
    670 {
    671  (void)params;
    672  config_line_t **ptr = (config_line_t **)target;
    673  const config_line_t *val = *(const config_line_t **)value;
    674  config_free_lines(*ptr);
    675  *ptr = config_lines_dup(val);
    676  return 0;
    677 }
    678 
    679 static void
    680 linelist_mark_fragile(void *target, const void *params)
    681 {
    682  (void)params;
    683  config_line_t **ptr = (config_line_t **)target;
    684  if (*ptr)
    685    (*ptr)->fragile = 1;
    686 }
    687 
    688 static const var_type_fns_t linelist_fns = {
    689  .kv_parse = linelist_kv_parse,
    690  .kv_encode = linelist_kv_encode,
    691  .clear = linelist_clear,
    692  .eq = linelist_eq,
    693  .copy = linelist_copy,
    694  .mark_fragile = linelist_mark_fragile,
    695 };
    696 
    697 static const var_type_fns_t linelist_v_fns = {
    698  .kv_parse = linelist_kv_virt_noparse,
    699  .kv_encode = linelist_kv_encode,
    700  .clear = linelist_clear,
    701  .eq = linelist_eq,
    702  .copy = linelist_copy,
    703  .mark_fragile = linelist_mark_fragile,
    704 };
    705 
    706 static const var_type_fns_t linelist_s_fns = {
    707  .kv_parse = linelist_kv_parse,
    708  .kv_encode = linelist_s_kv_encode,
    709  .clear = linelist_clear,
    710  .eq = linelist_eq,
    711  .copy = linelist_copy,
    712 };
    713 
    714 /////
    715 // CONFIG_TYPE_ROUTERSET
    716 //
    717 // XXXX to this module.
    718 /////
    719 
    720 /////
    721 // CONFIG_TYPE_IGNORE
    722 //
    723 // Used to indicate an option that cannot be stored or encoded.
    724 /////
    725 
    726 static int
    727 ignore_parse(void *target, const char *value, char **errmsg,
    728             const void *params)
    729 {
    730  (void)target;
    731  (void)value;
    732  (void)errmsg;
    733  (void)params;
    734  return 0;
    735 }
    736 
    737 static char *
    738 ignore_encode(const void *value, const void *params)
    739 {
    740  (void)value;
    741  (void)params;
    742  return NULL;
    743 }
    744 
    745 static const var_type_fns_t ignore_fns = {
    746  .parse = ignore_parse,
    747  .encode = ignore_encode,
    748 };
    749 
    750 const var_type_def_t STRING_type_defn = {
    751  .name="String", .fns=&string_fns };
    752 const var_type_def_t FILENAME_type_defn = {
    753  .name="Filename", .fns=&string_fns };
    754 const var_type_def_t INT_type_defn = {
    755  .name="SignedInteger", .fns=&int_fns,
    756  .params=&INT_PARSE_UNRESTRICTED };
    757 const var_type_def_t POSINT_type_defn = {
    758  .name="Integer", .fns=&int_fns,
    759  .params=&INT_PARSE_POSINT };
    760 const var_type_def_t UINT64_type_defn = {
    761  .name="Integer", .fns=&uint64_fns, };
    762 const var_type_def_t MEMUNIT_type_defn = {
    763  .name="DataSize", .fns=&memunit_fns,
    764  .params=&memory_units };
    765 const var_type_def_t INTERVAL_type_defn = {
    766  .name="TimeInterval", .fns=&interval_fns,
    767  .params=&time_units };
    768 const var_type_def_t MSEC_INTERVAL_type_defn = {
    769  .name="TimeMsecInterval",
    770  .fns=&interval_fns,
    771  .params=&time_msec_units };
    772 const var_type_def_t DOUBLE_type_defn = {
    773  .name="Float", .fns=&double_fns, };
    774 const var_type_def_t BOOL_type_defn = {
    775  .name="Boolean", .fns=&enum_fns,
    776  .params=&enum_params_bool };
    777 const var_type_def_t AUTOBOOL_type_defn = {
    778  .name="Boolean+Auto", .fns=&enum_fns,
    779  .params=&enum_params_autobool };
    780 const var_type_def_t ISOTIME_type_defn = {
    781  .name="Time", .fns=&time_fns, };
    782 const var_type_def_t CSV_type_defn = {
    783  .name="CommaList", .fns=&csv_fns, };
    784 const var_type_def_t CSV_INTERVAL_type_defn = {
    785  .name="TimeInterval",
    786  .fns=&legacy_csv_interval_fns, };
    787 const var_type_def_t LINELIST_type_defn = {
    788  .name="LineList", .fns=&linelist_fns,
    789  .flags=CFLG_NOREPLACE };
    790 /*
    791 * A "linelist_s" is a derived view of a linelist_v: inspecting
    792 * it gets part of a linelist_v, and setting it adds to the linelist_v.
    793 */
    794 const var_type_def_t LINELIST_S_type_defn = {
    795  .name="Dependent", .fns=&linelist_s_fns,
    796  .flags=CFLG_NOREPLACE|
    797  /* The operations we disable here are
    798   * handled by the linelist_v. */
    799  CFLG_NOCOPY|CFLG_NOCMP|CFLG_NODUMP };
    800 const var_type_def_t LINELIST_V_type_defn = {
    801  .name="Virtual", .fns=&linelist_v_fns,
    802  .flags=CFLG_NOREPLACE|CFLG_NOSET };
    803 const var_type_def_t IGNORE_type_defn = {
    804  .name="Ignored", .fns=&ignore_fns,
    805  .flags=CFLG_NOCOPY|CFLG_NOCMP|CFLG_NODUMP|CFLG_NOSET,
    806 };
    807 const var_type_def_t OBSOLETE_type_defn = {
    808  .name="Obsolete", .fns=&ignore_fns,
    809  .flags=CFLG_GROUP_OBSOLETE,
    810 };
    811 
    812 /**
    813 * Table mapping conf_type_t values to var_type_def_t objects.
    814 **/
    815 static const var_type_def_t *type_definitions_table[] = {
    816  [CONFIG_TYPE_STRING] = &STRING_type_defn,
    817  [CONFIG_TYPE_FILENAME] = &FILENAME_type_defn,
    818  [CONFIG_TYPE_INT] = &INT_type_defn,
    819  [CONFIG_TYPE_POSINT] = &POSINT_type_defn,
    820  [CONFIG_TYPE_UINT64] = &UINT64_type_defn,
    821  [CONFIG_TYPE_MEMUNIT] = &MEMUNIT_type_defn,
    822  [CONFIG_TYPE_INTERVAL] = &INTERVAL_type_defn,
    823  [CONFIG_TYPE_MSEC_INTERVAL] = &MSEC_INTERVAL_type_defn,
    824  [CONFIG_TYPE_DOUBLE] = &DOUBLE_type_defn,
    825  [CONFIG_TYPE_BOOL] = &BOOL_type_defn,
    826  [CONFIG_TYPE_AUTOBOOL] = &AUTOBOOL_type_defn,
    827  [CONFIG_TYPE_ISOTIME] = &ISOTIME_type_defn,
    828  [CONFIG_TYPE_CSV] = &CSV_type_defn,
    829  [CONFIG_TYPE_CSV_INTERVAL] = &CSV_INTERVAL_type_defn,
    830  [CONFIG_TYPE_LINELIST] = &LINELIST_type_defn,
    831  [CONFIG_TYPE_LINELIST_S] = &LINELIST_S_type_defn,
    832  [CONFIG_TYPE_LINELIST_V] = &LINELIST_V_type_defn,
    833  [CONFIG_TYPE_IGNORE] = &IGNORE_type_defn,
    834  [CONFIG_TYPE_OBSOLETE] = &OBSOLETE_type_defn,
    835 };
    836 
    837 /**
    838 * Return a pointer to the var_type_def_t object for the given
    839 * config_type_t value, or NULL if no such type definition exists.
    840 **/
    841 const var_type_def_t *
    842 lookup_type_def(config_type_t type)
    843 {
    844  int t = type;
    845  tor_assert(t >= 0);
    846  if (t >= (int)ARRAY_LENGTH(type_definitions_table))
    847    return NULL;
    848  return type_definitions_table[t];
    849 }