aboutsummaryrefslogtreecommitdiff
path: root/src/lib/confmgt/type_defs.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/confmgt/type_defs.c')
-rw-r--r--src/lib/confmgt/type_defs.c849
1 files changed, 849 insertions, 0 deletions
diff --git a/src/lib/confmgt/type_defs.c b/src/lib/confmgt/type_defs.c
new file mode 100644
index 0000000000..d9e5e1e4c2
--- /dev/null
+++ b/src/lib/confmgt/type_defs.c
@@ -0,0 +1,849 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * @file type_defs.c
+ * @brief Definitions for various low-level configuration types.
+ *
+ * This module creates a number of var_type_def_t objects, to be used by
+ * typedvar.c in manipulating variables.
+ *
+ * The types here are common types that can be implemented with Tor's
+ * low-level functionality. To define new types, see var_type_def_st.h.
+ **/
+
+#include "orconfig.h"
+#include "lib/conf/conftypes.h"
+#include "lib/conf/confdecl.h"
+#include "lib/confmgt/typedvar.h"
+#include "lib/confmgt/type_defs.h"
+#include "lib/confmgt/unitparse.h"
+
+#include "lib/cc/compat_compiler.h"
+#include "lib/container/smartlist.h"
+#include "lib/encoding/confline.h"
+#include "lib/encoding/time_fmt.h"
+#include "lib/log/escape.h"
+#include "lib/log/log.h"
+#include "lib/log/util_bug.h"
+#include "lib/malloc/malloc.h"
+#include "lib/string/parse_int.h"
+#include "lib/string/printf.h"
+
+#include "lib/confmgt/var_type_def_st.h"
+
+#include <stddef.h>
+#include <string.h>
+#include <errno.h>
+
+//////
+// CONFIG_TYPE_STRING
+// CONFIG_TYPE_FILENAME
+//
+// These two types are the same for now, but they have different names.
+//
+// Warning: For this type, the default value (NULL) and "" are considered
+// different values. That is generally risky, and best avoided for other
+// types in the future.
+//////
+
+static int
+string_parse(void *target, const char *value, char **errmsg,
+ const void *params)
+{
+ (void)params;
+ (void)errmsg;
+ char **p = (char**)target;
+ *p = tor_strdup(value);
+ return 0;
+}
+
+static char *
+string_encode(const void *value, const void *params)
+{
+ (void)params;
+ const char **p = (const char**)value;
+ return *p ? tor_strdup(*p) : NULL;
+}
+
+static void
+string_clear(void *value, const void *params)
+{
+ (void)params;
+ char **p = (char**)value;
+ tor_free(*p); // sets *p to NULL.
+}
+
+static const var_type_fns_t string_fns = {
+ .parse = string_parse,
+ .encode = string_encode,
+ .clear = string_clear,
+};
+
+/////
+// CONFIG_TYPE_INT
+// CONFIG_TYPE_POSINT
+//
+// These types are implemented as int, possibly with a restricted range.
+/////
+
+/**
+ * Parameters for parsing an integer type.
+ **/
+typedef struct int_type_params_t {
+ int minval; /**< Lowest allowed value */
+ int maxval; /**< Highest allowed value */
+} int_parse_params_t;
+
+static const int_parse_params_t INT_PARSE_UNRESTRICTED = {
+ .minval = INT_MIN,
+ .maxval = INT_MAX,
+};
+
+static const int_parse_params_t INT_PARSE_POSINT = {
+ .minval = 0,
+ .maxval = INT_MAX,
+};
+
+static int
+int_parse(void *target, const char *value, char **errmsg, const void *params)
+{
+ const int_parse_params_t *pp;
+ if (params) {
+ pp = params;
+ } else {
+ pp = &INT_PARSE_UNRESTRICTED;
+ }
+ int *p = target;
+ int ok=0;
+ *p = (int)tor_parse_long(value, 10, pp->minval, pp->maxval, &ok, NULL);
+ if (!ok) {
+ tor_asprintf(errmsg, "Integer %s is malformed or out of bounds. "
+ "Allowed values are between %d and %d.",
+ value, pp->minval, pp->maxval);
+ return -1;
+ }
+ return 0;
+}
+
+static char *
+int_encode(const void *value, const void *params)
+{
+ (void)params;
+ int v = *(int*)value;
+ char *result;
+ tor_asprintf(&result, "%d", v);
+ return result;
+}
+
+static void
+int_clear(void *value, const void *params)
+{
+ (void)params;
+ *(int*)value = 0;
+}
+
+static bool
+int_ok(const void *value, const void *params)
+{
+ const int_parse_params_t *pp = params;
+ if (pp) {
+ int v = *(int*)value;
+ return pp->minval <= v && v <= pp->maxval;
+ } else {
+ return true;
+ }
+}
+
+static const var_type_fns_t int_fns = {
+ .parse = int_parse,
+ .encode = int_encode,
+ .clear = int_clear,
+ .ok = int_ok,
+};
+
+/////
+// CONFIG_TYPE_UINT64
+//
+// This type is an unrestricted u64.
+/////
+
+static int
+uint64_parse(void *target, const char *value, char **errmsg,
+ const void *params)
+{
+ (void)params;
+ (void)errmsg;
+ uint64_t *p = target;
+ int ok=0;
+ *p = tor_parse_uint64(value, 10, 0, UINT64_MAX, &ok, NULL);
+ if (!ok) {
+ tor_asprintf(errmsg, "Integer %s is malformed or out of bounds.",
+ value);
+ return -1;
+ }
+ return 0;
+}
+
+static char *
+uint64_encode(const void *value, const void *params)
+{
+ (void)params;
+ uint64_t v = *(uint64_t*)value;
+ char *result;
+ tor_asprintf(&result, "%"PRIu64, v);
+ return result;
+}
+
+static void
+uint64_clear(void *value, const void *params)
+{
+ (void)params;
+ *(uint64_t*)value = 0;
+}
+
+static const var_type_fns_t uint64_fns = {
+ .parse = uint64_parse,
+ .encode = uint64_encode,
+ .clear = uint64_clear,
+};
+
+/////
+// CONFIG_TYPE_INTERVAL
+// CONFIG_TYPE_MSEC_INTERVAL
+// CONFIG_TYPE_MEMUNIT
+//
+// These types are implemented using the config_parse_units() function.
+// The intervals are stored as ints, whereas memory units are stored as
+// uint64_ts.
+/////
+
+static int
+units_parse_u64(void *target, const char *value, char **errmsg,
+ const void *params)
+{
+ const unit_table_t *table = params;
+ tor_assert(table);
+ uint64_t *v = (uint64_t*)target;
+ int ok=1;
+ char *msg = NULL;
+ *v = config_parse_units(value, table, &ok, &msg);
+ if (!ok) {
+ tor_asprintf(errmsg, "Provided value is malformed or out of bounds: %s",
+ msg);
+ tor_free(msg);
+ return -1;
+ }
+ if (BUG(msg)) {
+ tor_free(msg);
+ }
+ return 0;
+}
+
+static int
+units_parse_int(void *target, const char *value, char **errmsg,
+ const void *params)
+{
+ const unit_table_t *table = params;
+ tor_assert(table);
+ int *v = (int*)target;
+ int ok=1;
+ char *msg = NULL;
+ uint64_t u64 = config_parse_units(value, table, &ok, &msg);
+ if (!ok) {
+ tor_asprintf(errmsg, "Provided value is malformed or out of bounds: %s",
+ msg);
+ tor_free(msg);
+ return -1;
+ }
+ if (BUG(msg)) {
+ tor_free(msg);
+ }
+ if (u64 > INT_MAX) {
+ tor_asprintf(errmsg, "Provided value %s is too large", value);
+ return -1;
+ }
+ *v = (int) u64;
+ return 0;
+}
+
+static bool
+units_ok_int(const void *value, const void *params)
+{
+ (void)params;
+ int v = *(int*)value;
+ return v >= 0;
+}
+
+static const var_type_fns_t memunit_fns = {
+ .parse = units_parse_u64,
+ .encode = uint64_encode, // doesn't use params
+ .clear = uint64_clear, // doesn't use params
+};
+
+static const var_type_fns_t interval_fns = {
+ .parse = units_parse_int,
+ .encode = int_encode, // doesn't use params
+ .clear = int_clear, // doesn't use params,
+ .ok = units_ok_int // can't use int_ok, since that expects int params.
+};
+
+/////
+// CONFIG_TYPE_DOUBLE
+//
+// This is a nice simple double.
+/////
+
+static int
+double_parse(void *target, const char *value, char **errmsg,
+ const void *params)
+{
+ (void)params;
+ (void)errmsg;
+ double *v = (double*)target;
+ char *endptr=NULL;
+ errno = 0;
+ *v = strtod(value, &endptr);
+ if (endptr == value || *endptr != '\0') {
+ // Either there are no converted characters, or there were some characters
+ // that didn't get converted.
+ tor_asprintf(errmsg, "Could not convert %s to a number.", escaped(value));
+ return -1;
+ }
+ if (errno == ERANGE) {
+ // strtod will set errno to ERANGE on underflow or overflow.
+ bool underflow = -.00001 < *v && *v < .00001;
+ tor_asprintf(errmsg,
+ "%s is too %s to express as a floating-point number.",
+ escaped(value), underflow ? "small" : "large");
+ return -1;
+ }
+ return 0;
+}
+
+static char *
+double_encode(const void *value, const void *params)
+{
+ (void)params;
+ double v = *(double*)value;
+ char *result;
+ tor_asprintf(&result, "%f", v);
+ return result;
+}
+
+static void
+double_clear(void *value, const void *params)
+{
+ (void)params;
+ double *v = (double *)value;
+ *v = 0.0;
+}
+
+static const var_type_fns_t double_fns = {
+ .parse = double_parse,
+ .encode = double_encode,
+ .clear = double_clear,
+};
+
+/////
+// CONFIG_TYPE_BOOL
+// CONFIG_TYPE_AUTOBOOL
+//
+// These types are implemented as a case-insensitive string-to-integer
+// mapping.
+/////
+
+typedef struct enumeration_table_t {
+ const char *name;
+ int value;
+} enumeration_table_t;
+
+typedef struct enumeration_params_t {
+ const char *allowed_val_string;
+ const enumeration_table_t *table;
+} enumeration_params_t;
+
+static int
+enum_parse(void *target, const char *value, char **errmsg,
+ const void *params_)
+{
+ const enumeration_params_t *params = params_;
+ const enumeration_table_t *table = params->table;
+ int *p = (int *)target;
+ for (; table->name; ++table) {
+ if (!strcasecmp(value, table->name)) {
+ *p = table->value;
+ return 0;
+ }
+ }
+ tor_asprintf(errmsg, "Unrecognized value %s. %s",
+ value, params->allowed_val_string);
+ return -1;
+}
+
+static char *
+enum_encode(const void *value, const void *params_)
+{
+ int v = *(const int*)value;
+ const enumeration_params_t *params = params_;
+ const enumeration_table_t *table = params->table;
+ for (; table->name; ++table) {
+ if (v == table->value)
+ return tor_strdup(table->name);
+ }
+ return NULL; // error.
+}
+
+static void
+enum_clear(void *value, const void *params_)
+{
+ int *p = (int*)value;
+ const enumeration_params_t *params = params_;
+ const enumeration_table_t *table = params->table;
+ tor_assert(table->name);
+ *p = table->value;
+}
+
+static bool
+enum_ok(const void *value, const void *params_)
+{
+ int v = *(const int*)value;
+ const enumeration_params_t *params = params_;
+ const enumeration_table_t *table = params->table;
+ for (; table->name; ++table) {
+ if (v == table->value)
+ return true;
+ }
+ return false;
+}
+
+static const enumeration_table_t enum_table_bool[] = {
+ { "0", 0 },
+ { "1", 1 },
+ { NULL, 0 },
+};
+
+static const enumeration_params_t enum_params_bool = {
+ "Allowed values are 0 and 1.",
+ enum_table_bool
+};
+
+static const enumeration_table_t enum_table_autobool[] = {
+ { "0", 0 },
+ { "1", 1 },
+ { "auto", -1 },
+ { NULL, 0 },
+};
+
+static const enumeration_params_t enum_params_autobool = {
+ "Allowed values are 0, 1, and auto.",
+ enum_table_autobool
+};
+
+static const var_type_fns_t enum_fns = {
+ .parse = enum_parse,
+ .encode = enum_encode,
+ .clear = enum_clear,
+ .ok = enum_ok,
+};
+
+/////
+// CONFIG_TYPE_ISOTIME
+//
+// This is a time_t, encoded in ISO8601 format.
+/////
+
+static int
+time_parse(void *target, const char *value, char **errmsg,
+ const void *params)
+{
+ (void) params;
+ time_t *p = target;
+ if (parse_iso_time(value, p) < 0) {
+ tor_asprintf(errmsg, "Invalid time %s", escaped(value));
+ return -1;
+ }
+ return 0;
+}
+
+static char *
+time_encode(const void *value, const void *params)
+{
+ (void)params;
+ time_t v = *(const time_t *)value;
+ char *result = tor_malloc(ISO_TIME_LEN+1);
+ format_iso_time(result, v);
+ return result;
+}
+
+static void
+time_clear(void *value, const void *params)
+{
+ (void)params;
+ time_t *t = value;
+ *t = 0;
+}
+
+static const var_type_fns_t time_fns = {
+ .parse = time_parse,
+ .encode = time_encode,
+ .clear = time_clear,
+};
+
+/////
+// CONFIG_TYPE_CSV
+//
+// This type is a comma-separated list of strings, stored in a smartlist_t.
+// An empty list may be encoded either as an empty smartlist, or as NULL.
+/////
+
+static int
+csv_parse(void *target, const char *value, char **errmsg,
+ const void *params)
+{
+ (void)params;
+ (void)errmsg;
+ smartlist_t **sl = (smartlist_t**)target;
+ *sl = smartlist_new();
+ smartlist_split_string(*sl, value, ",",
+ SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
+ return 0;
+}
+
+static char *
+csv_encode(const void *value, const void *params)
+{
+ (void)params;
+ const smartlist_t *sl = *(const smartlist_t **)value;
+ if (! sl)
+ return tor_strdup("");
+
+ return smartlist_join_strings(*(smartlist_t**)value, ",", 0, NULL);
+}
+
+static void
+csv_clear(void *value, const void *params)
+{
+ (void)params;
+ smartlist_t **sl = (smartlist_t**)value;
+ if (!*sl)
+ return;
+ SMARTLIST_FOREACH(*sl, char *, cp, tor_free(cp));
+ smartlist_free(*sl); // clears pointer.
+}
+
+static const var_type_fns_t csv_fns = {
+ .parse = csv_parse,
+ .encode = csv_encode,
+ .clear = csv_clear,
+};
+
+/////
+// CONFIG_TYPE_CSV_INTERVAL
+//
+// This type used to be a list of time intervals, used to determine a download
+// schedule. Now, only the first interval counts: everything after the first
+// comma is discarded.
+/////
+
+static int
+legacy_csv_interval_parse(void *target, const char *value, char **errmsg,
+ const void *params)
+{
+ (void)params;
+ /* We used to have entire smartlists here. But now that all of our
+ * download schedules use exponential backoff, only the first part
+ * matters. */
+ const char *comma = strchr(value, ',');
+ const char *val = value;
+ char *tmp = NULL;
+ if (comma) {
+ tmp = tor_strndup(val, comma - val);
+ val = tmp;
+ }
+
+ int rv = units_parse_int(target, val, errmsg, &time_units);
+ tor_free(tmp);
+ return rv;
+}
+
+static const var_type_fns_t legacy_csv_interval_fns = {
+ .parse = legacy_csv_interval_parse,
+ .encode = int_encode,
+ .clear = int_clear,
+};
+
+/////
+// CONFIG_TYPE_LINELIST
+// CONFIG_TYPE_LINELIST_S
+// CONFIG_TYPE_LINELIST_V
+//
+// A linelist is a raw config_line_t list. Order is preserved.
+//
+// The LINELIST type is used for homogeneous lists, where all the lines
+// have the same key.
+//
+// The LINELIST_S and LINELIST_V types are used for the case where multiple
+// lines of different keys are kept in a single list, to preserve their
+// relative order. The unified list is stored as a "virtual" variable whose
+// type is LINELIST_V; the individual sublists are treated as variables of
+// type LINELIST_S.
+//
+// A linelist may be fragile or non-fragile. Assigning a line to a fragile
+// linelist replaces the list with the line. If the line has the "APPEND"
+// command set on it, or if the list is non-fragile, the line is appended.
+// Either way, the new list is non-fragile.
+/////
+
+static int
+linelist_kv_parse(void *target, const struct config_line_t *line,
+ char **errmsg, const void *params)
+{
+ (void)params;
+ (void)errmsg;
+ config_line_t **lines = target;
+
+ if (*lines && (*lines)->fragile) {
+ if (line->command == CONFIG_LINE_APPEND) {
+ (*lines)->fragile = 0;
+ } else {
+ config_free_lines(*lines); // sets it to NULL
+ }
+ }
+
+ config_line_append(lines, line->key, line->value);
+ return 0;
+}
+
+static int
+linelist_kv_virt_noparse(void *target, const struct config_line_t *line,
+ char **errmsg, const void *params)
+{
+ (void)target;
+ (void)line;
+ (void)params;
+ *errmsg = tor_strdup("Cannot assign directly to virtual option.");
+ return -1;
+}
+
+static struct config_line_t *
+linelist_kv_encode(const char *key, const void *value,
+ const void *params)
+{
+ (void)key;
+ (void)params;
+ config_line_t *lines = *(config_line_t **)value;
+ return config_lines_dup(lines);
+}
+
+static struct config_line_t *
+linelist_s_kv_encode(const char *key, const void *value,
+ const void *params)
+{
+ (void)params;
+ config_line_t *lines = *(config_line_t **)value;
+ return config_lines_dup_and_filter(lines, key);
+}
+
+static void
+linelist_clear(void *target, const void *params)
+{
+ (void)params;
+ config_line_t **lines = target;
+ config_free_lines(*lines); // sets it to NULL
+}
+
+static bool
+linelist_eq(const void *a, const void *b, const void *params)
+{
+ (void)params;
+ const config_line_t *lines_a = *(const config_line_t **)a;
+ const config_line_t *lines_b = *(const config_line_t **)b;
+ return config_lines_eq(lines_a, lines_b);
+}
+
+static int
+linelist_copy(void *target, const void *value, const void *params)
+{
+ (void)params;
+ config_line_t **ptr = (config_line_t **)target;
+ const config_line_t *val = *(const config_line_t **)value;
+ config_free_lines(*ptr);
+ *ptr = config_lines_dup(val);
+ return 0;
+}
+
+static void
+linelist_mark_fragile(void *target, const void *params)
+{
+ (void)params;
+ config_line_t **ptr = (config_line_t **)target;
+ if (*ptr)
+ (*ptr)->fragile = 1;
+}
+
+static const var_type_fns_t linelist_fns = {
+ .kv_parse = linelist_kv_parse,
+ .kv_encode = linelist_kv_encode,
+ .clear = linelist_clear,
+ .eq = linelist_eq,
+ .copy = linelist_copy,
+ .mark_fragile = linelist_mark_fragile,
+};
+
+static const var_type_fns_t linelist_v_fns = {
+ .kv_parse = linelist_kv_virt_noparse,
+ .kv_encode = linelist_kv_encode,
+ .clear = linelist_clear,
+ .eq = linelist_eq,
+ .copy = linelist_copy,
+ .mark_fragile = linelist_mark_fragile,
+};
+
+static const var_type_fns_t linelist_s_fns = {
+ .kv_parse = linelist_kv_parse,
+ .kv_encode = linelist_s_kv_encode,
+ .clear = linelist_clear,
+ .eq = linelist_eq,
+ .copy = linelist_copy,
+};
+
+/////
+// CONFIG_TYPE_ROUTERSET
+//
+// XXXX to this module.
+/////
+
+/////
+// CONFIG_TYPE_IGNORE
+//
+// Used to indicate an option that cannot be stored or encoded.
+/////
+
+static int
+ignore_parse(void *target, const char *value, char **errmsg,
+ const void *params)
+{
+ (void)target;
+ (void)value;
+ (void)errmsg;
+ (void)params;
+ return 0;
+}
+
+static char *
+ignore_encode(const void *value, const void *params)
+{
+ (void)value;
+ (void)params;
+ return NULL;
+}
+
+static const var_type_fns_t ignore_fns = {
+ .parse = ignore_parse,
+ .encode = ignore_encode,
+};
+
+const var_type_def_t STRING_type_defn = {
+ .name="String", .fns=&string_fns };
+const var_type_def_t FILENAME_type_defn = {
+ .name="Filename", .fns=&string_fns };
+const var_type_def_t INT_type_defn = {
+ .name="SignedInteger", .fns=&int_fns,
+ .params=&INT_PARSE_UNRESTRICTED };
+const var_type_def_t POSINT_type_defn = {
+ .name="Integer", .fns=&int_fns,
+ .params=&INT_PARSE_POSINT };
+const var_type_def_t UINT64_type_defn = {
+ .name="Integer", .fns=&uint64_fns, };
+const var_type_def_t MEMUNIT_type_defn = {
+ .name="DataSize", .fns=&memunit_fns,
+ .params=&memory_units };
+const var_type_def_t INTERVAL_type_defn = {
+ .name="TimeInterval", .fns=&interval_fns,
+ .params=&time_units };
+const var_type_def_t MSEC_INTERVAL_type_defn = {
+ .name="TimeMsecInterval",
+ .fns=&interval_fns,
+ .params=&time_msec_units };
+const var_type_def_t DOUBLE_type_defn = {
+ .name="Float", .fns=&double_fns, };
+const var_type_def_t BOOL_type_defn = {
+ .name="Boolean", .fns=&enum_fns,
+ .params=&enum_params_bool };
+const var_type_def_t AUTOBOOL_type_defn = {
+ .name="Boolean+Auto", .fns=&enum_fns,
+ .params=&enum_params_autobool };
+const var_type_def_t ISOTIME_type_defn = {
+ .name="Time", .fns=&time_fns, };
+const var_type_def_t CSV_type_defn = {
+ .name="CommaList", .fns=&csv_fns, };
+const var_type_def_t CSV_INTERVAL_type_defn = {
+ .name="TimeInterval",
+ .fns=&legacy_csv_interval_fns, };
+const var_type_def_t LINELIST_type_defn = {
+ .name="LineList", .fns=&linelist_fns,
+ .flags=CFLG_NOREPLACE };
+/*
+ * A "linelist_s" is a derived view of a linelist_v: inspecting
+ * it gets part of a linelist_v, and setting it adds to the linelist_v.
+ */
+const var_type_def_t LINELIST_S_type_defn = {
+ .name="Dependent", .fns=&linelist_s_fns,
+ .flags=CFLG_NOREPLACE|
+ /* The operations we disable here are
+ * handled by the linelist_v. */
+ CFLG_NOCOPY|CFLG_NOCMP|CFLG_NODUMP };
+const var_type_def_t LINELIST_V_type_defn = {
+ .name="Virtual", .fns=&linelist_v_fns,
+ .flags=CFLG_NOREPLACE|CFLG_NOSET };
+const var_type_def_t IGNORE_type_defn = {
+ .name="Ignored", .fns=&ignore_fns,
+ .flags=CFLG_NOCOPY|CFLG_NOCMP|CFLG_NODUMP|CFLG_NOSET,
+};
+const var_type_def_t OBSOLETE_type_defn = {
+ .name="Obsolete", .fns=&ignore_fns,
+ .flags=CFLG_GROUP_OBSOLETE,
+};
+
+/**
+ * Table mapping conf_type_t values to var_type_def_t objects.
+ **/
+static const var_type_def_t *type_definitions_table[] = {
+ [CONFIG_TYPE_STRING] = &STRING_type_defn,
+ [CONFIG_TYPE_FILENAME] = &FILENAME_type_defn,
+ [CONFIG_TYPE_INT] = &INT_type_defn,
+ [CONFIG_TYPE_POSINT] = &POSINT_type_defn,
+ [CONFIG_TYPE_UINT64] = &UINT64_type_defn,
+ [CONFIG_TYPE_MEMUNIT] = &MEMUNIT_type_defn,
+ [CONFIG_TYPE_INTERVAL] = &INTERVAL_type_defn,
+ [CONFIG_TYPE_MSEC_INTERVAL] = &MSEC_INTERVAL_type_defn,
+ [CONFIG_TYPE_DOUBLE] = &DOUBLE_type_defn,
+ [CONFIG_TYPE_BOOL] = &BOOL_type_defn,
+ [CONFIG_TYPE_AUTOBOOL] = &AUTOBOOL_type_defn,
+ [CONFIG_TYPE_ISOTIME] = &ISOTIME_type_defn,
+ [CONFIG_TYPE_CSV] = &CSV_type_defn,
+ [CONFIG_TYPE_CSV_INTERVAL] = &CSV_INTERVAL_type_defn,
+ [CONFIG_TYPE_LINELIST] = &LINELIST_type_defn,
+ [CONFIG_TYPE_LINELIST_S] = &LINELIST_S_type_defn,
+ [CONFIG_TYPE_LINELIST_V] = &LINELIST_V_type_defn,
+ [CONFIG_TYPE_IGNORE] = &IGNORE_type_defn,
+ [CONFIG_TYPE_OBSOLETE] = &OBSOLETE_type_defn,
+};
+
+/**
+ * Return a pointer to the var_type_def_t object for the given
+ * config_type_t value, or NULL if no such type definition exists.
+ **/
+const var_type_def_t *
+lookup_type_def(config_type_t type)
+{
+ int t = type;
+ tor_assert(t >= 0);
+ if (t >= (int)ARRAY_LENGTH(type_definitions_table))
+ return NULL;
+ return type_definitions_table[t];
+}