Commit d475d7c2 authored by David Goulet's avatar David Goulet 🆘
Browse files

Merge branch 'tor-github/pr/1244'

parents cc48eff2 edf5a327
o Code simplification and refactoring:
- Lower another layer of object management from confparse.c to
a more general tool. Now typed structure members are accessible
via an abstract type. Implements ticket 30914.
......@@ -29,8 +29,8 @@
#
# Remember: It is better to fix the problem than to add a new exception!
problem file-size /src/app/config/config.c 8510
problem include-count /src/app/config/config.c 87
problem file-size /src/app/config/config.c 8518
problem include-count /src/app/config/config.c 88
problem function-size /src/app/config/config.c:options_act_reversible() 296
problem function-size /src/app/config/config.c:options_act() 589
problem function-size /src/app/config/config.c:resolve_my_address() 190
......
......@@ -111,6 +111,7 @@
#include "feature/stats/predict_ports.h"
#include "feature/stats/rephist.h"
#include "lib/compress/compress.h"
#include "lib/confmgt/structvar.h"
#include "lib/crypt_ops/crypto_init.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "lib/crypt_ops/crypto_util.h"
......@@ -253,23 +254,45 @@ static config_abbrev_t option_abbrevs_[] = {
* members with CONF_CHECK_VAR_TYPE. */
DUMMY_TYPECHECK_INSTANCE(or_options_t);
/** An entry for config_vars: "The option <b>name</b> has type
/** An entry for config_vars: "The option <b>varname</b> has type
* CONFIG_TYPE_<b>conftype</b>, and corresponds to
* or_options_t.<b>member</b>"
*/
#define VAR(name,conftype,member,initvalue) \
{ name, CONFIG_TYPE_ ## conftype, offsetof(or_options_t, member), \
#define VAR(varname,conftype,member,initvalue) \
{ { .name = varname, \
.type = CONFIG_TYPE_ ## conftype, \
.offset = offsetof(or_options_t, member), \
}, \
initvalue CONF_TEST_MEMBERS(or_options_t, conftype, member) }
/** As VAR, but the option name and member name are the same. */
#define V(member,conftype,initvalue) \
VAR(#member, conftype, member, initvalue)
/** An entry for config_vars: "The option <b>name</b> is obsolete." */
#ifdef TOR_UNIT_TESTS
#define OBSOLETE(name) { name, CONFIG_TYPE_OBSOLETE, 0, NULL, {.INT=NULL} }
#define DUMMY_TEST_MEMBERS , {.INT=NULL}
#else
#define OBSOLETE(name) { name, CONFIG_TYPE_OBSOLETE, 0, NULL }
#define DUMMY_TEST_MEMBERS
#endif
/* As VAR, but uses a type definition in addition to a type enum. */
#define VAR_D(varname,conftype,member,initvalue) \
{ { .name = varname, \
.type = CONFIG_TYPE_ ## conftype, \
.type_def = &conftype ## _type_defn, \
.offset = offsetof(or_options_t, member), \
}, \
initvalue DUMMY_TEST_MEMBERS }
/** As VAR, but the option name and member name are the same. */
#define V(member,conftype,initvalue) \
VAR(#member, conftype, member, initvalue)
/** As V, but uses a type definition instead of a type enum */
#define V_D(member,type,initvalue) \
VAR_D(#member, type, member, initvalue)
/** An entry for config_vars: "The option <b>varname</b> is obsolete." */
#define OBSOLETE(varname) \
{ { .name = varname, .type = CONFIG_TYPE_OBSOLETE, }, NULL \
DUMMY_TEST_MEMBERS }
/**
* Macro to declare *Port options. Each one comes in three entries.
* For example, most users should use "SocksPort" to configure the
......@@ -418,17 +441,17 @@ static config_var_t option_vars_[] = {
V(TestingEnableCellStatsEvent, BOOL, "0"),
OBSOLETE("TestingEnableTbEmptyEvent"),
V(EnforceDistinctSubnets, BOOL, "1"),
V(EntryNodes, ROUTERSET, NULL),
V_D(EntryNodes, ROUTERSET, NULL),
V(EntryStatistics, BOOL, "0"),
V(TestingEstimatedDescriptorPropagationTime, INTERVAL, "10 minutes"),
V(ExcludeNodes, ROUTERSET, NULL),
V(ExcludeExitNodes, ROUTERSET, NULL),
V_D(ExcludeNodes, ROUTERSET, NULL),
V_D(ExcludeExitNodes, ROUTERSET, NULL),
OBSOLETE("ExcludeSingleHopRelays"),
V(ExitNodes, ROUTERSET, NULL),
V_D(ExitNodes, ROUTERSET, NULL),
/* Researchers need a way to tell their clients to use specific
* middles that they also control, to allow safe live-network
* experimentation with new padding machines. */
V(MiddleNodes, ROUTERSET, NULL),
V_D(MiddleNodes, ROUTERSET, NULL),
V(ExitPolicy, LINELIST, NULL),
V(ExitPolicyRejectPrivate, BOOL, "1"),
V(ExitPolicyRejectLocalInterfaces, BOOL, "0"),
......@@ -507,8 +530,8 @@ static config_var_t option_vars_[] = {
V(Socks5ProxyPassword, STRING, NULL),
VAR("KeyDirectory", FILENAME, KeyDirectory_option, NULL),
V(KeyDirectoryGroupReadable, BOOL, "0"),
VAR("HSLayer2Nodes", ROUTERSET, HSLayer2Nodes, NULL),
VAR("HSLayer3Nodes", ROUTERSET, HSLayer3Nodes, NULL),
VAR_D("HSLayer2Nodes", ROUTERSET, HSLayer2Nodes, NULL),
VAR_D("HSLayer3Nodes", ROUTERSET, HSLayer3Nodes, NULL),
V(KeepalivePeriod, INTERVAL, "5 minutes"),
V(KeepBindCapabilities, AUTOBOOL, "auto"),
VAR("Log", LINELIST, Logs, NULL),
......@@ -732,11 +755,11 @@ static config_var_t option_vars_[] = {
OBSOLETE("TestingDescriptorMaxDownloadTries"),
OBSOLETE("TestingMicrodescMaxDownloadTries"),
OBSOLETE("TestingCertMaxDownloadTries"),
V(TestingDirAuthVoteExit, ROUTERSET, NULL),
V_D(TestingDirAuthVoteExit, ROUTERSET, NULL),
V(TestingDirAuthVoteExitIsStrict, BOOL, "0"),
V(TestingDirAuthVoteGuard, ROUTERSET, NULL),
V_D(TestingDirAuthVoteGuard, ROUTERSET, NULL),
V(TestingDirAuthVoteGuardIsStrict, BOOL, "0"),
V(TestingDirAuthVoteHSDir, ROUTERSET, NULL),
V_D(TestingDirAuthVoteHSDir, ROUTERSET, NULL),
V(TestingDirAuthVoteHSDirIsStrict, BOOL, "0"),
VAR("___UsingTestNetworkDefaults", BOOL, UsingTestNetworkDefaults_, "0"),
......@@ -855,8 +878,11 @@ static void set_protocol_warning_severity_level(int warning_severity);
/** Configuration format for or_options_t. */
STATIC config_format_t options_format = {
sizeof(or_options_t),
OR_OPTIONS_MAGIC,
offsetof(or_options_t, magic_),
{
"or_options_t",
OR_OPTIONS_MAGIC,
offsetof(or_options_t, magic_),
},
option_abbrevs_,
option_deprecation_notes_,
option_vars_,
......@@ -949,11 +975,11 @@ set_options(or_options_t *new_val, char **msg)
* just starting up then the old_options will be undefined. */
if (old_options && old_options != global_options) {
elements = smartlist_new();
for (i=0; options_format.vars[i].name; ++i) {
for (i=0; options_format.vars[i].member.name; ++i) {
const config_var_t *var = &options_format.vars[i];
const char *var_name = var->name;
if (var->type == CONFIG_TYPE_LINELIST_S ||
var->type == CONFIG_TYPE_OBSOLETE) {
const char *var_name = var->member.name;
if (var->member.type == CONFIG_TYPE_LINELIST_S ||
var->member.type == CONFIG_TYPE_OBSOLETE) {
continue;
}
if (!config_is_same(&options_format, new_val, old_options, var_name)) {
......@@ -969,7 +995,7 @@ set_options(or_options_t *new_val, char **msg)
tor_free(line);
}
} else {
smartlist_add_strdup(elements, options_format.vars[i].name);
smartlist_add_strdup(elements, options_format.vars[i].member.name);
smartlist_add(elements, NULL);
}
}
......@@ -2571,7 +2597,7 @@ const char *
option_get_canonical_name(const char *key)
{
const config_var_t *var = config_find_option(&options_format, key);
return var ? var->name : NULL;
return var ? var->member.name : NULL;
}
/** Return a canonical list of the options assigned for key.
......@@ -2653,12 +2679,12 @@ static void
list_torrc_options(void)
{
int i;
for (i = 0; option_vars_[i].name; ++i) {
for (i = 0; option_vars_[i].member.name; ++i) {
const config_var_t *var = &option_vars_[i];
if (var->type == CONFIG_TYPE_OBSOLETE ||
var->type == CONFIG_TYPE_LINELIST_V)
if (var->member.type == CONFIG_TYPE_OBSOLETE ||
var->member.type == CONFIG_TYPE_LINELIST_V)
continue;
printf("%s\n", var->name);
printf("%s\n", var->member.name);
}
}
......@@ -5445,18 +5471,18 @@ options_init_from_string(const char *cf_defaults, const char *cf,
* let's clean it up. -NM */
/* Change defaults. */
for (int i = 0; testing_tor_network_defaults[i].name; ++i) {
for (int i = 0; testing_tor_network_defaults[i].member.name; ++i) {
const config_var_t *new_var = &testing_tor_network_defaults[i];
config_var_t *old_var =
config_find_option_mutable(&options_format, new_var->name);
config_find_option_mutable(&options_format, new_var->member.name);
tor_assert(new_var);
tor_assert(old_var);
old_var->initvalue = new_var->initvalue;
if ((config_find_deprecation(&options_format, new_var->name))) {
if ((config_find_deprecation(&options_format, new_var->member.name))) {
log_warn(LD_GENERAL, "Testing options override the deprecated "
"option %s. Is that intentional?",
new_var->name);
new_var->member.name);
}
}
......@@ -8168,41 +8194,15 @@ getinfo_helper_config(control_connection_t *conn,
if (!strcmp(question, "config/names")) {
smartlist_t *sl = smartlist_new();
int i;
for (i = 0; option_vars_[i].name; ++i) {
for (i = 0; option_vars_[i].member.name; ++i) {
const config_var_t *var = &option_vars_[i];
const char *type;
/* don't tell controller about triple-underscore options */
if (!strncmp(option_vars_[i].name, "___", 3))
if (!strncmp(option_vars_[i].member.name, "___", 3))
continue;
switch (var->type) {
case CONFIG_TYPE_STRING: type = "String"; break;
case CONFIG_TYPE_FILENAME: type = "Filename"; break;
case CONFIG_TYPE_POSINT: type = "Integer"; break;
case CONFIG_TYPE_UINT64: type = "Integer"; break;
case CONFIG_TYPE_INT: type = "SignedInteger"; break;
case CONFIG_TYPE_INTERVAL: type = "TimeInterval"; break;
case CONFIG_TYPE_MSEC_INTERVAL: type = "TimeMsecInterval"; break;
case CONFIG_TYPE_MEMUNIT: type = "DataSize"; break;
case CONFIG_TYPE_DOUBLE: type = "Float"; break;
case CONFIG_TYPE_BOOL: type = "Boolean"; break;
case CONFIG_TYPE_AUTOBOOL: type = "Boolean+Auto"; break;
case CONFIG_TYPE_ISOTIME: type = "Time"; break;
case CONFIG_TYPE_ROUTERSET: type = "RouterList"; break;
case CONFIG_TYPE_CSV: type = "CommaList"; break;
/* This type accepts more inputs than TimeInterval, but it ignores
* everything after the first entry, so we may as well pretend
* it's a TimeInterval. */
case CONFIG_TYPE_CSV_INTERVAL: type = "TimeInterval"; break;
case CONFIG_TYPE_LINELIST: type = "LineList"; break;
case CONFIG_TYPE_LINELIST_S: type = "Dependent"; break;
case CONFIG_TYPE_LINELIST_V: type = "Virtual"; break;
default:
case CONFIG_TYPE_OBSOLETE:
type = NULL; break;
}
const char *type = struct_var_get_typename(&var->member);
if (!type)
continue;
smartlist_add_asprintf(sl, "%s %s\n",var->name,type);
smartlist_add_asprintf(sl, "%s %s\n",var->member.name,type);
}
*answer = smartlist_join_strings(sl, "", 0, NULL);
SMARTLIST_FOREACH(sl, char *, c, tor_free(c));
......@@ -8210,17 +8210,17 @@ getinfo_helper_config(control_connection_t *conn,
} else if (!strcmp(question, "config/defaults")) {
smartlist_t *sl = smartlist_new();
int dirauth_lines_seen = 0, fallback_lines_seen = 0;
for (int i = 0; option_vars_[i].name; ++i) {
for (int i = 0; option_vars_[i].member.name; ++i) {
const config_var_t *var = &option_vars_[i];
if (var->initvalue != NULL) {
if (strcmp(option_vars_[i].name, "DirAuthority") == 0) {
if (strcmp(option_vars_[i].member.name, "DirAuthority") == 0) {
/*
* Count dirauth lines we have a default for; we'll use the
* count later to decide whether to add the defaults manually
*/
++dirauth_lines_seen;
}
if (strcmp(option_vars_[i].name, "FallbackDir") == 0) {
if (strcmp(option_vars_[i].member.name, "FallbackDir") == 0) {
/*
* Similarly count fallback lines, so that we can decided later
* to add the defaults manually.
......@@ -8228,7 +8228,7 @@ getinfo_helper_config(control_connection_t *conn,
++fallback_lines_seen;
}
char *val = esc_for_log(var->initvalue);
smartlist_add_asprintf(sl, "%s %s\n",var->name,val);
smartlist_add_asprintf(sl, "%s %s\n",var->member.name,val);
tor_free(val);
}
}
......
......@@ -29,8 +29,7 @@
#include "lib/confmgt/unitparse.h"
#include "lib/container/bitarray.h"
#include "lib/encoding/confline.h"
#include "lib/confmgt/typedvar.h"
#include "lib/confmgt/structvar.h"
static void config_reset(const config_format_t *fmt, void *options,
const config_var_t *var, int use_defaults);
......@@ -40,7 +39,7 @@ void *
config_new(const config_format_t *fmt)
{
void *opts = tor_malloc_zero(fmt->size);
*(uint32_t*)STRUCT_VAR_P(opts, fmt->magic_offset) = fmt->magic;
struct_set_magic(opts, &fmt->magic);
CONFIG_CHECK(fmt, opts);
return opts;
}
......@@ -110,17 +109,17 @@ config_find_option_mutable(config_format_t *fmt, const char *key)
if (!keylen)
return NULL; /* if they say "--" on the command line, it's not an option */
/* First, check for an exact (case-insensitive) match */
for (i=0; fmt->vars[i].name; ++i) {
if (!strcasecmp(key, fmt->vars[i].name)) {
for (i=0; fmt->vars[i].member.name; ++i) {
if (!strcasecmp(key, fmt->vars[i].member.name)) {
return &fmt->vars[i];
}
}
/* If none, check for an abbreviated match */
for (i=0; fmt->vars[i].name; ++i) {
if (!strncasecmp(key, fmt->vars[i].name, keylen)) {
for (i=0; fmt->vars[i].member.name; ++i) {
if (!strncasecmp(key, fmt->vars[i].member.name, keylen)) {
log_warn(LD_CONFIG, "The abbreviation '%s' is deprecated. "
"Please use '%s' instead",
key, fmt->vars[i].name);
key, fmt->vars[i].member.name);
return &fmt->vars[i];
}
}
......@@ -144,7 +143,7 @@ static int
config_count_options(const config_format_t *fmt)
{
int i;
for (i=0; fmt->vars[i].name; ++i)
for (i=0; fmt->vars[i].member.name; ++i)
;
return i;
}
......@@ -163,33 +162,14 @@ config_assign_value(const config_format_t *fmt, void *options,
config_line_t *c, char **msg)
{
const config_var_t *var;
void *lvalue;
CONFIG_CHECK(fmt, options);
var = config_find_option(fmt, c->key);
tor_assert(var);
tor_assert(!strcmp(c->key, var->name));
lvalue = STRUCT_VAR_P(options, var->var_offset);
tor_assert(!strcmp(c->key, var->member.name));
if (var->type == CONFIG_TYPE_ROUTERSET) {
// XXXX make the backend extensible so that we don't have to
// XXXX handle ROUTERSET specially.
if (*(routerset_t**)lvalue) {
routerset_free(*(routerset_t**)lvalue);
}
*(routerset_t**)lvalue = routerset_new();
if (routerset_parse(*(routerset_t**)lvalue, c->value, c->key)<0) {
tor_asprintf(msg, "Invalid exit list '%s' for option '%s'",
c->value, c->key);
return -1;
}
return 0;
}
return typed_var_kvassign(lvalue, c, msg, var->type);
return struct_var_kvassign(options, c, msg, &var->member);
}
/** Mark every linelist in <b>options</b> "fragile", so that fresh assignments
......@@ -201,14 +181,14 @@ config_mark_lists_fragile(const config_format_t *fmt, void *options)
tor_assert(fmt);
tor_assert(options);
for (i = 0; fmt->vars[i].name; ++i) {
for (i = 0; fmt->vars[i].member.name; ++i) {
const config_var_t *var = &fmt->vars[i];
config_line_t *list;
if (var->type != CONFIG_TYPE_LINELIST &&
var->type != CONFIG_TYPE_LINELIST_V)
if (var->member.type != CONFIG_TYPE_LINELIST &&
var->member.type != CONFIG_TYPE_LINELIST_V)
continue;
list = *(config_line_t **)STRUCT_VAR_P(options, var->var_offset);
list = *(config_line_t **)STRUCT_VAR_P(options, var->member.offset);
if (list)
list->fragile = 1;
}
......@@ -248,7 +228,7 @@ config_assign_line(const config_format_t *fmt, void *options,
var = config_find_option(fmt, c->key);
if (!var) {
if (fmt->extra) {
void *lvalue = STRUCT_VAR_P(options, fmt->extra->var_offset);
void *lvalue = STRUCT_VAR_P(options, fmt->extra->offset);
log_info(LD_CONFIG,
"Found unrecognized option '%s'; saving it.", c->key);
config_line_append((config_line_t**)lvalue, c->key, c->value);
......@@ -261,22 +241,22 @@ config_assign_line(const config_format_t *fmt, void *options,
}
/* Put keyword into canonical case. */
if (strcmp(var->name, c->key)) {
if (strcmp(var->member.name, c->key)) {
tor_free(c->key);
c->key = tor_strdup(var->name);
c->key = tor_strdup(var->member.name);
}
const char *deprecation_msg;
if (warn_deprecations &&
(deprecation_msg = config_find_deprecation(fmt, var->name))) {
warn_deprecated_option(var->name, deprecation_msg);
(deprecation_msg = config_find_deprecation(fmt, var->member.name))) {
warn_deprecated_option(var->member.name, deprecation_msg);
}
if (!strlen(c->value)) {
/* reset or clear it, then return */
if (!clear_first) {
if ((var->type == CONFIG_TYPE_LINELIST ||
var->type == CONFIG_TYPE_LINELIST_S) &&
if ((var->member.type == CONFIG_TYPE_LINELIST ||
var->member.type == CONFIG_TYPE_LINELIST_S) &&
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. */
......@@ -293,14 +273,14 @@ config_assign_line(const config_format_t *fmt, void *options,
config_reset(fmt, options, var, use_defaults); // LCOV_EXCL_LINE
}
if (options_seen && (var->type != CONFIG_TYPE_LINELIST &&
var->type != CONFIG_TYPE_LINELIST_S)) {
if (options_seen && (var->member.type != CONFIG_TYPE_LINELIST &&
var->member.type != CONFIG_TYPE_LINELIST_S)) {
/* 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);
if (bitarray_is_set(options_seen, var_index)) {
log_warn(LD_CONFIG, "Option '%s' used more than once; all but the last "
"value will be ignored.", var->name);
"value will be ignored.", var->member.name);
}
bitarray_set(options_seen, var_index);
}
......@@ -362,7 +342,6 @@ config_get_assigned_option(const config_format_t *fmt, const void *options,
const char *key, int escape_val)
{
const config_var_t *var;
const void *value;
config_line_t *result;
tor_assert(options && key);
......@@ -373,17 +352,8 @@ config_get_assigned_option(const config_format_t *fmt, const void *options,
log_warn(LD_CONFIG, "Unknown option '%s'. Failing.", key);
return NULL;
}
value = STRUCT_VAR_P(options, var->var_offset);
if (var->type == CONFIG_TYPE_ROUTERSET) {
// XXXX make the backend extensible so that we don't have to
// XXXX handle ROUTERSET specially.
result = tor_malloc_zero(sizeof(config_line_t));
result->key = tor_strdup(var->name);
result->value = routerset_to_string(*(routerset_t**)value);
} else {
result = typed_var_kvencode(var->name, value, var->type);
}
result = struct_var_kvencode(options, &var->member);
if (escape_val) {
config_line_t *line;
......@@ -509,19 +479,10 @@ static void
config_clear(const config_format_t *fmt, void *options,
const config_var_t *var)
{
void *lvalue = STRUCT_VAR_P(options, var->var_offset);
(void)fmt; /* unused */
if (var->type == CONFIG_TYPE_ROUTERSET) {
// XXXX make the backend extensible so that we don't have to
// XXXX handle ROUTERSET specially.
if (*(routerset_t**)lvalue) {
routerset_free(*(routerset_t**)lvalue);
*(routerset_t**)lvalue = NULL;
}
return;
}
typed_var_free(lvalue, var->type);
struct_var_free(options, &var->member);
}
/** Clear the option indexed by <b>var</b> in <b>options</b>. Then if
......@@ -539,7 +500,7 @@ config_reset(const config_format_t *fmt, void *options,
return; /* all done */
if (var->initvalue) {
c = tor_malloc_zero(sizeof(config_line_t));
c->key = tor_strdup(var->name);
c->key = tor_strdup(var->member.name);
c->value = tor_strdup(var->initvalue);
if (config_assign_value(fmt, options, c, &msg) < 0) {
// LCOV_EXCL_START
......@@ -562,10 +523,11 @@ config_free_(const config_format_t *fmt, void *options)
tor_assert(fmt);
for (i=0; fmt->vars[i].name; ++i)
for (i=0; fmt->vars[i].member.name; ++i)
config_clear(fmt, options, &(fmt->vars[i]));
if (fmt->extra) {
config_line_t **linep = STRUCT_VAR_P(options, fmt->extra->var_offset);
config_line_t **linep = STRUCT_VAR_P(options, fmt->extra->offset);
config_free_lines(*linep);
*linep = NULL;
}
......@@ -580,17 +542,15 @@ config_is_same(const config_format_t *fmt,
const void *o1, const void *o2,
const char *name)
{
config_line_t *c1, *c2;
int r = 1;
CONFIG_CHECK(fmt, o1);
CONFIG_CHECK(fmt, o2);
c1 = config_get_assigned_option(fmt, o1, name, 0);
c2 = config_get_assigned_option(fmt, o2, name, 0);
r = config_lines_eq(c1, c2);
config_free_lines(c1);
config_free_lines(c2);
return r;
const config_var_t *var = config_find_option(fmt, name);
if (!var) {
return true;
}
return struct_var_eq(o1, o2, &var->member);
}
/** Copy storage held by <b>old</b> into a new or_options_t and return it. */
......@@ -599,27 +559,20 @@ config_dup(const config_format_t *fmt, const void *old)
{
void *newopts;
int i;
config_line_t *line;
newopts = config_new(fmt);
for (i=0; fmt->vars[i].name; ++i) {
if (fmt->vars[i].type == CONFIG_TYPE_LINELIST_S)
for (i=0; fmt->vars[i].member.name; ++i) {
if (fmt->vars[i].member.type == CONFIG_TYPE_LINELIST_S)
continue;
if (fmt->vars[i].type == CONFIG_TYPE_OBSOLETE)
if (fmt->vars[i].member.type == CONFIG_TYPE_OBSOLETE)
continue;
line = config_get_assigned_option(fmt, old, fmt->vars[i].name, 0);
if (line) {
char *msg = NULL;
if (config_assign(fmt, newopts, line, 0, &msg) < 0) {
// LCOV_EXCL_START
log_err(LD_BUG, "config_get_assigned_option() generated "
"something we couldn't config_assign(): %s", msg);
tor_free(msg);
tor_assert(0);
// LCOV_EXCL_STOP
}
if (struct_var_copy(newopts, old, &fmt->vars[i].member) < 0) {
// LCOV_EXCL_START
log_err(LD_BUG, "Unable to copy value for %s.",
fmt->vars[i].member.name);
tor_assert_unreached();
// LCOV_EXCL_STOP
}
config_free_lines(line);
}
return newopts;
}
......@@ -632,7 +585,7 @@ config_init(const config_format_t *fmt, void *options)
const config_var_t *var;
CONFIG_CHECK(fmt, options);
for (i=0; fmt->vars[i].name; ++i) {
for (i=0; fmt->vars[i].member.name; ++i) {
var = &fmt->vars[i];
if (!var->initvalue)
continue; /* defaults to NULL or 0 */
......@@ -674,22 +627,23 @@ config_dump(const config_format_t *fmt, const void *default_options,
}
elements = smartlist_new();
for (i=0; fmt->vars[i].name; ++i) {
for (i=0; fmt->vars[i].member.name; ++i) {
int comment_option = 0;
if (fmt->vars[i].type == CONFIG_TYPE_OBSOLETE ||
fmt->vars[i].type == CONFIG_TYPE_LINELIST_S)
if (fmt->vars[i].member.type == CONFIG_TYPE_OBSOLETE ||
fmt->vars[i].member.type == CONFIG_TYPE_LINELIST_S)
continue;
/* Don't save 'hidden' control variables. */
if (!strcmpstart(fmt->vars[i].name, "__"))
if (!strcmpstart(fmt->vars[i].member.name, "__"))
continue;
if (minimal && config_is_same(fmt, options, defaults, fmt->vars[i].name))
if (minimal && config_is_same(fmt, options, defaults,
fmt->vars[i].member.name))