mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-30 23:53:32 +01:00
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.
This commit is contained in:
parent
b6457d4c08
commit
a7835202cf
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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) */
|
||||
|
@ -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
|
||||
|
@ -201,6 +201,19 @@ struct_var_kvencode(const void *object, const struct_member_t *member)
|
||||
return typed_var_kvencode_ex(member->name, p, def);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
**/
|
||||
@ -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;
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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, }
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -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,
|
||||
|
@ -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) */
|
||||
|
@ -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) */
|
||||
|
Loading…
Reference in New Issue
Block a user