diff options
Diffstat (limited to 'src/lib/confmgt')
-rw-r--r-- | src/lib/confmgt/.may_include | 1 | ||||
-rw-r--r-- | src/lib/confmgt/confmgt.c (renamed from src/lib/confmgt/confparse.c) | 191 | ||||
-rw-r--r-- | src/lib/confmgt/confmgt.h (renamed from src/lib/confmgt/confparse.h) | 134 | ||||
-rw-r--r-- | src/lib/confmgt/include.am | 4 | ||||
-rw-r--r-- | src/lib/confmgt/lib_confmgt.md | 7 | ||||
-rw-r--r-- | src/lib/confmgt/structvar.c | 24 | ||||
-rw-r--r-- | src/lib/confmgt/structvar.h | 2 | ||||
-rw-r--r-- | src/lib/confmgt/type_defs.c | 244 | ||||
-rw-r--r-- | src/lib/confmgt/type_defs.h | 2 | ||||
-rw-r--r-- | src/lib/confmgt/typedvar.c | 22 | ||||
-rw-r--r-- | src/lib/confmgt/typedvar.h | 4 | ||||
-rw-r--r-- | src/lib/confmgt/unitparse.c | 70 | ||||
-rw-r--r-- | src/lib/confmgt/unitparse.h | 5 | ||||
-rw-r--r-- | src/lib/confmgt/var_type_def_st.h | 7 |
14 files changed, 473 insertions, 244 deletions
diff --git a/src/lib/confmgt/.may_include b/src/lib/confmgt/.may_include index 2564133917..5ff949f103 100644 --- a/src/lib/confmgt/.may_include +++ b/src/lib/confmgt/.may_include @@ -4,6 +4,7 @@ lib/conf/*.h lib/confmgt/*.h lib/container/*.h lib/encoding/*.h +lib/intmath/*.h lib/log/*.h lib/malloc/*.h lib/string/*.h diff --git a/src/lib/confmgt/confparse.c b/src/lib/confmgt/confmgt.c index 08e562f654..bf2764160e 100644 --- a/src/lib/confmgt/confparse.c +++ b/src/lib/confmgt/confmgt.c @@ -1,11 +1,11 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** - * \file confparse.c + * \file confmgt.c * * \brief Back-end for parsing and generating key-value files, used to * implement the torrc file format and the state file. @@ -21,9 +21,9 @@ * specified, and a linked list of key-value pairs. */ -#define CONFPARSE_PRIVATE +#define CONFMGT_PRIVATE #include "orconfig.h" -#include "lib/confmgt/confparse.h" +#include "lib/confmgt/confmgt.h" #include "lib/confmgt/structvar.h" #include "lib/confmgt/unitparse.h" @@ -169,9 +169,14 @@ config_mgr_register_fmt(config_mgr_t *mgr, "it had been frozen."); if (object_idx != IDX_TOPLEVEL) { - tor_assertf(fmt->config_suite_offset < 0, + tor_assertf(! fmt->has_config_suite, "Tried to register a toplevel format in a non-toplevel position"); } + if (fmt->config_suite_offset) { + tor_assertf(fmt->has_config_suite, + "config_suite_offset was set, but has_config_suite was not."); + } + tor_assertf(fmt != mgr->toplevel && ! smartlist_contains(mgr->subconfigs, fmt), "Tried to register an already-registered format."); @@ -223,7 +228,7 @@ config_mgr_add_format(config_mgr_t *mgr, static inline config_suite_t ** config_mgr_get_suite_ptr(const config_mgr_t *mgr, void *toplevel) { - if (mgr->toplevel->config_suite_offset < 0) + if (! mgr->toplevel->has_config_suite) return NULL; return STRUCT_VAR_P(toplevel, mgr->toplevel->config_suite_offset); } @@ -237,7 +242,7 @@ config_mgr_get_suite_ptr(const config_mgr_t *mgr, void *toplevel) * to configuration objects for other modules. This function gets * the sub-object for a particular module. */ -STATIC void * +void * config_mgr_get_obj_mutable(const config_mgr_t *mgr, void *toplevel, int idx) { tor_assert(mgr); @@ -256,7 +261,7 @@ config_mgr_get_obj_mutable(const config_mgr_t *mgr, void *toplevel, int idx) } /** As config_mgr_get_obj_mutable(), but return a const pointer. */ -STATIC const void * +const void * config_mgr_get_obj(const config_mgr_t *mgr, const void *toplevel, int idx) { return config_mgr_get_obj_mutable(mgr, (void*)toplevel, idx); @@ -334,6 +339,17 @@ config_mgr_list_deprecated_vars(const config_mgr_t *mgr) return result; } +/** + * Check the magic number on <b>object</b> to make sure it's a valid toplevel + * object, created with <b>mgr</b>. Exit with an assertion if it isn't. + **/ +void +config_check_toplevel_magic(const config_mgr_t *mgr, + const void *object) +{ + struct_check_magic(object, &mgr->toplevel_magic); +} + /** Assert that the magic fields in <b>options</b> and its subsidiary * objects are all okay. */ static void @@ -641,6 +657,14 @@ config_assign_value(const config_mgr_t *mgr, void *options, tor_assert(!strcmp(c->key, var->cvar->member.name)); void *object = config_mgr_get_obj_mutable(mgr, options, var->object_idx); + if (config_var_has_flag(var->cvar, CFLG_WARN_OBSOLETE)) { + log_warn(LD_GENERAL, "Skipping obsolete configuration option \"%s\".", + var->cvar->member.name); + } else if (config_var_has_flag(var->cvar, CFLG_WARN_DISABLED)) { + log_warn(LD_GENERAL, "This copy of Tor was built without support for " + "the option \"%s\". Skipping.", var->cvar->member.name); + } + return struct_var_kvassign(object, c, msg, &var->cvar->member); } @@ -1142,6 +1166,146 @@ config_init(const config_mgr_t *mgr, void *options) } SMARTLIST_FOREACH_END(mv); } +/** + * Helper for config_validate_single: see whether any immutable option + * has changed between old_options and new_options. + * + * On success return 0; on failure set *msg_out to a newly allocated + * string explaining what is wrong, and return -1. + */ +static int +config_check_immutable_flags(const config_format_t *fmt, + const void *old_options, + const void *new_options, + char **msg_out) +{ + tor_assert(fmt); + tor_assert(new_options); + if (BUG(! old_options)) + return 0; + + unsigned i; + for (i = 0; fmt->vars[i].member.name; ++i) { + const config_var_t *v = &fmt->vars[i]; + if (! config_var_has_flag(v, CFLG_IMMUTABLE)) + continue; + + if (! struct_var_eq(old_options, new_options, &v->member)) { + tor_asprintf(msg_out, + "While Tor is running, changing %s is not allowed", + v->member.name); + return -1; + } + } + + return 0; +} + +/** + * Normalize and validate a single object `options` within a configuration + * suite, according to its format. `options` may be modified as appropriate + * in order to set ancillary data. If `old_options` is provided, make sure + * that the transition from `old_options` to `options` is permitted. + * + * On success return VSTAT_OK; on failure set *msg_out to a newly allocated + * string explaining what is wrong, and return a different validation_status_t + * to describe which step failed. + **/ +static validation_status_t +config_validate_single(const config_format_t *fmt, + const void *old_options, void *options, + char **msg_out) +{ + tor_assert(fmt); + tor_assert(options); + + if (fmt->pre_normalize_fn) { + if (fmt->pre_normalize_fn(options, msg_out) < 0) { + return VSTAT_PRE_NORMALIZE_ERR; + } + } + + if (fmt->legacy_validate_fn) { + if (fmt->legacy_validate_fn(old_options, options, msg_out) < 0) { + return VSTAT_LEGACY_ERR; + } + } + + if (fmt->validate_fn) { + if (fmt->validate_fn(options, msg_out) < 0) { + return VSTAT_VALIDATE_ERR; + } + } + + if (old_options) { + if (config_check_immutable_flags(fmt, old_options, options, msg_out) < 0) { + return VSTAT_TRANSITION_ERR; + } + + if (fmt->check_transition_fn) { + if (fmt->check_transition_fn(old_options, options, msg_out) < 0) { + return VSTAT_TRANSITION_ERR; + } + } + } + + if (fmt->post_normalize_fn) { + if (fmt->post_normalize_fn(options, msg_out) < 0) { + return VSTAT_POST_NORMALIZE_ERR; + } + } + + return VSTAT_OK; +} + +/** + * Normalize and validate all the options in configuration object `options` + * and its sub-objects. `options` may be modified as appropriate in order to + * set ancillary data. If `old_options` is provided, make sure that the + * transition from `old_options` to `options` is permitted. + * + * On success return VSTAT_OK; on failure set *msg_out to a newly allocated + * string explaining what is wrong, and return a different validation_status_t + * to describe which step failed. + **/ +validation_status_t +config_validate(const config_mgr_t *mgr, + const void *old_options, void *options, + char **msg_out) +{ + validation_status_t rv; + CONFIG_CHECK(mgr, options); + if (old_options) { + CONFIG_CHECK(mgr, old_options); + } + + config_suite_t **suitep_new = config_mgr_get_suite_ptr(mgr, options); + config_suite_t **suitep_old = NULL; + if (old_options) + suitep_old = config_mgr_get_suite_ptr(mgr, (void*) old_options); + + /* Validate the sub-objects */ + if (suitep_new) { + SMARTLIST_FOREACH_BEGIN(mgr->subconfigs, const config_format_t *, fmt) { + void *obj = smartlist_get((*suitep_new)->configs, fmt_sl_idx); + const void *obj_old=NULL; + if (suitep_old) + obj_old = smartlist_get((*suitep_old)->configs, fmt_sl_idx); + + rv = config_validate_single(fmt, obj_old, obj, msg_out); + if (rv < 0) + return rv; + } SMARTLIST_FOREACH_END(fmt); + } + + /* Validate the top-level object. */ + rv = config_validate_single(mgr->toplevel, old_options, options, msg_out); + if (rv < 0) + return rv; + + return VSTAT_OK; +} + /** Allocate and return a new string holding the written-out values of the vars * in 'options'. If 'minimal', do not write out any default-valued vars. * Else, if comment_defaults, write default values as comments. @@ -1166,7 +1330,7 @@ config_dump(const config_mgr_t *mgr, const void *default_options, /* XXX use a 1 here so we don't add a new log line while dumping */ if (default_options == NULL) { - if (fmt->validate_fn(NULL, defaults_tmp, defaults_tmp, 1, &msg) < 0) { + if (config_validate(mgr, NULL, defaults_tmp, &msg) < 0) { // LCOV_EXCL_START log_err(LD_BUG, "Failed to validate default config: %s", msg); tor_free(msg); @@ -1197,9 +1361,10 @@ config_dump(const config_mgr_t *mgr, const void *default_options, */ continue; } - smartlist_add_asprintf(elements, "%s%s %s\n", + int value_exists = line->value && *(line->value); + smartlist_add_asprintf(elements, "%s%s%s%s\n", comment_option ? "# " : "", - line->key, line->value); + line->key, value_exists ? " " : "", line->value); } config_free_lines(assigned); } SMARTLIST_FOREACH_END(mv); @@ -1207,7 +1372,9 @@ config_dump(const config_mgr_t *mgr, const void *default_options, if (fmt->extra) { line = *(config_line_t**)STRUCT_VAR_P(options, fmt->extra->offset); for (; line; line = line->next) { - smartlist_add_asprintf(elements, "%s %s\n", line->key, line->value); + int value_exists = line->value && *(line->value); + smartlist_add_asprintf(elements, "%s%s%s\n", + line->key, value_exists ? " " : "", line->value); } } diff --git a/src/lib/confmgt/confparse.h b/src/lib/confmgt/confmgt.h index 2332f69790..5065c13b60 100644 --- a/src/lib/confmgt/confparse.h +++ b/src/lib/confmgt/confmgt.h @@ -1,116 +1,23 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** - * \file confparse.h + * \file confmgt.h * - * \brief Header for confparse.c. + * \brief Header for confmgt.c. */ -#ifndef TOR_CONFPARSE_H -#define TOR_CONFPARSE_H +#ifndef TOR_CONFMGT_H +#define TOR_CONFMGT_H #include "lib/conf/conftypes.h" #include "lib/conf/confmacros.h" #include "lib/testsupport/testsupport.h" /** - * An abbreviation or alias for a configuration option. - **/ -typedef struct config_abbrev_t { - /** The option name as abbreviated. Not case-sensitive. */ - const char *abbreviated; - /** The full name of the option. Not case-sensitive. */ - const char *full; - /** True if this abbreviation should only be allowed on the command line. */ - int commandline_only; - /** True if we should warn whenever this abbreviation is used. */ - int warn; -} config_abbrev_t; - -/** - * A note that a configuration option is deprecated, with an explanation why. - */ -typedef struct config_deprecation_t { - /** The option that is deprecated. */ - const char *name; - /** A user-facing string explaining why the option is deprecated. */ - const char *why_deprecated; -} config_deprecation_t; - -/** - * Handy macro for declaring "In the config file or on the command line, you - * can abbreviate <b>tok</b>s as <b>tok</b>". Used inside an array of - * config_abbrev_t. - * - * For example, to declare "NumCpu" as an abbreviation for "NumCPUs", - * you can say PLURAL(NumCpu). - **/ -#define PLURAL(tok) { #tok, #tok "s", 0, 0 } - -/** - * Type of a callback to validate whether a given configuration is - * well-formed and consistent. - * - * The configuration to validate is passed as <b>newval</b>. The previous - * configuration, if any, is provided in <b>oldval</b>. The - * <b>default_val</b> argument receives a configuration object initialized - * with default values for all its fields. The <b>from_setconf</b> argument - * is true iff the input comes from a SETCONF controller command. - * - * On success, return 0. On failure, set *<b>msg_out</b> to a newly allocated - * error message, and return -1. - * - * REFACTORING NOTE: Currently, this callback type is only used from inside - * config_dump(); later in our refactoring, it will be cleaned up and used - * more generally. - */ -typedef int (*validate_fn_t)(void *oldval, - void *newval, - void *default_val, - int from_setconf, - char **msg_out); - -struct config_mgr_t; - -/** - * Callback to clear all non-managed fields of a configuration object. - * - * <b>obj</b> is the configuration object whose non-managed fields should be - * cleared. - * - * (Regular fields get cleared by config_reset(), but you might have fields - * in the object that do not correspond to configuration variables. If those - * fields need to be cleared or freed, this is where to do it.) - */ -typedef void (*clear_cfg_fn_t)(const struct config_mgr_t *mgr, void *obj); - -/** Information on the keys, value types, key-to-struct-member mappings, - * variable descriptions, validation functions, and abbreviations for a - * configuration or storage format. */ -typedef struct config_format_t { - size_t size; /**< Size of the struct that everything gets parsed into. */ - struct_magic_decl_t magic; /**< Magic number info for this struct. */ - const config_abbrev_t *abbrevs; /**< List of abbreviations that we expand - * when parsing this format. */ - const config_deprecation_t *deprecations; /** List of deprecated options */ - const config_var_t *vars; /**< List of variables we recognize, their default - * values, and where we stick them in the - * structure. */ - validate_fn_t validate_fn; /**< Function to validate config. */ - clear_cfg_fn_t clear_fn; /**< Function to clear the configuration. */ - /** If present, extra denotes a LINELIST variable for unrecognized - * lines. Otherwise, unrecognized lines are an error. */ - const struct_member_t *extra; - /** The position of a config_suite_t pointer within the toplevel object, - * or -1 if there is no such pointer. */ - ptrdiff_t config_suite_offset; -} config_format_t; - -/** * A collection of config_format_t objects to describe several objects * that are all configured with the same configuration file. * @@ -171,10 +78,26 @@ int config_is_same(const config_mgr_t *fmt, struct config_line_t *config_get_changes(const config_mgr_t *mgr, const void *options1, const void *options2); void config_init(const config_mgr_t *mgr, void *options); + +/** An enumeration to report which validation step failed. */ +typedef enum { + VSTAT_PRE_NORMALIZE_ERR = -5, + VSTAT_VALIDATE_ERR = -4, + VSTAT_LEGACY_ERR = -3, + VSTAT_TRANSITION_ERR = -2, + VSTAT_POST_NORMALIZE_ERR = -1, + VSTAT_OK = 0, +} validation_status_t; + +validation_status_t config_validate(const config_mgr_t *mgr, + const void *old_options, void *options, + char **msg_out); void *config_dup(const config_mgr_t *mgr, const void *old); char *config_dump(const config_mgr_t *mgr, const void *default_options, const void *options, int minimal, int comment_defaults); +void config_check_toplevel_magic(const config_mgr_t *mgr, + const void *object); bool config_check_ok(const config_mgr_t *mgr, const void *options, int severity); int config_assign(const config_mgr_t *mgr, void *options, @@ -200,13 +123,14 @@ bool config_var_is_listable(const config_var_t *var); #define CFG_EQ_LINELIST(a,b,opt) config_lines_eq((a)->opt, (b)->opt) #define CFG_EQ_ROUTERSET(a,b,opt) routerset_equal((a)->opt, (b)->opt) -#ifdef CONFPARSE_PRIVATE +void *config_mgr_get_obj_mutable(const config_mgr_t *mgr, + void *toplevel, int idx); +const void *config_mgr_get_obj(const config_mgr_t *mgr, + const void *toplevel, int idx); + +#ifdef CONFMGT_PRIVATE STATIC void config_reset_line(const config_mgr_t *mgr, void *options, const char *key, int use_defaults); -STATIC void *config_mgr_get_obj_mutable(const config_mgr_t *mgr, - void *toplevel, int idx); -STATIC const void *config_mgr_get_obj(const config_mgr_t *mgr, - const void *toplevel, int idx); -#endif /* defined(CONFPARSE_PRIVATE) */ +#endif /* defined(CONFMGT_PRIVATE) */ -#endif /* !defined(TOR_CONFPARSE_H) */ +#endif /* !defined(TOR_CONFMGT_H) */ diff --git a/src/lib/confmgt/include.am b/src/lib/confmgt/include.am index 81cd868e5e..d3a7a7cd69 100644 --- a/src/lib/confmgt/include.am +++ b/src/lib/confmgt/include.am @@ -6,7 +6,7 @@ endif # ADD_C_FILE: INSERT SOURCES HERE. src_lib_libtor_confmgt_a_SOURCES = \ - src/lib/confmgt/confparse.c \ + src/lib/confmgt/confmgt.c \ src/lib/confmgt/structvar.c \ src/lib/confmgt/type_defs.c \ src/lib/confmgt/typedvar.c \ @@ -19,7 +19,7 @@ src_lib_libtor_confmgt_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) # ADD_C_FILE: INSERT HEADERS HERE. noinst_HEADERS += \ - src/lib/confmgt/confparse.h \ + src/lib/confmgt/confmgt.h \ src/lib/confmgt/structvar.h \ src/lib/confmgt/type_defs.h \ src/lib/confmgt/typedvar.h \ diff --git a/src/lib/confmgt/lib_confmgt.md b/src/lib/confmgt/lib_confmgt.md new file mode 100644 index 0000000000..861e720f64 --- /dev/null +++ b/src/lib/confmgt/lib_confmgt.md @@ -0,0 +1,7 @@ +@dir /lib/confmgt +@brief lib/confmgt: Parse, encode, manipulate configuration files. + +This logic is used in common by our state files (statefile.c) and +configuration files (config.c) to manage a set of named, typed fields, +reading and writing them to disk and to the controller. + diff --git a/src/lib/confmgt/structvar.c b/src/lib/confmgt/structvar.c index 7a3b8c7df2..55deb4759c 100644 --- a/src/lib/confmgt/structvar.c +++ b/src/lib/confmgt/structvar.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -30,13 +30,28 @@ #include <stddef.h> /** + * Return true iff all fields on <b>decl</b> are NULL or 0, indicating that + * there is no object or no magic number to check. + **/ +static inline bool +magic_is_null(const struct_magic_decl_t *decl) +{ + return decl->typename == NULL && + decl->magic_offset == 0 && + decl->magic_val == 0; +} + +/** * Set the 'magic number' on <b>object</b> to correspond to decl. **/ void struct_set_magic(void *object, const struct_magic_decl_t *decl) { - tor_assert(object); tor_assert(decl); + if (magic_is_null(decl)) + return; + + tor_assert(object); uint32_t *ptr = STRUCT_VAR_P(object, decl->magic_offset); *ptr = decl->magic_val; } @@ -47,8 +62,11 @@ struct_set_magic(void *object, const struct_magic_decl_t *decl) void struct_check_magic(const void *object, const struct_magic_decl_t *decl) { - tor_assert(object); tor_assert(decl); + if (magic_is_null(decl)) + return; + + tor_assert(object); const uint32_t *ptr = STRUCT_VAR_P(object, decl->magic_offset); tor_assertf(*ptr == decl->magic_val, diff --git a/src/lib/confmgt/structvar.h b/src/lib/confmgt/structvar.h index bcb4b58c3f..91334fa8c5 100644 --- a/src/lib/confmgt/structvar.h +++ b/src/lib/confmgt/structvar.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/confmgt/type_defs.c b/src/lib/confmgt/type_defs.c index 5066e12265..d9e5e1e4c2 100644 --- a/src/lib/confmgt/type_defs.c +++ b/src/lib/confmgt/type_defs.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -17,12 +17,12 @@ #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/conf/conftypes.h" #include "lib/container/smartlist.h" #include "lib/encoding/confline.h" #include "lib/encoding/time_fmt.h" @@ -52,11 +52,10 @@ static int string_parse(void *target, const char *value, char **errmsg, - const void *params, const char *key) + const void *params) { (void)params; (void)errmsg; - (void)key; char **p = (char**)target; *p = tor_strdup(value); return 0; @@ -91,9 +90,12 @@ static const var_type_fns_t string_fns = { // 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; - int maxval; + int minval; /**< Lowest allowed value */ + int maxval; /**< Highest allowed value */ } int_parse_params_t; static const int_parse_params_t INT_PARSE_UNRESTRICTED = { @@ -107,10 +109,8 @@ static const int_parse_params_t INT_PARSE_POSINT = { }; static int -int_parse(void *target, const char *value, char **errmsg, const void *params, - const char *key) +int_parse(void *target, const char *value, char **errmsg, const void *params) { - (void)key; const int_parse_params_t *pp; if (params) { pp = params; @@ -121,8 +121,9 @@ int_parse(void *target, const char *value, char **errmsg, const void *params, 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.", - value); + 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; @@ -172,11 +173,10 @@ static const var_type_fns_t int_fns = { static int uint64_parse(void *target, const char *value, char **errmsg, - const void *params, const char *key) + const void *params) { (void)params; (void)errmsg; - (void)key; uint64_t *p = target; int ok=0; *p = tor_parse_uint64(value, 10, 0, UINT64_MAX, &ok, NULL); @@ -223,35 +223,45 @@ static const var_type_fns_t uint64_fns = { static int units_parse_u64(void *target, const char *value, char **errmsg, - const void *params, const char *key) + const void *params) { - (void)key; const unit_table_t *table = params; tor_assert(table); uint64_t *v = (uint64_t*)target; int ok=1; - *v = config_parse_units(value, table, &ok); + char *msg = NULL; + *v = config_parse_units(value, table, &ok, &msg); if (!ok) { - *errmsg = tor_strdup("Provided value is malformed or out of bounds."); + 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 char *key) + const void *params) { - (void)key; const unit_table_t *table = params; tor_assert(table); int *v = (int*)target; int ok=1; - uint64_t u64 = config_parse_units(value, table, &ok); + char *msg = NULL; + uint64_t u64 = config_parse_units(value, table, &ok, &msg); if (!ok) { - *errmsg = tor_strdup("Provided value is malformed or out of bounds."); + 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; @@ -289,11 +299,10 @@ static const var_type_fns_t interval_fns = { static int double_parse(void *target, const char *value, char **errmsg, - const void *params, const char *key) + const void *params) { (void)params; (void)errmsg; - (void)key; double *v = (double*)target; char *endptr=NULL; errno = 0; @@ -352,12 +361,17 @@ typedef struct enumeration_table_t { 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 char *key) + const void *params_) { - (void)key; - const enumeration_table_t *table = 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)) { @@ -365,15 +379,17 @@ enum_parse(void *target, const char *value, char **errmsg, return 0; } } - tor_asprintf(errmsg, "Unrecognized value %s.", value); + tor_asprintf(errmsg, "Unrecognized value %s. %s", + value, params->allowed_val_string); return -1; } static char * -enum_encode(const void *value, const void *params) +enum_encode(const void *value, const void *params_) { int v = *(const int*)value; - const enumeration_table_t *table = params; + 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); @@ -382,19 +398,21 @@ enum_encode(const void *value, const void *params) } static void -enum_clear(void *value, const void *params) +enum_clear(void *value, const void *params_) { int *p = (int*)value; - const enumeration_table_t *table = params; + 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) +enum_ok(const void *value, const void *params_) { int v = *(const int*)value; - const enumeration_table_t *table = params; + const enumeration_params_t *params = params_; + const enumeration_table_t *table = params->table; for (; table->name; ++table) { if (v == table->value) return true; @@ -408,6 +426,11 @@ static const enumeration_table_t enum_table_bool[] = { { 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 }, @@ -415,6 +438,11 @@ static const enumeration_table_t enum_table_autobool[] = { { 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, @@ -430,10 +458,9 @@ static const var_type_fns_t enum_fns = { static int time_parse(void *target, const char *value, char **errmsg, - const void *params, const char *key) + const void *params) { (void) params; - (void) key; time_t *p = target; if (parse_iso_time(value, p) < 0) { tor_asprintf(errmsg, "Invalid time %s", escaped(value)); @@ -475,11 +502,10 @@ static const var_type_fns_t time_fns = { static int csv_parse(void *target, const char *value, char **errmsg, - const void *params, const char *key) + const void *params) { (void)params; (void)errmsg; - (void)key; smartlist_t **sl = (smartlist_t**)target; *sl = smartlist_new(); smartlist_split_string(*sl, value, ",", @@ -525,7 +551,7 @@ static const var_type_fns_t csv_fns = { static int legacy_csv_interval_parse(void *target, const char *value, char **errmsg, - const void *params, const char *key) + const void *params) { (void)params; /* We used to have entire smartlists here. But now that all of our @@ -539,7 +565,7 @@ legacy_csv_interval_parse(void *target, const char *value, char **errmsg, val = tmp; } - int rv = units_parse_int(target, val, errmsg, &time_units, key); + int rv = units_parse_int(target, val, errmsg, &time_units); tor_free(tmp); return rv; } @@ -688,32 +714,23 @@ static const var_type_fns_t linelist_s_fns = { ///// // CONFIG_TYPE_ROUTERSET // -// XXXX This type is not implemented here, since routerset_t is not available // XXXX to this module. ///// ///// -// CONFIG_TYPE_OBSOLETE -// -// Used to indicate an obsolete option. +// CONFIG_TYPE_IGNORE // -// XXXX This is not a type, and should be handled at a higher level of -// XXXX abstraction. +// 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, const char *key) + const void *params) { (void)target; (void)value; (void)errmsg; (void)params; - // XXXX move this to a higher level, once such a level exists. - log_warn(LD_GENERAL, "Skipping obsolete configuration option%s%s%s", - key && *key ? " \"" : "", - key && *key ? key : "", - key && *key ? "\"." : "."); return 0; } @@ -730,50 +747,91 @@ static const var_type_fns_t ignore_fns = { .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] = { .name="String", .fns=&string_fns }, - [CONFIG_TYPE_FILENAME] = { .name="Filename", .fns=&string_fns }, - [CONFIG_TYPE_INT] = { .name="SignedInteger", .fns=&int_fns, - .params=&INT_PARSE_UNRESTRICTED }, - [CONFIG_TYPE_POSINT] = { .name="Integer", .fns=&int_fns, - .params=&INT_PARSE_POSINT }, - [CONFIG_TYPE_UINT64] = { .name="Integer", .fns=&uint64_fns, }, - [CONFIG_TYPE_MEMUNIT] = { .name="DataSize", .fns=&memunit_fns, - .params=&memory_units }, - [CONFIG_TYPE_INTERVAL] = { .name="TimeInterval", .fns=&interval_fns, - .params=&time_units }, - [CONFIG_TYPE_MSEC_INTERVAL] = { .name="TimeMsecInterval", - .fns=&interval_fns, - .params=&time_msec_units }, - [CONFIG_TYPE_DOUBLE] = { .name="Float", .fns=&double_fns, }, - [CONFIG_TYPE_BOOL] = { .name="Boolean", .fns=&enum_fns, - .params=&enum_table_bool }, - [CONFIG_TYPE_AUTOBOOL] = { .name="Boolean+Auto", .fns=&enum_fns, - .params=&enum_table_autobool }, - [CONFIG_TYPE_ISOTIME] = { .name="Time", .fns=&time_fns, }, - [CONFIG_TYPE_CSV] = { .name="CommaList", .fns=&csv_fns, }, - [CONFIG_TYPE_CSV_INTERVAL] = { .name="TimeInterval", - .fns=&legacy_csv_interval_fns, }, - [CONFIG_TYPE_LINELIST] = { .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. - */ - [CONFIG_TYPE_LINELIST_S] = { .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 }, - [CONFIG_TYPE_LINELIST_V] = { .name="Virtual", .fns=&linelist_v_fns, - .flags=CFLG_NOREPLACE|CFLG_NOSET }, - [CONFIG_TYPE_OBSOLETE] = { - .name="Obsolete", .fns=&ignore_fns, - .flags=CFLG_GROUP_OBSOLETE, - } +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, }; /** @@ -787,5 +845,5 @@ lookup_type_def(config_type_t type) tor_assert(t >= 0); if (t >= (int)ARRAY_LENGTH(type_definitions_table)) return NULL; - return &type_definitions_table[t]; + return type_definitions_table[t]; } diff --git a/src/lib/confmgt/type_defs.h b/src/lib/confmgt/type_defs.h index ecf040529e..fec002b1d3 100644 --- a/src/lib/confmgt/type_defs.h +++ b/src/lib/confmgt/type_defs.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/confmgt/typedvar.c b/src/lib/confmgt/typedvar.c index ce11a69379..1955302cdc 100644 --- a/src/lib/confmgt/typedvar.c +++ b/src/lib/confmgt/typedvar.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -24,6 +24,7 @@ #include "lib/log/log.h" #include "lib/log/util_bug.h" #include "lib/malloc/malloc.h" +#include "lib/string/printf.h" #include "lib/string/util_string.h" #include "lib/confmgt/var_type_def_st.h" @@ -33,8 +34,7 @@ /** * Try to parse a string in <b>value</b> that encodes an object of the type - * defined by <b>def</b>. If not NULL, <b>key</b> is the name of the option, - * which may be used for logging. + * defined by <b>def</b>. * * On success, adjust the lvalue pointed to by <b>target</b> to hold that * value, and return 0. On failure, set *<b>errmsg</b> to a newly allocated @@ -42,7 +42,7 @@ **/ int typed_var_assign(void *target, const char *value, char **errmsg, - const var_type_def_t *def, const char *key) + const var_type_def_t *def) { if (BUG(!def)) return -1; // LCOV_EXCL_LINE @@ -50,7 +50,7 @@ typed_var_assign(void *target, const char *value, char **errmsg, typed_var_free(target, def); tor_assert(def->fns->parse); - return def->fns->parse(target, value, errmsg, def->params, key); + return def->fns->parse(target, value, errmsg, def->params); } /** @@ -76,7 +76,15 @@ typed_var_kvassign(void *target, const config_line_t *line, return def->fns->kv_parse(target, line, errmsg, def->params); } - return typed_var_assign(target, line->value, errmsg, def, line->key); + int rv = typed_var_assign(target, line->value, errmsg, def); + if (rv < 0 && *errmsg != NULL) { + /* typed_var_assign() didn't know the line's keyword, but we do. + * Let's add it to the error message. */ + char *oldmsg = *errmsg; + tor_asprintf(errmsg, "Could not parse %s: %s", line->key, oldmsg); + tor_free(oldmsg); + } + return rv; } /** @@ -159,7 +167,7 @@ typed_var_copy(void *dest, const void *src, const var_type_def_t *def) return 0; } char *err = NULL; - int rv = typed_var_assign(dest, enc, &err, def, NULL); + int rv = typed_var_assign(dest, enc, &err, def); if (BUG(rv < 0)) { // LCOV_EXCL_START log_warn(LD_BUG, "Encoded value %s was not parseable as a %s: %s", diff --git a/src/lib/confmgt/typedvar.h b/src/lib/confmgt/typedvar.h index 4382613833..cc90ed10a3 100644 --- a/src/lib/confmgt/typedvar.h +++ b/src/lib/confmgt/typedvar.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -21,7 +21,7 @@ typedef struct var_type_fns_t var_type_fns_t; typedef struct var_type_def_t var_type_def_t; int typed_var_assign(void *target, const char *value, char **errmsg, - const var_type_def_t *def, const char *key); + const var_type_def_t *def); void typed_var_free(void *target, const var_type_def_t *def); char *typed_var_encode(const void *value, const var_type_def_t *def); int typed_var_copy(void *dest, const void *src, const var_type_def_t *def); diff --git a/src/lib/confmgt/unitparse.c b/src/lib/confmgt/unitparse.c index c3ed8285a4..61edc60694 100644 --- a/src/lib/confmgt/unitparse.c +++ b/src/lib/confmgt/unitparse.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -13,8 +13,11 @@ #include "lib/confmgt/unitparse.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/string/util_string.h" +#include "lib/intmath/muldiv.h" #include <string.h> @@ -109,22 +112,30 @@ const struct unit_table_t time_msec_units[] = { * table <b>u</b>, then multiply the number by the unit multiplier. * On success, set *<b>ok</b> to 1 and return this product. * Otherwise, set *<b>ok</b> to 0. + * + * If an error (like overflow or a negative value is detected), put an error + * message in *<b>errmsg_out</b> if that pointer is non-NULL, and otherwise + * log a warning. */ uint64_t -config_parse_units(const char *val, const unit_table_t *u, int *ok) +config_parse_units(const char *val, const unit_table_t *u, int *ok, + char **errmsg_out) { uint64_t v = 0; double d = 0; int use_float = 0; char *cp; + char *errmsg = NULL; tor_assert(ok); v = tor_parse_uint64(val, 10, 0, UINT64_MAX, ok, &cp); if (!*ok || (cp && *cp == '.')) { d = tor_parse_double(val, 0, (double)UINT64_MAX, ok, &cp); - if (!*ok) + if (!*ok) { + tor_asprintf(&errmsg, "Unable to parse %s as a number", val); goto done; + } use_float = 1; } @@ -142,18 +153,55 @@ config_parse_units(const char *val, const unit_table_t *u, int *ok) for ( ;u->unit;++u) { if (!strcasecmp(u->unit, cp)) { - if (use_float) - v = (uint64_t)(u->multiplier * d); - else - v *= u->multiplier; + if (use_float) { + d = u->multiplier * d; + + if (d < 0) { + tor_asprintf(&errmsg, "Got a negative value while parsing %s %s", + val, u->unit); + *ok = 0; + goto done; + } + + // Some compilers may warn about casting a double to an unsigned type + // because they don't know if d is >= 0 + if (d >= 0 && (d > (double)INT64_MAX || (uint64_t)d > INT64_MAX)) { + tor_asprintf(&errmsg, "Overflow while parsing %s %s", + val, u->unit); + *ok = 0; + goto done; + } + + v = (uint64_t) d; + } else { + v = tor_mul_u64_nowrap(v, u->multiplier); + + if (v > INT64_MAX) { + tor_asprintf(&errmsg, "Overflow while parsing %s %s", + val, u->unit); + *ok = 0; + goto done; + } + } + *ok = 1; goto done; } } - log_warn(LD_CONFIG, "Unknown unit '%s'.", cp); + tor_asprintf(&errmsg, "Unknown unit in %s", val); *ok = 0; done: + if (errmsg) { + tor_assert_nonfatal(!*ok); + if (errmsg_out) { + *errmsg_out = errmsg; + } else { + log_warn(LD_CONFIG, "%s", errmsg); + tor_free(errmsg); + } + } + if (*ok) return v; else @@ -167,7 +215,7 @@ config_parse_units(const char *val, const unit_table_t *u, int *ok) uint64_t config_parse_memunit(const char *s, int *ok) { - uint64_t u = config_parse_units(s, memory_units, ok); + uint64_t u = config_parse_units(s, memory_units, ok, NULL); return u; } @@ -179,7 +227,7 @@ int config_parse_msec_interval(const char *s, int *ok) { uint64_t r; - r = config_parse_units(s, time_msec_units, ok); + r = config_parse_units(s, time_msec_units, ok, NULL); if (r > INT_MAX) { log_warn(LD_CONFIG, "Msec interval '%s' is too long", s); *ok = 0; @@ -196,7 +244,7 @@ int config_parse_interval(const char *s, int *ok) { uint64_t r; - r = config_parse_units(s, time_units, ok); + r = config_parse_units(s, time_units, ok, NULL); if (r > INT_MAX) { log_warn(LD_CONFIG, "Interval '%s' is too long", s); *ok = 0; diff --git a/src/lib/confmgt/unitparse.h b/src/lib/confmgt/unitparse.h index 216361a7d4..047e11b424 100644 --- a/src/lib/confmgt/unitparse.h +++ b/src/lib/confmgt/unitparse.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -25,7 +25,8 @@ extern const unit_table_t memory_units[]; extern const unit_table_t time_units[]; extern const struct unit_table_t time_msec_units[]; -uint64_t config_parse_units(const char *val, const unit_table_t *u, int *ok); +uint64_t config_parse_units(const char *val, const unit_table_t *u, int *ok, + char **errmsg_out); uint64_t config_parse_memunit(const char *s, int *ok); int config_parse_msec_interval(const char *s, int *ok); diff --git a/src/lib/confmgt/var_type_def_st.h b/src/lib/confmgt/var_type_def_st.h index aa9ded39e9..2519b86aa0 100644 --- a/src/lib/confmgt/var_type_def_st.h +++ b/src/lib/confmgt/var_type_def_st.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -52,12 +52,9 @@ struct var_type_fns_t { * type. On success, adjust the lvalue pointed to by <b>target</b> to hold * that value, and return 0. On failure, set *<b>errmsg</b> to a newly * allocated string holding an error message, and return -1. - * - * If not NULL, <b>key</b> is the name of the option, which may be used for - * logging. **/ int (*parse)(void *target, const char *value, char **errmsg, - const void *params, const char *key); + const void *params); /** * Try to parse a single line from the head of<b>line</b> that encodes * an object of this type. On success and failure, behave as in the parse() |