commit a7835202cf871f68854494df904058a6e644c0b0 Author: Nick Mathewson nickm@torproject.org Date: Fri Jun 21 09:58:40 2019 -0400
Turn several properties of types or variables into flags.
"unsettable" is a property of types. LINELIST_V and OBSOLETE are unsettable, meaning that they cannot be set by name.
"contained" is a property of types. I'm hoping to find a better name here. LINELIST_S is "contained" because it always appears within a LINELIST_V, and as such doesn't need to be dumped ore copied independently.
"cumulative" is a property of types. Cumulative types can appear more than once in a torrc without causing a warning, because they add to each other rather than replacing each other.
"obsolete" is a property of variables.
"marking fragile" is now a command that struct members can accept.
With these changes, confparse and config no longer ever need to mention CONFIG_TYPE_XYZ values by name. --- src/app/config/config.c | 9 +++--- src/app/config/confparse.c | 45 ++++++++++++++++----------- src/app/config/confparse.h | 4 +++ src/lib/conf/confmacros.h | 4 ++- src/lib/conf/conftypes.h | 6 ++++ src/lib/confmgt/structvar.c | 37 ++++++++++++++++++++++ src/lib/confmgt/structvar.h | 5 +++ src/lib/confmgt/type_defs.c | 65 +++++++++++++++++++++++++++------------ src/lib/confmgt/typedvar.c | 45 +++++++++++++++++++++++++++ src/lib/confmgt/typedvar.h | 6 ++++ src/lib/confmgt/var_type_def_st.h | 20 ++++++++++++ 11 files changed, 203 insertions(+), 43 deletions(-)
diff --git a/src/app/config/config.c b/src/app/config/config.c index 5f7a82d15..d240a73fe 100644 --- a/src/app/config/config.c +++ b/src/app/config/config.c @@ -960,8 +960,8 @@ set_options(or_options_t *new_val, char **msg) for (i=0; options_format.vars[i].member.name; ++i) { const config_var_t *var = &options_format.vars[i]; const char *var_name = var->member.name; - if (var->member.type == CONFIG_TYPE_LINELIST_S || - var->member.type == CONFIG_TYPE_OBSOLETE) { + if (config_var_is_contained(var)) { + /* something else will check this var, or it doesn't need checking */ continue; } if (!config_is_same(&options_format, new_val, old_options, var_name)) { @@ -2663,9 +2663,10 @@ list_torrc_options(void) int i; for (i = 0; option_vars_[i].member.name; ++i) { const config_var_t *var = &option_vars_[i]; - if (var->member.type == CONFIG_TYPE_OBSOLETE || - var->member.type == CONFIG_TYPE_LINELIST_V) + if (! config_var_is_settable(var)) { + /* This variable cannot be set, or cannot be set by this name. */ continue; + } printf("%s\n", var->member.name); } } diff --git a/src/app/config/confparse.c b/src/app/config/confparse.c index 2890d8c81..0d19974d7 100644 --- a/src/app/config/confparse.c +++ b/src/app/config/confparse.c @@ -148,6 +148,24 @@ config_count_options(const config_format_t *fmt) return i; }
+bool +config_var_is_cumulative(const config_var_t *var) +{ + return struct_var_is_cumulative(&var->member); +} +bool +config_var_is_settable(const config_var_t *var) +{ + if (var->flags & CVFLAG_OBSOLETE) + return false; + return struct_var_is_settable(&var->member); +} +bool +config_var_is_contained(const config_var_t *var) +{ + return struct_var_is_contained(&var->member); +} + /* * Functions to assign config options. */ @@ -183,14 +201,7 @@ config_mark_lists_fragile(const config_format_t *fmt, void *options)
for (i = 0; fmt->vars[i].member.name; ++i) { const config_var_t *var = &fmt->vars[i]; - config_line_t *list; - if (var->member.type != CONFIG_TYPE_LINELIST && - var->member.type != CONFIG_TYPE_LINELIST_V) - continue; - - list = *(config_line_t **)STRUCT_VAR_P(options, var->member.offset); - if (list) - list->fragile = 1; + struct_var_mark_fragile(options, &var->member); } }
@@ -255,9 +266,7 @@ config_assign_line(const config_format_t *fmt, void *options, if (!strlen(c->value)) { /* reset or clear it, then return */ if (!clear_first) { - if ((var->member.type == CONFIG_TYPE_LINELIST || - var->member.type == CONFIG_TYPE_LINELIST_S) && - c->command != CONFIG_LINE_CLEAR) { + if (config_var_is_cumulative(var) && c->command != CONFIG_LINE_CLEAR) { /* We got an empty linelist from the torrc or command line. As a special case, call this an error. Warn and ignore. */ log_warn(LD_CONFIG, @@ -273,8 +282,7 @@ config_assign_line(const config_format_t *fmt, void *options, config_reset(fmt, options, var, use_defaults); // LCOV_EXCL_LINE }
- if (options_seen && (var->member.type != CONFIG_TYPE_LINELIST && - var->member.type != CONFIG_TYPE_LINELIST_S)) { + if (options_seen && ! config_var_is_cumulative(var)) { /* We're tracking which options we've seen, and this option is not * supposed to occur more than once. */ int var_index = (int)(var - fmt->vars); @@ -562,10 +570,10 @@ config_dup(const config_format_t *fmt, const void *old)
newopts = config_new(fmt); for (i=0; fmt->vars[i].member.name; ++i) { - if (fmt->vars[i].member.type == CONFIG_TYPE_LINELIST_S) - continue; - if (fmt->vars[i].member.type == CONFIG_TYPE_OBSOLETE) + if (config_var_is_contained(&fmt->vars[i])) { + // Something else will copy this option, or it doesn't need copying. continue; + } if (struct_var_copy(newopts, old, &fmt->vars[i].member) < 0) { // LCOV_EXCL_START log_err(LD_BUG, "Unable to copy value for %s.", @@ -629,9 +637,10 @@ config_dump(const config_format_t *fmt, const void *default_options, elements = smartlist_new(); for (i=0; fmt->vars[i].member.name; ++i) { int comment_option = 0; - if (fmt->vars[i].member.type == CONFIG_TYPE_OBSOLETE || - fmt->vars[i].member.type == CONFIG_TYPE_LINELIST_S) + if (config_var_is_contained(&fmt->vars[i])) { + // Something else will dump this option, or it doesn't need dumping. continue; + } /* Don't save 'hidden' control variables. */ if (!strcmpstart(fmt->vars[i].member.name, "__")) continue; diff --git a/src/app/config/confparse.h b/src/app/config/confparse.h index 6d63ba3e0..c53e3224d 100644 --- a/src/app/config/confparse.h +++ b/src/app/config/confparse.h @@ -104,6 +104,10 @@ const char *config_expand_abbrev(const config_format_t *fmt, int command_line, int warn_obsolete); void warn_deprecated_option(const char *what, const char *why);
+bool config_var_is_cumulative(const config_var_t *var); +bool config_var_is_settable(const config_var_t *var); +bool config_var_is_contained(const config_var_t *var); + /* Helper macros to compare an option across two configuration objects */ #define CFG_EQ_BOOL(a,b,opt) ((a)->opt == (b)->opt) #define CFG_EQ_INT(a,b,opt) ((a)->opt == (b)->opt) diff --git a/src/lib/conf/confmacros.h b/src/lib/conf/confmacros.h index ff284e681..aa89965e6 100644 --- a/src/lib/conf/confmacros.h +++ b/src/lib/conf/confmacros.h @@ -60,6 +60,8 @@ }
#define CONFIG_VAR_OBSOLETE(varname) \ - { .member = { .name = varname, .type = CONFIG_TYPE_OBSOLETE } } + { .member = { .name = varname, .type = CONFIG_TYPE_OBSOLETE }, \ + .flags = CVFLAG_OBSOLETE \ + }
#endif /* !defined(TOR_LIB_CONF_CONFMACROS_H) */ diff --git a/src/lib/conf/conftypes.h b/src/lib/conf/conftypes.h index 028a88991..6a44fb92e 100644 --- a/src/lib/conf/conftypes.h +++ b/src/lib/conf/conftypes.h @@ -105,6 +105,12 @@ typedef struct struct_magic_decl_t { int magic_offset; } struct_magic_decl_t;
+/** + * 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) + /** 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 diff --git a/src/lib/confmgt/structvar.c b/src/lib/confmgt/structvar.c index 38f8e5dd7..97a8fb363 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 92b9b6fc7..e6dbc6d6e 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 62b4c1019..f8b2681aa 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 c2b9b4572..3cba07539 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 720ad54fc..2e36f9d67 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 c63ff66ef..c4f7acec6 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) */
tor-commits@lists.torproject.org