diff options
author | Nick Mathewson <nickm@torproject.org> | 2019-08-22 17:25:35 -0400 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2019-08-22 17:25:35 -0400 |
commit | 2780cbb9cb9905a7194364d791da4d94ac419998 (patch) | |
tree | 76a29e21d60d9cbe83dfa16a64fadbe3fefbc679 /src/lib | |
parent | d475d7c2fb3c0ed5120c50011b187f6957a4f52c (diff) | |
parent | c32d485942e766eeea70cab468cc7c727a5be270 (diff) | |
download | tor-2780cbb9cb9905a7194364d791da4d94ac419998.tar.gz tor-2780cbb9cb9905a7194364d791da4d94ac419998.zip |
Merge branch 'ticket30935' into ticket30935_merged
Diffstat (limited to 'src/lib')
-rw-r--r-- | src/lib/conf/.may_include | 1 | ||||
-rw-r--r-- | src/lib/conf/confmacros.h | 67 | ||||
-rw-r--r-- | src/lib/conf/conftesting.h | 86 | ||||
-rw-r--r-- | src/lib/conf/conftypes.h | 63 | ||||
-rw-r--r-- | src/lib/conf/include.am | 4 | ||||
-rw-r--r-- | src/lib/confmgt/structvar.c | 37 | ||||
-rw-r--r-- | src/lib/confmgt/structvar.h | 5 | ||||
-rw-r--r-- | src/lib/confmgt/type_defs.c | 65 | ||||
-rw-r--r-- | src/lib/confmgt/typedvar.c | 45 | ||||
-rw-r--r-- | src/lib/confmgt/typedvar.h | 6 | ||||
-rw-r--r-- | src/lib/confmgt/var_type_def_st.h | 20 |
11 files changed, 346 insertions, 53 deletions
diff --git a/src/lib/conf/.may_include b/src/lib/conf/.may_include index 4285c3dcb8..629e2f897d 100644 --- a/src/lib/conf/.may_include +++ b/src/lib/conf/.may_include @@ -1,2 +1,3 @@ orconfig.h lib/cc/*.h +lib/conf/*.h diff --git a/src/lib/conf/confmacros.h b/src/lib/conf/confmacros.h new file mode 100644 index 0000000000..aa89965e69 --- /dev/null +++ b/src/lib/conf/confmacros.h @@ -0,0 +1,67 @@ +/* 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. */ +/* See LICENSE for licensing information */ + +/** + * @file confmacros.h + * @brief Macro definitions for declaring configuration variables + **/ + +#ifndef TOR_LIB_CONF_CONFMACROS_H +#define TOR_LIB_CONF_CONFMACROS_H + +#include "orconfig.h" +#include "lib/conf/conftesting.h" + +/** + * Used to indicate the end of an array of configuration variables. + **/ +#define END_OF_CONFIG_VARS \ + { .member = { .name = NULL } DUMMY_CONF_TEST_MEMBERS } + +/** + * Declare a config_var_t as a member named <b>membername</b> of the structure + * <b>structtype</b>, whose user-visible name is <b>varname</b>, whose + * type corresponds to the config_type_t member CONFIG_TYPE_<b>vartype</b>, + * and whose initial value is <b>intval</b>. + * + * Most modules that use this macro should wrap it in a local macro that + * sets structtype to the local configuration type. + **/ +#define CONFIG_VAR_ETYPE(structtype, varname, vartype, membername, \ + varflags, initval) \ + { .member = \ + { .name = varname, \ + .type = CONFIG_TYPE_ ## vartype, \ + .offset = offsetof(structtype, membername), \ + }, \ + .flags = varflags, \ + .initvalue = initval \ + CONF_TEST_MEMBERS(structtype, vartype, membername) \ + } + +/** + * As CONFIG_VAR_XTYPE, but declares a value using an extension type whose + * type definition is <b>vartype</b>_type_defn. + **/ +#define CONFIG_VAR_DEFN(structtype, varname, vartype, membername, \ + varflags, initval) \ + { .member = \ + { .name = varname, \ + .type = CONFIG_TYPE_EXTENDED, \ + .type_def = &vartype ## _type_defn, \ + .offset = offsetof(structtype, membername), \ + }, \ + .flags = varflags, \ + .initvalue = initval \ + CONF_TEST_MEMBERS(structtype, vartype, membername) \ + } + +#define CONFIG_VAR_OBSOLETE(varname) \ + { .member = { .name = varname, .type = CONFIG_TYPE_OBSOLETE }, \ + .flags = CVFLAG_OBSOLETE \ + } + +#endif /* !defined(TOR_LIB_CONF_CONFMACROS_H) */ diff --git a/src/lib/conf/conftesting.h b/src/lib/conf/conftesting.h new file mode 100644 index 0000000000..a40c9bc97c --- /dev/null +++ b/src/lib/conf/conftesting.h @@ -0,0 +1,86 @@ +/* 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. */ +/* See LICENSE for licensing information */ + +/** + * @file conftesting.h + * @brief Macro and type declarations for testing + **/ + +#ifndef TOR_LIB_CONF_CONFTESTING_H +#define TOR_LIB_CONF_CONFTESTING_H + +#ifdef TOR_UNIT_TESTS +/** + * Union used when building in test mode typechecking the members of a type + * used with confparse.c. See CONF_CHECK_VAR_TYPE for a description of how + * it is used. */ +typedef union { + char **STRING; + char **FILENAME; + int *POSINT; /* yes, this is really an int, and not an unsigned int. For + * historical reasons, many configuration values are restricted + * to the range [0,INT_MAX], and stored in signed ints. + */ + uint64_t *UINT64; + int *INT; + int *INTERVAL; + int *MSEC_INTERVAL; + uint64_t *MEMUNIT; + double *DOUBLE; + int *BOOL; + int *AUTOBOOL; + time_t *ISOTIME; + struct smartlist_t **CSV; + int *CSV_INTERVAL; + struct config_line_t **LINELIST; + struct config_line_t **LINELIST_S; + struct config_line_t **LINELIST_V; + // XXXX this doesn't belong at this level of abstraction. + struct routerset_t **ROUTERSET; +} confparse_dummy_values_t; +#endif /* defined(TOR_UNIT_TESTS) */ + +/* Macros to define extra members inside config_var_t fields, and at the + * end of a list of them. + */ +#ifdef TOR_UNIT_TESTS +/* This is a somewhat magic type-checking macro for users of confparse.c. + * It initializes a union member "confparse_dummy_values_t.conftype" with + * the address of a static member "tp_dummy.member". This + * will give a compiler warning unless the member field is of the correct + * type. + * + * (This warning is mandatory, because a type mismatch here violates the type + * compatibility constraint for simple assignment, and requires a diagnostic, + * according to the C spec.) + * + * For example, suppose you say: + * "CONF_CHECK_VAR_TYPE(or_options_t, STRING, Address)". + * Then this macro will evaluate to: + * { .STRING = &or_options_t_dummy.Address } + * And since confparse_dummy_values_t.STRING has type "char **", that + * expression will create a warning unless or_options_t.Address also + * has type "char *". + */ +#define CONF_CHECK_VAR_TYPE(tp, conftype, member) \ + { . conftype = &tp ## _dummy . member } +#define CONF_TEST_MEMBERS(tp, conftype, member) \ + , .var_ptr_dummy=CONF_CHECK_VAR_TYPE(tp, conftype, member) +#define DUMMY_CONF_TEST_MEMBERS , .var_ptr_dummy={ .INT=NULL } +#define DUMMY_TYPECHECK_INSTANCE(tp) \ + static tp tp ## _dummy + +#else /* !(defined(TOR_UNIT_TESTS)) */ + +#define CONF_TEST_MEMBERS(tp, conftype, member) +/* Repeatedly declarable incomplete struct to absorb redundant semicolons */ +#define DUMMY_TYPECHECK_INSTANCE(tp) \ + struct tor_semicolon_eater +#define DUMMY_CONF_TEST_MEMBERS + +#endif /* defined(TOR_UNIT_TESTS) */ + +#endif /* !defined(TOR_LIB_CONF_CONFTESTING_H) */ diff --git a/src/lib/conf/conftypes.h b/src/lib/conf/conftypes.h index cddfeff2fd..3b754e07be 100644 --- a/src/lib/conf/conftypes.h +++ b/src/lib/conf/conftypes.h @@ -29,6 +29,9 @@ #define TOR_SRC_LIB_CONF_CONFTYPES_H #include "lib/cc/torint.h" +#ifdef TOR_UNIT_TESTS +#include "lib/conf/conftesting.h" +#endif /** Enumeration of types which option values can take */ typedef enum config_type_t { @@ -59,9 +62,6 @@ typedef enum config_type_t { CONFIG_TYPE_LINELIST_V, /**< Catch-all "virtual" option to summarize * context-sensitive config lines when fetching. */ - // XXXX this doesn't belong at this level of abstraction. - CONFIG_TYPE_ROUTERSET, /**< A list of router names, addrs, and fps, - * parsed into a routerset_t. */ CONFIG_TYPE_OBSOLETE, /**< Obsolete (ignored) option. */ CONFIG_TYPE_EXTENDED, /**< Extended type; definition will appear in * pointer. */ @@ -105,35 +105,34 @@ typedef struct struct_magic_decl_t { int magic_offset; } struct_magic_decl_t; -#ifdef TOR_UNIT_TESTS /** - * Union used when building in test mode typechecking the members of a type - * used with confparse.c. See CONF_CHECK_VAR_TYPE for a description of how - * it is used. */ -typedef union { - char **STRING; - char **FILENAME; - int *POSINT; /* yes, this is really an int, and not an unsigned int. For - * historical reasons, many configuration values are restricted - * to the range [0,INT_MAX], and stored in signed ints. - */ - uint64_t *UINT64; - int *INT; - int *INTERVAL; - int *MSEC_INTERVAL; - uint64_t *MEMUNIT; - double *DOUBLE; - int *BOOL; - int *AUTOBOOL; - time_t *ISOTIME; - struct smartlist_t **CSV; - int *CSV_INTERVAL; - struct config_line_t **LINELIST; - struct config_line_t **LINELIST_S; - struct config_line_t **LINELIST_V; - // XXXX this doesn't belong at this level of abstraction. - struct routerset_t **ROUTERSET; -} confparse_dummy_values_t; -#endif /* defined(TOR_UNIT_TESTS) */ + * Flag to indicate that an option is obsolete. Any attempt to set or + * fetch this option should produce a warning. + **/ +#define CVFLAG_OBSOLETE (1u<<0) +/** + * Flag to indicate that an option is undumpable. An undumpable option is + * never saved to disk, and is prefixed with __. + **/ +#define CVFLAG_NODUMP (1u<<1) +/** + * Flag to indicate that an option is "invisible". An invisible option + * is always undumpable, and we don't tell the controller about it. + **/ +#define CVFLAG_INVISIBLE (1u<<2) + +/** A variable allowed in the configuration file or on the command line. */ +typedef struct config_var_t { + struct_member_t member; /** A struct member corresponding to this + * variable. */ + const char *initvalue; /**< String (or null) describing initial value. */ + uint32_t flags; /**< One or more flags describing special handling for this + * variable */ +#ifdef TOR_UNIT_TESTS + /** Used for compiler-magic to typecheck the corresponding field in the + * corresponding struct. Only used in unit test mode, at compile-time. */ + confparse_dummy_values_t var_ptr_dummy; +#endif +} config_var_t; #endif /* !defined(TOR_SRC_LIB_CONF_CONFTYPES_H) */ diff --git a/src/lib/conf/include.am b/src/lib/conf/include.am index 25355697d2..cb7126184d 100644 --- a/src/lib/conf/include.am +++ b/src/lib/conf/include.am @@ -1,4 +1,6 @@ # ADD_C_FILE: INSERT HEADERS HERE. noinst_HEADERS += \ - src/lib/conf/conftypes.h + src/lib/conf/conftesting.h \ + src/lib/conf/conftypes.h \ + src/lib/conf/confmacros.h diff --git a/src/lib/confmgt/structvar.c b/src/lib/confmgt/structvar.c index 38f8e5dd7a..97a8fb3633 100644 --- a/src/lib/confmgt/structvar.c +++ b/src/lib/confmgt/structvar.c @@ -202,6 +202,19 @@ struct_var_kvencode(const void *object, const struct_member_t *member) } /** + * Mark the field in <b>object</b> determined by <b>member</b> -- a variable + * that ordinarily would be extended by assignment -- as "fragile", so that it + * will get replaced by the next assignment instead. + */ +void +struct_var_mark_fragile(void *object, const struct_member_t *member) +{ + void *p = struct_get_mptr(object, member); + const var_type_def_t *def = get_type_def(member); + return typed_var_mark_fragile_ex(p, def); +} + +/** * Return the official name of this struct member. **/ const char * @@ -224,3 +237,27 @@ struct_var_get_typename(const struct_member_t *member) return def ? def->name : NULL; } + +bool +struct_var_is_cumulative(const struct_member_t *member) +{ + const var_type_def_t *def = get_type_def(member); + + return def ? def->is_cumulative : false; +} + +bool +struct_var_is_settable(const struct_member_t *member) +{ + const var_type_def_t *def = get_type_def(member); + + return def ? !def->is_unsettable : true; +} + +bool +struct_var_is_contained(const struct_member_t *member) +{ + const var_type_def_t *def = get_type_def(member); + + return def ? def->is_contained : false; +} diff --git a/src/lib/confmgt/structvar.h b/src/lib/confmgt/structvar.h index 92b9b6fc71..e6dbc6d6ec 100644 --- a/src/lib/confmgt/structvar.h +++ b/src/lib/confmgt/structvar.h @@ -40,9 +40,14 @@ bool struct_var_eq(const void *a, const void *b, const struct struct_member_t *member); bool struct_var_ok(const void *object, const struct struct_member_t *member); +void struct_var_mark_fragile(void *object, + const struct struct_member_t *member); const char *struct_var_get_name(const struct struct_member_t *member); const char *struct_var_get_typename(const struct struct_member_t *member); +bool struct_var_is_cumulative(const struct struct_member_t *member); +bool struct_var_is_settable(const struct struct_member_t *member); +bool struct_var_is_contained(const struct struct_member_t *member); int struct_var_kvassign(void *object, const struct config_line_t *line, char **errmsg, diff --git a/src/lib/confmgt/type_defs.c b/src/lib/confmgt/type_defs.c index 62b4c1019d..f8b2681aa0 100644 --- a/src/lib/confmgt/type_defs.c +++ b/src/lib/confmgt/type_defs.c @@ -620,12 +620,22 @@ linelist_copy(void *target, const void *value, const void *params) 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 = { @@ -634,6 +644,7 @@ static const var_type_fns_t linelist_v_fns = { .clear = linelist_clear, .eq = linelist_eq, .copy = linelist_copy, + .mark_fragile = linelist_mark_fragile, }; static const var_type_fns_t linelist_s_fns = { @@ -690,26 +701,40 @@ static const var_type_fns_t ignore_fns = { * 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", &string_fns, NULL }, - [CONFIG_TYPE_FILENAME] = { "Filename", &string_fns, NULL }, - [CONFIG_TYPE_INT] = { "SignedInteger", &int_fns, &INT_PARSE_UNRESTRICTED }, - [CONFIG_TYPE_POSINT] = { "Integer", &int_fns, &INT_PARSE_POSINT }, - [CONFIG_TYPE_UINT64] = { "Integer", &uint64_fns, NULL, }, - [CONFIG_TYPE_MEMUNIT] = { "DataSize", &memunit_fns, &memory_units }, - [CONFIG_TYPE_INTERVAL] = { "TimeInterval", &interval_fns, &time_units }, - [CONFIG_TYPE_MSEC_INTERVAL] = { "TimeMsecInterval", &interval_fns, - &time_msec_units }, - [CONFIG_TYPE_DOUBLE] = { "Float", &double_fns, NULL }, - [CONFIG_TYPE_BOOL] = { "Boolean", &enum_fns, &enum_table_bool }, - [CONFIG_TYPE_AUTOBOOL] = { "Boolean+Auto", &enum_fns, &enum_table_autobool }, - [CONFIG_TYPE_ISOTIME] = { "Time", &time_fns, NULL }, - [CONFIG_TYPE_CSV] = { "CommaList", &csv_fns, NULL }, - [CONFIG_TYPE_CSV_INTERVAL] = { "TimeInterval", &legacy_csv_interval_fns, - NULL }, - [CONFIG_TYPE_LINELIST] = { "LineList", &linelist_fns, NULL }, - [CONFIG_TYPE_LINELIST_S] = { "Dependent", &linelist_s_fns, NULL }, - [CONFIG_TYPE_LINELIST_V] = { "Virtual", &linelist_v_fns, NULL }, - [CONFIG_TYPE_OBSOLETE] = { "Obsolete", &ignore_fns, NULL } + [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, + .is_cumulative=true}, + [CONFIG_TYPE_LINELIST_S] = { .name="Dependent", .fns=&linelist_s_fns, + .is_cumulative=true, + .is_contained=true, }, + [CONFIG_TYPE_LINELIST_V] = { .name="Virtual", .fns=&linelist_v_fns, + .is_cumulative=true, + .is_unsettable=true }, + [CONFIG_TYPE_OBSOLETE] = { .name="Obsolete", .fns=&ignore_fns, + .is_unsettable=true, + .is_contained=true, } }; /** diff --git a/src/lib/confmgt/typedvar.c b/src/lib/confmgt/typedvar.c index c2b9b45725..3cba075390 100644 --- a/src/lib/confmgt/typedvar.c +++ b/src/lib/confmgt/typedvar.c @@ -210,6 +210,51 @@ typed_var_ok_ex(const void *value, const var_type_def_t *def) return true; } +/** + * Mark <b>value</b> -- a variable that ordinarily would be extended by + * assignment -- as "fragile", so that it will get replaced by the next + * assignment instead. + **/ +void +typed_var_mark_fragile_ex(void *value, const var_type_def_t *def) +{ + if (BUG(!def)) { + return; // LCOV_EXCL_LINE + } + + if (def->fns->mark_fragile) + def->fns->mark_fragile(value, def->params); +} + +/** + * Return true iff multiple assignments to a variable will extend its + * value, rather than replacing it. + **/ +bool +var_type_is_cumulative(const var_type_def_t *def) +{ + return def->is_cumulative; +} + +/** + * Return true iff this variable type is always contained in another variable, + * and as such doesn't need to be dumped or copied independently. + **/ +bool +var_type_is_contained(const var_type_def_t *def) +{ + return def->is_contained; +} + +/** + * Return true iff this type can not be assigned directly by the user. + **/ +bool +var_type_is_settable(const var_type_def_t *def) +{ + return ! def->is_unsettable; +} + /* ===== * The functions below take a config_type_t instead of a var_type_def_t. * I'd like to deprecate them eventually and use var_type_def_t everywhere, diff --git a/src/lib/confmgt/typedvar.h b/src/lib/confmgt/typedvar.h index 720ad54fc6..2e36f9d673 100644 --- a/src/lib/confmgt/typedvar.h +++ b/src/lib/confmgt/typedvar.h @@ -46,4 +46,10 @@ int typed_var_kvassign_ex(void *target, const struct config_line_t *line, struct config_line_t *typed_var_kvencode_ex(const char *key, const void *value, const var_type_def_t *def); +void typed_var_mark_fragile_ex(void *value, const var_type_def_t *def); + +bool var_type_is_cumulative(const var_type_def_t *def); +bool var_type_is_contained(const var_type_def_t *def); +bool var_type_is_settable(const var_type_def_t *def); + #endif /* !defined(TOR_LIB_CONFMGT_TYPEDVAR_H) */ diff --git a/src/lib/confmgt/var_type_def_st.h b/src/lib/confmgt/var_type_def_st.h index d142ee1104..4157cb8ff6 100644 --- a/src/lib/confmgt/var_type_def_st.h +++ b/src/lib/confmgt/var_type_def_st.h @@ -122,6 +122,15 @@ struct var_type_fns_t { * values are valid. **/ bool (*ok)(const void *value, const void *params); + /** + * Mark a value of this variable as "fragile", so that future attempts to + * assign to this variable will replace rather than extending it. + * + * The default implementation for this function does nothing. + * + * Only meaningful for types with is_cumulative set. + **/ + void (*mark_fragile)(void *value, const void *params); }; /** @@ -142,6 +151,17 @@ struct var_type_def_t { * calling the functions in this type's function table. */ const void *params; + + /** True iff a variable of this type can never be set directly by name. */ + bool is_unsettable; + /** True iff a variable of this type is always contained in another + * variable, and as such doesn't need to be dumped or copied + * independently. */ + bool is_contained; + /** True iff a variable of this type can be set more than once without + * destroying older values. Such variables should implement "mark_fragile". + */ + bool is_cumulative; }; #endif /* !defined(TOR_LIB_CONFMGT_VAR_TYPE_DEF_ST_H) */ |