mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-10 05:03:43 +01:00
Merge branch 'tor-github/pr/1244'
This commit is contained in:
commit
d475d7c2fb
4
changes/ticket30914
Normal file
4
changes/ticket30914
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
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!
|
# Remember: It is better to fix the problem than to add a new exception!
|
||||||
|
|
||||||
problem file-size /src/app/config/config.c 8510
|
problem file-size /src/app/config/config.c 8518
|
||||||
problem include-count /src/app/config/config.c 87
|
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_reversible() 296
|
||||||
problem function-size /src/app/config/config.c:options_act() 589
|
problem function-size /src/app/config/config.c:options_act() 589
|
||||||
problem function-size /src/app/config/config.c:resolve_my_address() 190
|
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/predict_ports.h"
|
||||||
#include "feature/stats/rephist.h"
|
#include "feature/stats/rephist.h"
|
||||||
#include "lib/compress/compress.h"
|
#include "lib/compress/compress.h"
|
||||||
|
#include "lib/confmgt/structvar.h"
|
||||||
#include "lib/crypt_ops/crypto_init.h"
|
#include "lib/crypt_ops/crypto_init.h"
|
||||||
#include "lib/crypt_ops/crypto_rand.h"
|
#include "lib/crypt_ops/crypto_rand.h"
|
||||||
#include "lib/crypt_ops/crypto_util.h"
|
#include "lib/crypt_ops/crypto_util.h"
|
||||||
@ -253,22 +254,44 @@ static config_abbrev_t option_abbrevs_[] = {
|
|||||||
* members with CONF_CHECK_VAR_TYPE. */
|
* members with CONF_CHECK_VAR_TYPE. */
|
||||||
DUMMY_TYPECHECK_INSTANCE(or_options_t);
|
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
|
* CONFIG_TYPE_<b>conftype</b>, and corresponds to
|
||||||
* or_options_t.<b>member</b>"
|
* or_options_t.<b>member</b>"
|
||||||
*/
|
*/
|
||||||
#define VAR(name,conftype,member,initvalue) \
|
#define VAR(varname,conftype,member,initvalue) \
|
||||||
{ name, CONFIG_TYPE_ ## conftype, offsetof(or_options_t, member), \
|
{ { .name = varname, \
|
||||||
|
.type = CONFIG_TYPE_ ## conftype, \
|
||||||
|
.offset = offsetof(or_options_t, member), \
|
||||||
|
}, \
|
||||||
initvalue CONF_TEST_MEMBERS(or_options_t, conftype, member) }
|
initvalue CONF_TEST_MEMBERS(or_options_t, conftype, member) }
|
||||||
|
|
||||||
|
#ifdef TOR_UNIT_TESTS
|
||||||
|
#define DUMMY_TEST_MEMBERS , {.INT=NULL}
|
||||||
|
#else
|
||||||
|
#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. */
|
/** As VAR, but the option name and member name are the same. */
|
||||||
#define V(member,conftype,initvalue) \
|
#define V(member,conftype,initvalue) \
|
||||||
VAR(#member, conftype, member, initvalue)
|
VAR(#member, conftype, member, initvalue)
|
||||||
/** An entry for config_vars: "The option <b>name</b> is obsolete." */
|
|
||||||
#ifdef TOR_UNIT_TESTS
|
/** As V, but uses a type definition instead of a type enum */
|
||||||
#define OBSOLETE(name) { name, CONFIG_TYPE_OBSOLETE, 0, NULL, {.INT=NULL} }
|
#define V_D(member,type,initvalue) \
|
||||||
#else
|
VAR_D(#member, type, member, initvalue)
|
||||||
#define OBSOLETE(name) { name, CONFIG_TYPE_OBSOLETE, 0, NULL }
|
|
||||||
#endif
|
/** 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.
|
* Macro to declare *Port options. Each one comes in three entries.
|
||||||
@ -418,17 +441,17 @@ static config_var_t option_vars_[] = {
|
|||||||
V(TestingEnableCellStatsEvent, BOOL, "0"),
|
V(TestingEnableCellStatsEvent, BOOL, "0"),
|
||||||
OBSOLETE("TestingEnableTbEmptyEvent"),
|
OBSOLETE("TestingEnableTbEmptyEvent"),
|
||||||
V(EnforceDistinctSubnets, BOOL, "1"),
|
V(EnforceDistinctSubnets, BOOL, "1"),
|
||||||
V(EntryNodes, ROUTERSET, NULL),
|
V_D(EntryNodes, ROUTERSET, NULL),
|
||||||
V(EntryStatistics, BOOL, "0"),
|
V(EntryStatistics, BOOL, "0"),
|
||||||
V(TestingEstimatedDescriptorPropagationTime, INTERVAL, "10 minutes"),
|
V(TestingEstimatedDescriptorPropagationTime, INTERVAL, "10 minutes"),
|
||||||
V(ExcludeNodes, ROUTERSET, NULL),
|
V_D(ExcludeNodes, ROUTERSET, NULL),
|
||||||
V(ExcludeExitNodes, ROUTERSET, NULL),
|
V_D(ExcludeExitNodes, ROUTERSET, NULL),
|
||||||
OBSOLETE("ExcludeSingleHopRelays"),
|
OBSOLETE("ExcludeSingleHopRelays"),
|
||||||
V(ExitNodes, ROUTERSET, NULL),
|
V_D(ExitNodes, ROUTERSET, NULL),
|
||||||
/* Researchers need a way to tell their clients to use specific
|
/* Researchers need a way to tell their clients to use specific
|
||||||
* middles that they also control, to allow safe live-network
|
* middles that they also control, to allow safe live-network
|
||||||
* experimentation with new padding machines. */
|
* experimentation with new padding machines. */
|
||||||
V(MiddleNodes, ROUTERSET, NULL),
|
V_D(MiddleNodes, ROUTERSET, NULL),
|
||||||
V(ExitPolicy, LINELIST, NULL),
|
V(ExitPolicy, LINELIST, NULL),
|
||||||
V(ExitPolicyRejectPrivate, BOOL, "1"),
|
V(ExitPolicyRejectPrivate, BOOL, "1"),
|
||||||
V(ExitPolicyRejectLocalInterfaces, BOOL, "0"),
|
V(ExitPolicyRejectLocalInterfaces, BOOL, "0"),
|
||||||
@ -507,8 +530,8 @@ static config_var_t option_vars_[] = {
|
|||||||
V(Socks5ProxyPassword, STRING, NULL),
|
V(Socks5ProxyPassword, STRING, NULL),
|
||||||
VAR("KeyDirectory", FILENAME, KeyDirectory_option, NULL),
|
VAR("KeyDirectory", FILENAME, KeyDirectory_option, NULL),
|
||||||
V(KeyDirectoryGroupReadable, BOOL, "0"),
|
V(KeyDirectoryGroupReadable, BOOL, "0"),
|
||||||
VAR("HSLayer2Nodes", ROUTERSET, HSLayer2Nodes, NULL),
|
VAR_D("HSLayer2Nodes", ROUTERSET, HSLayer2Nodes, NULL),
|
||||||
VAR("HSLayer3Nodes", ROUTERSET, HSLayer3Nodes, NULL),
|
VAR_D("HSLayer3Nodes", ROUTERSET, HSLayer3Nodes, NULL),
|
||||||
V(KeepalivePeriod, INTERVAL, "5 minutes"),
|
V(KeepalivePeriod, INTERVAL, "5 minutes"),
|
||||||
V(KeepBindCapabilities, AUTOBOOL, "auto"),
|
V(KeepBindCapabilities, AUTOBOOL, "auto"),
|
||||||
VAR("Log", LINELIST, Logs, NULL),
|
VAR("Log", LINELIST, Logs, NULL),
|
||||||
@ -732,11 +755,11 @@ static config_var_t option_vars_[] = {
|
|||||||
OBSOLETE("TestingDescriptorMaxDownloadTries"),
|
OBSOLETE("TestingDescriptorMaxDownloadTries"),
|
||||||
OBSOLETE("TestingMicrodescMaxDownloadTries"),
|
OBSOLETE("TestingMicrodescMaxDownloadTries"),
|
||||||
OBSOLETE("TestingCertMaxDownloadTries"),
|
OBSOLETE("TestingCertMaxDownloadTries"),
|
||||||
V(TestingDirAuthVoteExit, ROUTERSET, NULL),
|
V_D(TestingDirAuthVoteExit, ROUTERSET, NULL),
|
||||||
V(TestingDirAuthVoteExitIsStrict, BOOL, "0"),
|
V(TestingDirAuthVoteExitIsStrict, BOOL, "0"),
|
||||||
V(TestingDirAuthVoteGuard, ROUTERSET, NULL),
|
V_D(TestingDirAuthVoteGuard, ROUTERSET, NULL),
|
||||||
V(TestingDirAuthVoteGuardIsStrict, BOOL, "0"),
|
V(TestingDirAuthVoteGuardIsStrict, BOOL, "0"),
|
||||||
V(TestingDirAuthVoteHSDir, ROUTERSET, NULL),
|
V_D(TestingDirAuthVoteHSDir, ROUTERSET, NULL),
|
||||||
V(TestingDirAuthVoteHSDirIsStrict, BOOL, "0"),
|
V(TestingDirAuthVoteHSDirIsStrict, BOOL, "0"),
|
||||||
VAR("___UsingTestNetworkDefaults", BOOL, UsingTestNetworkDefaults_, "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. */
|
/** Configuration format for or_options_t. */
|
||||||
STATIC config_format_t options_format = {
|
STATIC config_format_t options_format = {
|
||||||
sizeof(or_options_t),
|
sizeof(or_options_t),
|
||||||
|
{
|
||||||
|
"or_options_t",
|
||||||
OR_OPTIONS_MAGIC,
|
OR_OPTIONS_MAGIC,
|
||||||
offsetof(or_options_t, magic_),
|
offsetof(or_options_t, magic_),
|
||||||
|
},
|
||||||
option_abbrevs_,
|
option_abbrevs_,
|
||||||
option_deprecation_notes_,
|
option_deprecation_notes_,
|
||||||
option_vars_,
|
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. */
|
* just starting up then the old_options will be undefined. */
|
||||||
if (old_options && old_options != global_options) {
|
if (old_options && old_options != global_options) {
|
||||||
elements = smartlist_new();
|
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 config_var_t *var = &options_format.vars[i];
|
||||||
const char *var_name = var->name;
|
const char *var_name = var->member.name;
|
||||||
if (var->type == CONFIG_TYPE_LINELIST_S ||
|
if (var->member.type == CONFIG_TYPE_LINELIST_S ||
|
||||||
var->type == CONFIG_TYPE_OBSOLETE) {
|
var->member.type == CONFIG_TYPE_OBSOLETE) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!config_is_same(&options_format, new_val, old_options, var_name)) {
|
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);
|
tor_free(line);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
smartlist_add_strdup(elements, options_format.vars[i].name);
|
smartlist_add_strdup(elements, options_format.vars[i].member.name);
|
||||||
smartlist_add(elements, NULL);
|
smartlist_add(elements, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2571,7 +2597,7 @@ const char *
|
|||||||
option_get_canonical_name(const char *key)
|
option_get_canonical_name(const char *key)
|
||||||
{
|
{
|
||||||
const config_var_t *var = config_find_option(&options_format, 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.
|
/** Return a canonical list of the options assigned for key.
|
||||||
@ -2653,12 +2679,12 @@ static void
|
|||||||
list_torrc_options(void)
|
list_torrc_options(void)
|
||||||
{
|
{
|
||||||
int i;
|
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 config_var_t *var = &option_vars_[i];
|
||||||
if (var->type == CONFIG_TYPE_OBSOLETE ||
|
if (var->member.type == CONFIG_TYPE_OBSOLETE ||
|
||||||
var->type == CONFIG_TYPE_LINELIST_V)
|
var->member.type == CONFIG_TYPE_LINELIST_V)
|
||||||
continue;
|
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 */
|
* let's clean it up. -NM */
|
||||||
|
|
||||||
/* Change defaults. */
|
/* 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];
|
const config_var_t *new_var = &testing_tor_network_defaults[i];
|
||||||
config_var_t *old_var =
|
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(new_var);
|
||||||
tor_assert(old_var);
|
tor_assert(old_var);
|
||||||
old_var->initvalue = new_var->initvalue;
|
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 "
|
log_warn(LD_GENERAL, "Testing options override the deprecated "
|
||||||
"option %s. Is that intentional?",
|
"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")) {
|
if (!strcmp(question, "config/names")) {
|
||||||
smartlist_t *sl = smartlist_new();
|
smartlist_t *sl = smartlist_new();
|
||||||
int i;
|
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 config_var_t *var = &option_vars_[i];
|
||||||
const char *type;
|
|
||||||
/* don't tell controller about triple-underscore options */
|
/* don't tell controller about triple-underscore options */
|
||||||
if (!strncmp(option_vars_[i].name, "___", 3))
|
if (!strncmp(option_vars_[i].member.name, "___", 3))
|
||||||
continue;
|
continue;
|
||||||
switch (var->type) {
|
const char *type = struct_var_get_typename(&var->member);
|
||||||
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;
|
|
||||||
}
|
|
||||||
if (!type)
|
if (!type)
|
||||||
continue;
|
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);
|
*answer = smartlist_join_strings(sl, "", 0, NULL);
|
||||||
SMARTLIST_FOREACH(sl, char *, c, tor_free(c));
|
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")) {
|
} else if (!strcmp(question, "config/defaults")) {
|
||||||
smartlist_t *sl = smartlist_new();
|
smartlist_t *sl = smartlist_new();
|
||||||
int dirauth_lines_seen = 0, fallback_lines_seen = 0;
|
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];
|
const config_var_t *var = &option_vars_[i];
|
||||||
if (var->initvalue != NULL) {
|
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 dirauth lines we have a default for; we'll use the
|
||||||
* count later to decide whether to add the defaults manually
|
* count later to decide whether to add the defaults manually
|
||||||
*/
|
*/
|
||||||
++dirauth_lines_seen;
|
++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
|
* Similarly count fallback lines, so that we can decided later
|
||||||
* to add the defaults manually.
|
* to add the defaults manually.
|
||||||
@ -8228,7 +8228,7 @@ getinfo_helper_config(control_connection_t *conn,
|
|||||||
++fallback_lines_seen;
|
++fallback_lines_seen;
|
||||||
}
|
}
|
||||||
char *val = esc_for_log(var->initvalue);
|
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);
|
tor_free(val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,8 +29,7 @@
|
|||||||
#include "lib/confmgt/unitparse.h"
|
#include "lib/confmgt/unitparse.h"
|
||||||
#include "lib/container/bitarray.h"
|
#include "lib/container/bitarray.h"
|
||||||
#include "lib/encoding/confline.h"
|
#include "lib/encoding/confline.h"
|
||||||
|
#include "lib/confmgt/structvar.h"
|
||||||
#include "lib/confmgt/typedvar.h"
|
|
||||||
|
|
||||||
static void config_reset(const config_format_t *fmt, void *options,
|
static void config_reset(const config_format_t *fmt, void *options,
|
||||||
const config_var_t *var, int use_defaults);
|
const config_var_t *var, int use_defaults);
|
||||||
@ -40,7 +39,7 @@ void *
|
|||||||
config_new(const config_format_t *fmt)
|
config_new(const config_format_t *fmt)
|
||||||
{
|
{
|
||||||
void *opts = tor_malloc_zero(fmt->size);
|
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);
|
CONFIG_CHECK(fmt, opts);
|
||||||
return opts;
|
return opts;
|
||||||
}
|
}
|
||||||
@ -110,17 +109,17 @@ config_find_option_mutable(config_format_t *fmt, const char *key)
|
|||||||
if (!keylen)
|
if (!keylen)
|
||||||
return NULL; /* if they say "--" on the command line, it's not an option */
|
return NULL; /* if they say "--" on the command line, it's not an option */
|
||||||
/* First, check for an exact (case-insensitive) match */
|
/* First, check for an exact (case-insensitive) match */
|
||||||
for (i=0; fmt->vars[i].name; ++i) {
|
for (i=0; fmt->vars[i].member.name; ++i) {
|
||||||
if (!strcasecmp(key, fmt->vars[i].name)) {
|
if (!strcasecmp(key, fmt->vars[i].member.name)) {
|
||||||
return &fmt->vars[i];
|
return &fmt->vars[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* If none, check for an abbreviated match */
|
/* If none, check for an abbreviated match */
|
||||||
for (i=0; fmt->vars[i].name; ++i) {
|
for (i=0; fmt->vars[i].member.name; ++i) {
|
||||||
if (!strncasecmp(key, fmt->vars[i].name, keylen)) {
|
if (!strncasecmp(key, fmt->vars[i].member.name, keylen)) {
|
||||||
log_warn(LD_CONFIG, "The abbreviation '%s' is deprecated. "
|
log_warn(LD_CONFIG, "The abbreviation '%s' is deprecated. "
|
||||||
"Please use '%s' instead",
|
"Please use '%s' instead",
|
||||||
key, fmt->vars[i].name);
|
key, fmt->vars[i].member.name);
|
||||||
return &fmt->vars[i];
|
return &fmt->vars[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -144,7 +143,7 @@ static int
|
|||||||
config_count_options(const config_format_t *fmt)
|
config_count_options(const config_format_t *fmt)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
for (i=0; fmt->vars[i].name; ++i)
|
for (i=0; fmt->vars[i].member.name; ++i)
|
||||||
;
|
;
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
@ -163,33 +162,14 @@ config_assign_value(const config_format_t *fmt, void *options,
|
|||||||
config_line_t *c, char **msg)
|
config_line_t *c, char **msg)
|
||||||
{
|
{
|
||||||
const config_var_t *var;
|
const config_var_t *var;
|
||||||
void *lvalue;
|
|
||||||
|
|
||||||
CONFIG_CHECK(fmt, options);
|
CONFIG_CHECK(fmt, options);
|
||||||
|
|
||||||
var = config_find_option(fmt, c->key);
|
var = config_find_option(fmt, c->key);
|
||||||
tor_assert(var);
|
tor_assert(var);
|
||||||
tor_assert(!strcmp(c->key, var->name));
|
tor_assert(!strcmp(c->key, var->member.name));
|
||||||
|
|
||||||
lvalue = STRUCT_VAR_P(options, var->var_offset);
|
return struct_var_kvassign(options, c, msg, &var->member);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Mark every linelist in <b>options</b> "fragile", so that fresh assignments
|
/** 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(fmt);
|
||||||
tor_assert(options);
|
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];
|
const config_var_t *var = &fmt->vars[i];
|
||||||
config_line_t *list;
|
config_line_t *list;
|
||||||
if (var->type != CONFIG_TYPE_LINELIST &&
|
if (var->member.type != CONFIG_TYPE_LINELIST &&
|
||||||
var->type != CONFIG_TYPE_LINELIST_V)
|
var->member.type != CONFIG_TYPE_LINELIST_V)
|
||||||
continue;
|
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)
|
if (list)
|
||||||
list->fragile = 1;
|
list->fragile = 1;
|
||||||
}
|
}
|
||||||
@ -248,7 +228,7 @@ config_assign_line(const config_format_t *fmt, void *options,
|
|||||||
var = config_find_option(fmt, c->key);
|
var = config_find_option(fmt, c->key);
|
||||||
if (!var) {
|
if (!var) {
|
||||||
if (fmt->extra) {
|
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,
|
log_info(LD_CONFIG,
|
||||||
"Found unrecognized option '%s'; saving it.", c->key);
|
"Found unrecognized option '%s'; saving it.", c->key);
|
||||||
config_line_append((config_line_t**)lvalue, c->key, c->value);
|
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. */
|
/* Put keyword into canonical case. */
|
||||||
if (strcmp(var->name, c->key)) {
|
if (strcmp(var->member.name, c->key)) {
|
||||||
tor_free(c->key);
|
tor_free(c->key);
|
||||||
c->key = tor_strdup(var->name);
|
c->key = tor_strdup(var->member.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *deprecation_msg;
|
const char *deprecation_msg;
|
||||||
if (warn_deprecations &&
|
if (warn_deprecations &&
|
||||||
(deprecation_msg = config_find_deprecation(fmt, var->name))) {
|
(deprecation_msg = config_find_deprecation(fmt, var->member.name))) {
|
||||||
warn_deprecated_option(var->name, deprecation_msg);
|
warn_deprecated_option(var->member.name, deprecation_msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!strlen(c->value)) {
|
if (!strlen(c->value)) {
|
||||||
/* reset or clear it, then return */
|
/* reset or clear it, then return */
|
||||||
if (!clear_first) {
|
if (!clear_first) {
|
||||||
if ((var->type == CONFIG_TYPE_LINELIST ||
|
if ((var->member.type == CONFIG_TYPE_LINELIST ||
|
||||||
var->type == CONFIG_TYPE_LINELIST_S) &&
|
var->member.type == CONFIG_TYPE_LINELIST_S) &&
|
||||||
c->command != CONFIG_LINE_CLEAR) {
|
c->command != CONFIG_LINE_CLEAR) {
|
||||||
/* We got an empty linelist from the torrc or command line.
|
/* We got an empty linelist from the torrc or command line.
|
||||||
As a special case, call this an error. Warn and ignore. */
|
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
|
config_reset(fmt, options, var, use_defaults); // LCOV_EXCL_LINE
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options_seen && (var->type != CONFIG_TYPE_LINELIST &&
|
if (options_seen && (var->member.type != CONFIG_TYPE_LINELIST &&
|
||||||
var->type != CONFIG_TYPE_LINELIST_S)) {
|
var->member.type != CONFIG_TYPE_LINELIST_S)) {
|
||||||
/* We're tracking which options we've seen, and this option is not
|
/* We're tracking which options we've seen, and this option is not
|
||||||
* supposed to occur more than once. */
|
* supposed to occur more than once. */
|
||||||
int var_index = (int)(var - fmt->vars);
|
int var_index = (int)(var - fmt->vars);
|
||||||
if (bitarray_is_set(options_seen, var_index)) {
|
if (bitarray_is_set(options_seen, var_index)) {
|
||||||
log_warn(LD_CONFIG, "Option '%s' used more than once; all but the last "
|
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);
|
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 char *key, int escape_val)
|
||||||
{
|
{
|
||||||
const config_var_t *var;
|
const config_var_t *var;
|
||||||
const void *value;
|
|
||||||
config_line_t *result;
|
config_line_t *result;
|
||||||
tor_assert(options && key);
|
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);
|
log_warn(LD_CONFIG, "Unknown option '%s'. Failing.", key);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
value = STRUCT_VAR_P(options, var->var_offset);
|
|
||||||
|
|
||||||
if (var->type == CONFIG_TYPE_ROUTERSET) {
|
result = struct_var_kvencode(options, &var->member);
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (escape_val) {
|
if (escape_val) {
|
||||||
config_line_t *line;
|
config_line_t *line;
|
||||||
@ -509,19 +479,10 @@ static void
|
|||||||
config_clear(const config_format_t *fmt, void *options,
|
config_clear(const config_format_t *fmt, void *options,
|
||||||
const config_var_t *var)
|
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);
|
(void)fmt; /* unused */
|
||||||
|
|
||||||
|
struct_var_free(options, &var->member);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Clear the option indexed by <b>var</b> in <b>options</b>. Then if
|
/** 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 */
|
return; /* all done */
|
||||||
if (var->initvalue) {
|
if (var->initvalue) {
|
||||||
c = tor_malloc_zero(sizeof(config_line_t));
|
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);
|
c->value = tor_strdup(var->initvalue);
|
||||||
if (config_assign_value(fmt, options, c, &msg) < 0) {
|
if (config_assign_value(fmt, options, c, &msg) < 0) {
|
||||||
// LCOV_EXCL_START
|
// LCOV_EXCL_START
|
||||||
@ -562,10 +523,11 @@ config_free_(const config_format_t *fmt, void *options)
|
|||||||
|
|
||||||
tor_assert(fmt);
|
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]));
|
config_clear(fmt, options, &(fmt->vars[i]));
|
||||||
|
|
||||||
if (fmt->extra) {
|
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);
|
config_free_lines(*linep);
|
||||||
*linep = NULL;
|
*linep = NULL;
|
||||||
}
|
}
|
||||||
@ -580,17 +542,15 @@ config_is_same(const config_format_t *fmt,
|
|||||||
const void *o1, const void *o2,
|
const void *o1, const void *o2,
|
||||||
const char *name)
|
const char *name)
|
||||||
{
|
{
|
||||||
config_line_t *c1, *c2;
|
|
||||||
int r = 1;
|
|
||||||
CONFIG_CHECK(fmt, o1);
|
CONFIG_CHECK(fmt, o1);
|
||||||
CONFIG_CHECK(fmt, o2);
|
CONFIG_CHECK(fmt, o2);
|
||||||
|
|
||||||
c1 = config_get_assigned_option(fmt, o1, name, 0);
|
const config_var_t *var = config_find_option(fmt, name);
|
||||||
c2 = config_get_assigned_option(fmt, o2, name, 0);
|
if (!var) {
|
||||||
r = config_lines_eq(c1, c2);
|
return true;
|
||||||
config_free_lines(c1);
|
}
|
||||||
config_free_lines(c2);
|
|
||||||
return r;
|
return struct_var_eq(o1, o2, &var->member);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Copy storage held by <b>old</b> into a new or_options_t and return it. */
|
/** Copy storage held by <b>old</b> into a new or_options_t and return it. */
|
||||||
@ -599,28 +559,21 @@ config_dup(const config_format_t *fmt, const void *old)
|
|||||||
{
|
{
|
||||||
void *newopts;
|
void *newopts;
|
||||||
int i;
|
int i;
|
||||||
config_line_t *line;
|
|
||||||
|
|
||||||
newopts = config_new(fmt);
|
newopts = config_new(fmt);
|
||||||
for (i=0; fmt->vars[i].name; ++i) {
|
for (i=0; fmt->vars[i].member.name; ++i) {
|
||||||
if (fmt->vars[i].type == CONFIG_TYPE_LINELIST_S)
|
if (fmt->vars[i].member.type == CONFIG_TYPE_LINELIST_S)
|
||||||
continue;
|
continue;
|
||||||
if (fmt->vars[i].type == CONFIG_TYPE_OBSOLETE)
|
if (fmt->vars[i].member.type == CONFIG_TYPE_OBSOLETE)
|
||||||
continue;
|
continue;
|
||||||
line = config_get_assigned_option(fmt, old, fmt->vars[i].name, 0);
|
if (struct_var_copy(newopts, old, &fmt->vars[i].member) < 0) {
|
||||||
if (line) {
|
|
||||||
char *msg = NULL;
|
|
||||||
if (config_assign(fmt, newopts, line, 0, &msg) < 0) {
|
|
||||||
// LCOV_EXCL_START
|
// LCOV_EXCL_START
|
||||||
log_err(LD_BUG, "config_get_assigned_option() generated "
|
log_err(LD_BUG, "Unable to copy value for %s.",
|
||||||
"something we couldn't config_assign(): %s", msg);
|
fmt->vars[i].member.name);
|
||||||
tor_free(msg);
|
tor_assert_unreached();
|
||||||
tor_assert(0);
|
|
||||||
// LCOV_EXCL_STOP
|
// LCOV_EXCL_STOP
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
config_free_lines(line);
|
|
||||||
}
|
|
||||||
return newopts;
|
return newopts;
|
||||||
}
|
}
|
||||||
/** Set all vars in the configuration object <b>options</b> to their default
|
/** Set all vars in the configuration object <b>options</b> to their default
|
||||||
@ -632,7 +585,7 @@ config_init(const config_format_t *fmt, void *options)
|
|||||||
const config_var_t *var;
|
const config_var_t *var;
|
||||||
CONFIG_CHECK(fmt, options);
|
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];
|
var = &fmt->vars[i];
|
||||||
if (!var->initvalue)
|
if (!var->initvalue)
|
||||||
continue; /* defaults to NULL or 0 */
|
continue; /* defaults to NULL or 0 */
|
||||||
@ -674,22 +627,23 @@ config_dump(const config_format_t *fmt, const void *default_options,
|
|||||||
}
|
}
|
||||||
|
|
||||||
elements = smartlist_new();
|
elements = smartlist_new();
|
||||||
for (i=0; fmt->vars[i].name; ++i) {
|
for (i=0; fmt->vars[i].member.name; ++i) {
|
||||||
int comment_option = 0;
|
int comment_option = 0;
|
||||||
if (fmt->vars[i].type == CONFIG_TYPE_OBSOLETE ||
|
if (fmt->vars[i].member.type == CONFIG_TYPE_OBSOLETE ||
|
||||||
fmt->vars[i].type == CONFIG_TYPE_LINELIST_S)
|
fmt->vars[i].member.type == CONFIG_TYPE_LINELIST_S)
|
||||||
continue;
|
continue;
|
||||||
/* Don't save 'hidden' control variables. */
|
/* Don't save 'hidden' control variables. */
|
||||||
if (!strcmpstart(fmt->vars[i].name, "__"))
|
if (!strcmpstart(fmt->vars[i].member.name, "__"))
|
||||||
continue;
|
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))
|
||||||
continue;
|
continue;
|
||||||
else if (comment_defaults &&
|
else if (comment_defaults &&
|
||||||
config_is_same(fmt, options, defaults, fmt->vars[i].name))
|
config_is_same(fmt, options, defaults, fmt->vars[i].member.name))
|
||||||
comment_option = 1;
|
comment_option = 1;
|
||||||
|
|
||||||
line = assigned =
|
line = assigned =
|
||||||
config_get_assigned_option(fmt, options, fmt->vars[i].name, 1);
|
config_get_assigned_option(fmt, options, fmt->vars[i].member.name, 1);
|
||||||
|
|
||||||
for (; line; line = line->next) {
|
for (; line; line = line->next) {
|
||||||
if (!strcmpstart(line->key, "__")) {
|
if (!strcmpstart(line->key, "__")) {
|
||||||
@ -705,7 +659,7 @@ config_dump(const config_format_t *fmt, const void *default_options,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (fmt->extra) {
|
if (fmt->extra) {
|
||||||
line = *(config_line_t**)STRUCT_VAR_P(options, fmt->extra->var_offset);
|
line = *(config_line_t**)STRUCT_VAR_P(options, fmt->extra->offset);
|
||||||
for (; line; line = line->next) {
|
for (; line; line = line->next) {
|
||||||
smartlist_add_asprintf(elements, "%s %s\n", line->key, line->value);
|
smartlist_add_asprintf(elements, "%s %s\n", line->key, line->value);
|
||||||
}
|
}
|
||||||
@ -719,3 +673,21 @@ config_dump(const config_format_t *fmt, const void *default_options,
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if every member of <b>options</b> is in-range and well-formed.
|
||||||
|
* Return false otherwise. Log errors at level <b>severity</b>.
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
config_check_ok(const config_format_t *fmt, const void *options, int severity)
|
||||||
|
{
|
||||||
|
bool all_ok = true;
|
||||||
|
for (int i=0; fmt->vars[i].member.name; ++i) {
|
||||||
|
if (!struct_var_ok(options, &fmt->vars[i].member)) {
|
||||||
|
log_fn(severity, LD_BUG, "Invalid value for %s",
|
||||||
|
fmt->vars[i].member.name);
|
||||||
|
all_ok = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return all_ok;
|
||||||
|
}
|
||||||
|
@ -34,10 +34,8 @@ typedef struct config_deprecation_t {
|
|||||||
|
|
||||||
/** A variable allowed in the configuration file or on the command line. */
|
/** A variable allowed in the configuration file or on the command line. */
|
||||||
typedef struct config_var_t {
|
typedef struct config_var_t {
|
||||||
const char *name; /**< The full keyword (case insensitive). */
|
struct_member_t member; /** A struct member corresponding to this
|
||||||
config_type_t type; /**< How to interpret the type and turn it into a
|
* variable. */
|
||||||
* value. */
|
|
||||||
off_t var_offset; /**< Offset of the corresponding member of or_options_t. */
|
|
||||||
const char *initvalue; /**< String (or null) describing initial value. */
|
const char *initvalue; /**< String (or null) describing initial value. */
|
||||||
|
|
||||||
#ifdef TOR_UNIT_TESTS
|
#ifdef TOR_UNIT_TESTS
|
||||||
@ -74,12 +72,12 @@ typedef struct config_var_t {
|
|||||||
#define CONF_TEST_MEMBERS(tp, conftype, member) \
|
#define CONF_TEST_MEMBERS(tp, conftype, member) \
|
||||||
, CONF_CHECK_VAR_TYPE(tp, conftype, member)
|
, CONF_CHECK_VAR_TYPE(tp, conftype, member)
|
||||||
#define END_OF_CONFIG_VARS \
|
#define END_OF_CONFIG_VARS \
|
||||||
{ NULL, CONFIG_TYPE_OBSOLETE, 0, NULL, { .INT=NULL } }
|
{ { .name = NULL }, NULL, { .INT=NULL } }
|
||||||
#define DUMMY_TYPECHECK_INSTANCE(tp) \
|
#define DUMMY_TYPECHECK_INSTANCE(tp) \
|
||||||
static tp tp ## _dummy
|
static tp tp ## _dummy
|
||||||
#else /* !(defined(TOR_UNIT_TESTS)) */
|
#else /* !(defined(TOR_UNIT_TESTS)) */
|
||||||
#define CONF_TEST_MEMBERS(tp, conftype, member)
|
#define CONF_TEST_MEMBERS(tp, conftype, member)
|
||||||
#define END_OF_CONFIG_VARS { NULL, CONFIG_TYPE_OBSOLETE, 0, NULL }
|
#define END_OF_CONFIG_VARS { { .name = NULL, }, NULL }
|
||||||
/* Repeatedly declarable incomplete struct to absorb redundant semicolons */
|
/* Repeatedly declarable incomplete struct to absorb redundant semicolons */
|
||||||
#define DUMMY_TYPECHECK_INSTANCE(tp) \
|
#define DUMMY_TYPECHECK_INSTANCE(tp) \
|
||||||
struct tor_semicolon_eater
|
struct tor_semicolon_eater
|
||||||
@ -98,9 +96,7 @@ typedef void (*free_cfg_fn_t)(void*);
|
|||||||
* configuration or storage format. */
|
* configuration or storage format. */
|
||||||
typedef struct config_format_t {
|
typedef struct config_format_t {
|
||||||
size_t size; /**< Size of the struct that everything gets parsed into. */
|
size_t size; /**< Size of the struct that everything gets parsed into. */
|
||||||
uint32_t magic; /**< Required 'magic value' to make sure we have a struct
|
struct_magic_decl_t magic; /**< Magic number info for this struct. */
|
||||||
* of the right type. */
|
|
||||||
off_t magic_offset; /**< Offset of the magic value within the struct. */
|
|
||||||
config_abbrev_t *abbrevs; /**< List of abbreviations that we expand when
|
config_abbrev_t *abbrevs; /**< List of abbreviations that we expand when
|
||||||
* parsing this format. */
|
* parsing this format. */
|
||||||
const config_deprecation_t *deprecations; /** List of deprecated options */
|
const config_deprecation_t *deprecations; /** List of deprecated options */
|
||||||
@ -108,17 +104,16 @@ typedef struct config_format_t {
|
|||||||
* values, and where we stick them in the structure. */
|
* values, and where we stick them in the structure. */
|
||||||
validate_fn_t validate_fn; /**< Function to validate config. */
|
validate_fn_t validate_fn; /**< Function to validate config. */
|
||||||
free_cfg_fn_t free_fn; /**< Function to free the configuration. */
|
free_cfg_fn_t free_fn; /**< Function to free the configuration. */
|
||||||
/** If present, extra is a LINELIST variable for unrecognized
|
/** If present, extra denotes a LINELIST variable for unrecognized
|
||||||
* lines. Otherwise, unrecognized lines are an error. */
|
* lines. Otherwise, unrecognized lines are an error. */
|
||||||
config_var_t *extra;
|
struct_member_t *extra;
|
||||||
} config_format_t;
|
} config_format_t;
|
||||||
|
|
||||||
/** Macro: assert that <b>cfg</b> has the right magic field for format
|
/** Macro: assert that <b>cfg</b> has the right magic field for format
|
||||||
* <b>fmt</b>. */
|
* <b>fmt</b>. */
|
||||||
#define CONFIG_CHECK(fmt, cfg) STMT_BEGIN \
|
#define CONFIG_CHECK(fmt, cfg) STMT_BEGIN \
|
||||||
tor_assert(fmt && cfg); \
|
tor_assert(fmt); \
|
||||||
tor_assert((fmt)->magic == \
|
struct_check_magic((cfg), &fmt->magic); \
|
||||||
*(uint32_t*)STRUCT_VAR_P(cfg,fmt->magic_offset)); \
|
|
||||||
STMT_END
|
STMT_END
|
||||||
|
|
||||||
#define CAL_USE_DEFAULTS (1u<<0)
|
#define CAL_USE_DEFAULTS (1u<<0)
|
||||||
@ -143,6 +138,8 @@ void *config_dup(const config_format_t *fmt, const void *old);
|
|||||||
char *config_dump(const config_format_t *fmt, const void *default_options,
|
char *config_dump(const config_format_t *fmt, const void *default_options,
|
||||||
const void *options, int minimal,
|
const void *options, int minimal,
|
||||||
int comment_defaults);
|
int comment_defaults);
|
||||||
|
bool config_check_ok(const config_format_t *fmt, const void *options,
|
||||||
|
int severity);
|
||||||
int config_assign(const config_format_t *fmt, void *options,
|
int config_assign(const config_format_t *fmt, void *options,
|
||||||
struct config_line_t *list,
|
struct config_line_t *list,
|
||||||
unsigned flags, char **msg);
|
unsigned flags, char **msg);
|
||||||
|
@ -71,8 +71,10 @@ static config_abbrev_t state_abbrevs_[] = {
|
|||||||
DUMMY_TYPECHECK_INSTANCE(or_state_t);
|
DUMMY_TYPECHECK_INSTANCE(or_state_t);
|
||||||
|
|
||||||
/*XXXX these next two are duplicates or near-duplicates from config.c */
|
/*XXXX these next two are duplicates or near-duplicates from config.c */
|
||||||
#define VAR(name,conftype,member,initvalue) \
|
#define VAR(varname,conftype,member,initvalue) \
|
||||||
{ name, CONFIG_TYPE_ ## conftype, offsetof(or_state_t, member), \
|
{ { .name = varname, \
|
||||||
|
.type = CONFIG_TYPE_ ## conftype, \
|
||||||
|
.offset = offsetof(or_state_t, member), }, \
|
||||||
initvalue CONF_TEST_MEMBERS(or_state_t, conftype, member) }
|
initvalue CONF_TEST_MEMBERS(or_state_t, conftype, member) }
|
||||||
/** As VAR, but the option name and member name are the same. */
|
/** As VAR, but the option name and member name are the same. */
|
||||||
#define V(member,conftype,initvalue) \
|
#define V(member,conftype,initvalue) \
|
||||||
@ -155,16 +157,20 @@ static void or_state_free_cb(void *state);
|
|||||||
|
|
||||||
/** "Extra" variable in the state that receives lines we can't parse. This
|
/** "Extra" variable in the state that receives lines we can't parse. This
|
||||||
* lets us preserve options from versions of Tor newer than us. */
|
* lets us preserve options from versions of Tor newer than us. */
|
||||||
static config_var_t state_extra_var = {
|
static struct_member_t state_extra_var = {
|
||||||
"__extra", CONFIG_TYPE_LINELIST, offsetof(or_state_t, ExtraLines), NULL
|
.name = "__extra",
|
||||||
CONF_TEST_MEMBERS(or_state_t, LINELIST, ExtraLines)
|
.type = CONFIG_TYPE_LINELIST,
|
||||||
|
.offset = offsetof(or_state_t, ExtraLines),
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Configuration format for or_state_t. */
|
/** Configuration format for or_state_t. */
|
||||||
static const config_format_t state_format = {
|
static const config_format_t state_format = {
|
||||||
sizeof(or_state_t),
|
sizeof(or_state_t),
|
||||||
|
{
|
||||||
|
"or_state_t",
|
||||||
OR_STATE_MAGIC,
|
OR_STATE_MAGIC,
|
||||||
offsetof(or_state_t, magic_),
|
offsetof(or_state_t, magic_),
|
||||||
|
},
|
||||||
state_abbrevs_,
|
state_abbrevs_,
|
||||||
NULL,
|
NULL,
|
||||||
state_vars_,
|
state_vars_,
|
||||||
|
@ -52,8 +52,10 @@ static const char dstate_cur_srv_key[] = "SharedRandCurrentValue";
|
|||||||
DUMMY_TYPECHECK_INSTANCE(sr_disk_state_t);
|
DUMMY_TYPECHECK_INSTANCE(sr_disk_state_t);
|
||||||
|
|
||||||
/* These next two are duplicates or near-duplicates from config.c */
|
/* These next two are duplicates or near-duplicates from config.c */
|
||||||
#define VAR(name, conftype, member, initvalue) \
|
#define VAR(varname, conftype, member, initvalue) \
|
||||||
{ name, CONFIG_TYPE_ ## conftype, offsetof(sr_disk_state_t, member), \
|
{ { .name = varname, \
|
||||||
|
.type = CONFIG_TYPE_ ## conftype, \
|
||||||
|
.offset = offsetof(sr_disk_state_t, member), }, \
|
||||||
initvalue CONF_TEST_MEMBERS(sr_disk_state_t, conftype, member) }
|
initvalue CONF_TEST_MEMBERS(sr_disk_state_t, conftype, member) }
|
||||||
/* As VAR, but the option name and member name are the same. */
|
/* As VAR, but the option name and member name are the same. */
|
||||||
#define V(member, conftype, initvalue) \
|
#define V(member, conftype, initvalue) \
|
||||||
@ -83,17 +85,20 @@ static config_var_t state_vars[] = {
|
|||||||
|
|
||||||
/* "Extra" variable in the state that receives lines we can't parse. This
|
/* "Extra" variable in the state that receives lines we can't parse. This
|
||||||
* lets us preserve options from versions of Tor newer than us. */
|
* lets us preserve options from versions of Tor newer than us. */
|
||||||
static config_var_t state_extra_var = {
|
static struct_member_t state_extra_var = {
|
||||||
"__extra", CONFIG_TYPE_LINELIST,
|
.name = "__extra",
|
||||||
offsetof(sr_disk_state_t, ExtraLines), NULL
|
.type = CONFIG_TYPE_LINELIST,
|
||||||
CONF_TEST_MEMBERS(sr_disk_state_t, LINELIST, ExtraLines)
|
.offset = offsetof(sr_disk_state_t, ExtraLines),
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Configuration format of sr_disk_state_t. */
|
/* Configuration format of sr_disk_state_t. */
|
||||||
static const config_format_t state_format = {
|
static const config_format_t state_format = {
|
||||||
sizeof(sr_disk_state_t),
|
sizeof(sr_disk_state_t),
|
||||||
|
{
|
||||||
|
"sr_disk_state_t",
|
||||||
SR_DISK_STATE_MAGIC,
|
SR_DISK_STATE_MAGIC,
|
||||||
offsetof(sr_disk_state_t, magic_),
|
offsetof(sr_disk_state_t, magic_),
|
||||||
|
},
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
state_vars,
|
state_vars,
|
||||||
|
@ -34,6 +34,9 @@ n * Copyright (c) 2001-2004, Roger Dingledine.
|
|||||||
#include "feature/nodelist/nickname.h"
|
#include "feature/nodelist/nickname.h"
|
||||||
#include "feature/nodelist/nodelist.h"
|
#include "feature/nodelist/nodelist.h"
|
||||||
#include "feature/nodelist/routerset.h"
|
#include "feature/nodelist/routerset.h"
|
||||||
|
#include "lib/conf/conftypes.h"
|
||||||
|
#include "lib/confmgt/typedvar.h"
|
||||||
|
#include "lib/encoding/confline.h"
|
||||||
#include "lib/geoip/geoip.h"
|
#include "lib/geoip/geoip.h"
|
||||||
|
|
||||||
#include "core/or/addr_policy_st.h"
|
#include "core/or/addr_policy_st.h"
|
||||||
@ -41,6 +44,7 @@ n * Copyright (c) 2001-2004, Roger Dingledine.
|
|||||||
#include "feature/nodelist/node_st.h"
|
#include "feature/nodelist/node_st.h"
|
||||||
#include "feature/nodelist/routerinfo_st.h"
|
#include "feature/nodelist/routerinfo_st.h"
|
||||||
#include "feature/nodelist/routerstatus_st.h"
|
#include "feature/nodelist/routerstatus_st.h"
|
||||||
|
#include "lib/confmgt/var_type_def_st.h"
|
||||||
|
|
||||||
/** Return a new empty routerset. */
|
/** Return a new empty routerset. */
|
||||||
routerset_t *
|
routerset_t *
|
||||||
@ -461,3 +465,61 @@ routerset_free_(routerset_t *routerset)
|
|||||||
bitarray_free(routerset->countries);
|
bitarray_free(routerset->countries);
|
||||||
tor_free(routerset);
|
tor_free(routerset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
routerset_kv_parse(void *target, const config_line_t *line, char **errmsg,
|
||||||
|
const void *params)
|
||||||
|
{
|
||||||
|
(void)params;
|
||||||
|
routerset_t **p = (routerset_t**)target;
|
||||||
|
routerset_free(*p); // clear the old value, if any.
|
||||||
|
routerset_t *rs = routerset_new();
|
||||||
|
if (routerset_parse(rs, line->value, line->key) < 0) {
|
||||||
|
routerset_free(rs);
|
||||||
|
*errmsg = tor_strdup("Invalid router list.");
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
*p = rs;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
routerset_encode(const void *value, const void *params)
|
||||||
|
{
|
||||||
|
(void)params;
|
||||||
|
const routerset_t **p = (const routerset_t**)value;
|
||||||
|
return routerset_to_string(*p);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
routerset_clear(void *value, const void *params)
|
||||||
|
{
|
||||||
|
(void)params;
|
||||||
|
routerset_t **p = (routerset_t**)value;
|
||||||
|
routerset_free(*p); // sets *p to NULL.
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
routerset_copy(void *dest, const void *src, const void *params)
|
||||||
|
{
|
||||||
|
(void)params;
|
||||||
|
routerset_t **output = (routerset_t**)dest;
|
||||||
|
const routerset_t *input = *(routerset_t**)src;
|
||||||
|
routerset_free(*output); // sets *output to NULL
|
||||||
|
*output = routerset_new();
|
||||||
|
routerset_union(*output, input);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const var_type_fns_t routerset_type_fns = {
|
||||||
|
.kv_parse = routerset_kv_parse,
|
||||||
|
.encode = routerset_encode,
|
||||||
|
.clear = routerset_clear,
|
||||||
|
.copy = routerset_copy
|
||||||
|
};
|
||||||
|
|
||||||
|
const var_type_def_t ROUTERSET_type_defn = {
|
||||||
|
.name = "RouterList",
|
||||||
|
.fns = &routerset_type_fns
|
||||||
|
};
|
||||||
|
@ -44,6 +44,9 @@ void routerset_free_(routerset_t *routerset);
|
|||||||
#define routerset_free(rs) FREE_AND_NULL(routerset_t, routerset_free_, (rs))
|
#define routerset_free(rs) FREE_AND_NULL(routerset_t, routerset_free_, (rs))
|
||||||
int routerset_len(const routerset_t *set);
|
int routerset_len(const routerset_t *set);
|
||||||
|
|
||||||
|
struct var_type_def_t;
|
||||||
|
extern const struct var_type_def_t ROUTERSET_type_defn;
|
||||||
|
|
||||||
#ifdef ROUTERSET_PRIVATE
|
#ifdef ROUTERSET_PRIVATE
|
||||||
#include "lib/container/bitarray.h"
|
#include "lib/container/bitarray.h"
|
||||||
|
|
||||||
|
@ -63,8 +63,48 @@ typedef enum config_type_t {
|
|||||||
CONFIG_TYPE_ROUTERSET, /**< A list of router names, addrs, and fps,
|
CONFIG_TYPE_ROUTERSET, /**< A list of router names, addrs, and fps,
|
||||||
* parsed into a routerset_t. */
|
* parsed into a routerset_t. */
|
||||||
CONFIG_TYPE_OBSOLETE, /**< Obsolete (ignored) option. */
|
CONFIG_TYPE_OBSOLETE, /**< Obsolete (ignored) option. */
|
||||||
|
CONFIG_TYPE_EXTENDED, /**< Extended type; definition will appear in
|
||||||
|
* pointer. */
|
||||||
} config_type_t;
|
} config_type_t;
|
||||||
|
|
||||||
|
/* Forward delcaration for var_type_def_t, for extended types. */
|
||||||
|
struct var_type_def_t;
|
||||||
|
|
||||||
|
/** Structure to specify a named, typed member within a structure. */
|
||||||
|
typedef struct struct_member_t {
|
||||||
|
/** Name of the field. */
|
||||||
|
const char *name;
|
||||||
|
/** Type of the field, according to the config_type_t enumeration.
|
||||||
|
*
|
||||||
|
* This value is CONFIG_TYPE_EXTENDED for any type not listed in
|
||||||
|
* config_type_t.
|
||||||
|
**/
|
||||||
|
config_type_t type;
|
||||||
|
/**
|
||||||
|
* Pointer to a type definition for the type of this field. Overrides
|
||||||
|
* <b>type</b> if not NULL.
|
||||||
|
**/
|
||||||
|
const struct var_type_def_t *type_def;
|
||||||
|
/**
|
||||||
|
* Offset of this field within the structure. Compute this with
|
||||||
|
* offsetof(structure, fieldname).
|
||||||
|
**/
|
||||||
|
int offset;
|
||||||
|
} struct_member_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Structure to describe the location and preferred value of a "magic number"
|
||||||
|
* field within a structure.
|
||||||
|
*
|
||||||
|
* These 'magic numbers' are 32-bit values used to tag objects to make sure
|
||||||
|
* that they have the correct type.
|
||||||
|
*/
|
||||||
|
typedef struct struct_magic_decl_t {
|
||||||
|
const char *typename;
|
||||||
|
uint32_t magic_val;
|
||||||
|
int magic_offset;
|
||||||
|
} struct_magic_decl_t;
|
||||||
|
|
||||||
#ifdef TOR_UNIT_TESTS
|
#ifdef TOR_UNIT_TESTS
|
||||||
/**
|
/**
|
||||||
* Union used when building in test mode typechecking the members of a type
|
* Union used when building in test mode typechecking the members of a type
|
||||||
|
@ -6,6 +6,7 @@ endif
|
|||||||
|
|
||||||
# ADD_C_FILE: INSERT SOURCES HERE.
|
# ADD_C_FILE: INSERT SOURCES HERE.
|
||||||
src_lib_libtor_confmgt_a_SOURCES = \
|
src_lib_libtor_confmgt_a_SOURCES = \
|
||||||
|
src/lib/confmgt/structvar.c \
|
||||||
src/lib/confmgt/type_defs.c \
|
src/lib/confmgt/type_defs.c \
|
||||||
src/lib/confmgt/typedvar.c \
|
src/lib/confmgt/typedvar.c \
|
||||||
src/lib/confmgt/unitparse.c
|
src/lib/confmgt/unitparse.c
|
||||||
@ -17,6 +18,7 @@ src_lib_libtor_confmgt_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
|
|||||||
|
|
||||||
# ADD_C_FILE: INSERT HEADERS HERE.
|
# ADD_C_FILE: INSERT HEADERS HERE.
|
||||||
noinst_HEADERS += \
|
noinst_HEADERS += \
|
||||||
|
src/lib/confmgt/structvar.h \
|
||||||
src/lib/confmgt/type_defs.h \
|
src/lib/confmgt/type_defs.h \
|
||||||
src/lib/confmgt/typedvar.h \
|
src/lib/confmgt/typedvar.h \
|
||||||
src/lib/confmgt/unitparse.h \
|
src/lib/confmgt/unitparse.h \
|
||||||
|
226
src/lib/confmgt/structvar.c
Normal file
226
src/lib/confmgt/structvar.c
Normal file
@ -0,0 +1,226 @@
|
|||||||
|
/* 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 structvar.c
|
||||||
|
* @brief Functions to manipulate named and typed elements of
|
||||||
|
* a structure.
|
||||||
|
*
|
||||||
|
* These functions represent a low-level API for accessing a member of a
|
||||||
|
* structure. They use typedvar.c to work, and they are used in turn by the
|
||||||
|
* configuration system to examine and set fields in configuration objects
|
||||||
|
* used by individual modules.
|
||||||
|
*
|
||||||
|
* Almost no code should call these directly.
|
||||||
|
**/
|
||||||
|
|
||||||
|
#include "orconfig.h"
|
||||||
|
#include "lib/confmgt/structvar.h"
|
||||||
|
#include "lib/cc/compat_compiler.h"
|
||||||
|
#include "lib/conf/conftypes.h"
|
||||||
|
#include "lib/confmgt/type_defs.h"
|
||||||
|
#include "lib/confmgt/typedvar.h"
|
||||||
|
#include "lib/log/util_bug.h"
|
||||||
|
|
||||||
|
#include "lib/confmgt/var_type_def_st.h"
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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);
|
||||||
|
uint32_t *ptr = STRUCT_VAR_P(object, decl->magic_offset);
|
||||||
|
*ptr = decl->magic_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assert that the 'magic number' on <b>object</b> to corresponds to decl.
|
||||||
|
**/
|
||||||
|
void
|
||||||
|
struct_check_magic(const void *object, const struct_magic_decl_t *decl)
|
||||||
|
{
|
||||||
|
tor_assert(object);
|
||||||
|
tor_assert(decl);
|
||||||
|
|
||||||
|
const uint32_t *ptr = STRUCT_VAR_P(object, decl->magic_offset);
|
||||||
|
tor_assertf(*ptr == decl->magic_val,
|
||||||
|
"Bad magic number on purported %s object. "
|
||||||
|
"Expected %"PRIu32"x but got "PRIu32"x.",
|
||||||
|
decl->magic_val, *ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a mutable pointer to the member of <b>object</b> described
|
||||||
|
* by <b>member</b>.
|
||||||
|
**/
|
||||||
|
void *
|
||||||
|
struct_get_mptr(void *object, const struct_member_t *member)
|
||||||
|
{
|
||||||
|
tor_assert(object);
|
||||||
|
return STRUCT_VAR_P(object, member->offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a const pointer to the member of <b>object</b> described
|
||||||
|
* by <b>member</b>.
|
||||||
|
**/
|
||||||
|
const void *
|
||||||
|
struct_get_ptr(const void *object, const struct_member_t *member)
|
||||||
|
{
|
||||||
|
tor_assert(object);
|
||||||
|
return STRUCT_VAR_P(object, member->offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper: given a struct_member_t, look up the type definition for its
|
||||||
|
* variable.
|
||||||
|
*/
|
||||||
|
static const var_type_def_t *
|
||||||
|
get_type_def(const struct_member_t *member)
|
||||||
|
{
|
||||||
|
if (member->type_def)
|
||||||
|
return member->type_def;
|
||||||
|
|
||||||
|
return lookup_type_def(member->type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (As typed_var_assign, but assign a value to the member of <b>object</b>
|
||||||
|
* defined by <b>member</b>.)
|
||||||
|
**/
|
||||||
|
int
|
||||||
|
struct_var_assign(void *object, const char *value, char **errmsg,
|
||||||
|
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_assign_ex(p, value, errmsg, def);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (As typed_var_free, but free and clear the member of <b>object</b> defined
|
||||||
|
* by <b>member</b>.)
|
||||||
|
**/
|
||||||
|
void
|
||||||
|
struct_var_free(void *object, const struct_member_t *member)
|
||||||
|
{
|
||||||
|
void *p = struct_get_mptr(object, member);
|
||||||
|
const var_type_def_t *def = get_type_def(member);
|
||||||
|
|
||||||
|
typed_var_free_ex(p, def);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (As typed_var_encode, but encode the member of <b>object</b> defined
|
||||||
|
* by <b>member</b>.)
|
||||||
|
**/
|
||||||
|
char *
|
||||||
|
struct_var_encode(const void *object, const struct_member_t *member)
|
||||||
|
{
|
||||||
|
const void *p = struct_get_ptr(object, member);
|
||||||
|
const var_type_def_t *def = get_type_def(member);
|
||||||
|
|
||||||
|
return typed_var_encode_ex(p, def);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (As typed_var_copy, but copy from <b>src</b> to <b>dest</b> the member
|
||||||
|
* defined by <b>member</b>.)
|
||||||
|
**/
|
||||||
|
int
|
||||||
|
struct_var_copy(void *dest, const void *src, const struct_member_t *member)
|
||||||
|
{
|
||||||
|
void *p_dest = struct_get_mptr(dest, member);
|
||||||
|
const void *p_src = struct_get_ptr(src, member);
|
||||||
|
const var_type_def_t *def = get_type_def(member);
|
||||||
|
|
||||||
|
return typed_var_copy_ex(p_dest, p_src, def);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (As typed_var_eq, but compare the members of <b>a</b> and <b>b</b>
|
||||||
|
* defined by <b>member</b>.)
|
||||||
|
**/
|
||||||
|
bool
|
||||||
|
struct_var_eq(const void *a, const void *b, const struct_member_t *member)
|
||||||
|
{
|
||||||
|
const void *p_a = struct_get_ptr(a, member);
|
||||||
|
const void *p_b = struct_get_ptr(b, member);
|
||||||
|
const var_type_def_t *def = get_type_def(member);
|
||||||
|
|
||||||
|
return typed_var_eq_ex(p_a, p_b, def);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (As typed_var_ok, but validate the member of <b>object</b> defined by
|
||||||
|
* <b>member</b>.)
|
||||||
|
**/
|
||||||
|
bool
|
||||||
|
struct_var_ok(const void *object, const struct_member_t *member)
|
||||||
|
{
|
||||||
|
const void *p = struct_get_ptr(object, member);
|
||||||
|
const var_type_def_t *def = get_type_def(member);
|
||||||
|
|
||||||
|
return typed_var_ok_ex(p, def);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (As typed_var_kvassign, but assign a value to the member of <b>object</b>
|
||||||
|
* defined by <b>member</b>.)
|
||||||
|
**/
|
||||||
|
int
|
||||||
|
struct_var_kvassign(void *object, const struct config_line_t *line,
|
||||||
|
char **errmsg,
|
||||||
|
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_kvassign_ex(p, line, errmsg, def);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (As typed_var_kvencode, but encode the value of the member of <b>object</b>
|
||||||
|
* defined by <b>member</b>.)
|
||||||
|
**/
|
||||||
|
struct config_line_t *
|
||||||
|
struct_var_kvencode(const void *object, const struct_member_t *member)
|
||||||
|
{
|
||||||
|
const void *p = struct_get_ptr(object, member);
|
||||||
|
const var_type_def_t *def = get_type_def(member);
|
||||||
|
|
||||||
|
return typed_var_kvencode_ex(member->name, p, def);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the official name of this struct member.
|
||||||
|
**/
|
||||||
|
const char *
|
||||||
|
struct_var_get_name(const struct_member_t *member)
|
||||||
|
{
|
||||||
|
return member->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the type name for this struct member.
|
||||||
|
*
|
||||||
|
* Do not use the output of this function to inspect a type within Tor. It is
|
||||||
|
* suitable for debugging, informing the controller or user of a variable's
|
||||||
|
* type, etc.
|
||||||
|
**/
|
||||||
|
const char *
|
||||||
|
struct_var_get_typename(const struct_member_t *member)
|
||||||
|
{
|
||||||
|
const var_type_def_t *def = get_type_def(member);
|
||||||
|
|
||||||
|
return def ? def->name : NULL;
|
||||||
|
}
|
54
src/lib/confmgt/structvar.h
Normal file
54
src/lib/confmgt/structvar.h
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
/* 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 structvar.h
|
||||||
|
* @brief Header for lib/confmgt/structvar.c
|
||||||
|
**/
|
||||||
|
|
||||||
|
#ifndef TOR_LIB_CONFMGT_STRUCTVAR_H
|
||||||
|
#define TOR_LIB_CONFMGT_STRUCTVAR_H
|
||||||
|
|
||||||
|
struct struct_magic_decl_t;
|
||||||
|
struct struct_member_t;
|
||||||
|
struct config_line_t;
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
void struct_set_magic(void *object,
|
||||||
|
const struct struct_magic_decl_t *decl);
|
||||||
|
void struct_check_magic(const void *object,
|
||||||
|
const struct struct_magic_decl_t *decl);
|
||||||
|
|
||||||
|
void *struct_get_mptr(void *object,
|
||||||
|
const struct struct_member_t *member);
|
||||||
|
const void *struct_get_ptr(const void *object,
|
||||||
|
const struct struct_member_t *member);
|
||||||
|
|
||||||
|
int struct_var_assign(void *object, const char *value, char **errmsg,
|
||||||
|
const struct struct_member_t *member);
|
||||||
|
void struct_var_free(void *object,
|
||||||
|
const struct struct_member_t *member);
|
||||||
|
char *struct_var_encode(const void *object,
|
||||||
|
const struct struct_member_t *member);
|
||||||
|
int struct_var_copy(void *dest, const void *src,
|
||||||
|
const struct struct_member_t *member);
|
||||||
|
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);
|
||||||
|
|
||||||
|
const char *struct_var_get_name(const struct struct_member_t *member);
|
||||||
|
const char *struct_var_get_typename(const struct struct_member_t *member);
|
||||||
|
|
||||||
|
int struct_var_kvassign(void *object, const struct config_line_t *line,
|
||||||
|
char **errmsg,
|
||||||
|
const struct struct_member_t *member);
|
||||||
|
struct config_line_t *struct_var_kvencode(
|
||||||
|
const void *object,
|
||||||
|
const struct struct_member_t *member);
|
||||||
|
|
||||||
|
#endif /* !defined(TOR_LIB_CONFMGT_STRUCTVAR_H) */
|
@ -44,7 +44,7 @@ typed_var_assign_ex(void *target, const char *value, char **errmsg,
|
|||||||
const var_type_def_t *def)
|
const var_type_def_t *def)
|
||||||
{
|
{
|
||||||
if (BUG(!def))
|
if (BUG(!def))
|
||||||
return -1;
|
return -1; // LCOV_EXCL_LINE
|
||||||
// clear old value if needed.
|
// clear old value if needed.
|
||||||
typed_var_free_ex(target, def);
|
typed_var_free_ex(target, def);
|
||||||
|
|
||||||
@ -67,7 +67,7 @@ typed_var_kvassign_ex(void *target, const config_line_t *line,
|
|||||||
char **errmsg, const var_type_def_t *def)
|
char **errmsg, const var_type_def_t *def)
|
||||||
{
|
{
|
||||||
if (BUG(!def))
|
if (BUG(!def))
|
||||||
return -1;
|
return -1; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
if (def->fns->kv_parse) {
|
if (def->fns->kv_parse) {
|
||||||
// We do _not_ free the old value here, since linelist options
|
// We do _not_ free the old value here, since linelist options
|
||||||
@ -86,7 +86,7 @@ void
|
|||||||
typed_var_free_ex(void *target, const var_type_def_t *def)
|
typed_var_free_ex(void *target, const var_type_def_t *def)
|
||||||
{
|
{
|
||||||
if (BUG(!def))
|
if (BUG(!def))
|
||||||
return;
|
return; // LCOV_EXCL_LINE
|
||||||
if (def->fns->clear) {
|
if (def->fns->clear) {
|
||||||
def->fns->clear(target, def->params);
|
def->fns->clear(target, def->params);
|
||||||
}
|
}
|
||||||
@ -102,7 +102,7 @@ char *
|
|||||||
typed_var_encode_ex(const void *value, const var_type_def_t *def)
|
typed_var_encode_ex(const void *value, const var_type_def_t *def)
|
||||||
{
|
{
|
||||||
if (BUG(!def))
|
if (BUG(!def))
|
||||||
return NULL;
|
return NULL; // LCOV_EXCL_LINE
|
||||||
tor_assert(def->fns->encode);
|
tor_assert(def->fns->encode);
|
||||||
return def->fns->encode(value, def->params);
|
return def->fns->encode(value, def->params);
|
||||||
}
|
}
|
||||||
@ -121,7 +121,7 @@ typed_var_kvencode_ex(const char *key, const void *value,
|
|||||||
const var_type_def_t *def)
|
const var_type_def_t *def)
|
||||||
{
|
{
|
||||||
if (BUG(!def))
|
if (BUG(!def))
|
||||||
return NULL;
|
return NULL; // LCOV_EXCL_LINE
|
||||||
if (def->fns->kv_encode) {
|
if (def->fns->kv_encode) {
|
||||||
return def->fns->kv_encode(key, value, def->params);
|
return def->fns->kv_encode(key, value, def->params);
|
||||||
}
|
}
|
||||||
@ -145,7 +145,7 @@ int
|
|||||||
typed_var_copy_ex(void *dest, const void *src, const var_type_def_t *def)
|
typed_var_copy_ex(void *dest, const void *src, const var_type_def_t *def)
|
||||||
{
|
{
|
||||||
if (BUG(!def))
|
if (BUG(!def))
|
||||||
return -1;
|
return -1; // LCOV_EXCL_LINE
|
||||||
if (def->fns->copy) {
|
if (def->fns->copy) {
|
||||||
// If we have been provided a copy fuction, use it.
|
// If we have been provided a copy fuction, use it.
|
||||||
return def->fns->copy(dest, src, def);
|
return def->fns->copy(dest, src, def);
|
||||||
@ -160,8 +160,10 @@ typed_var_copy_ex(void *dest, const void *src, const var_type_def_t *def)
|
|||||||
char *err = NULL;
|
char *err = NULL;
|
||||||
int rv = typed_var_assign_ex(dest, enc, &err, def);
|
int rv = typed_var_assign_ex(dest, enc, &err, def);
|
||||||
if (BUG(rv < 0)) {
|
if (BUG(rv < 0)) {
|
||||||
|
// LCOV_EXCL_START
|
||||||
log_warn(LD_BUG, "Encoded value %s was not parseable as a %s: %s",
|
log_warn(LD_BUG, "Encoded value %s was not parseable as a %s: %s",
|
||||||
escaped(enc), def->name, err?err:"");
|
escaped(enc), def->name, err?err:"");
|
||||||
|
// LCOV_EXCL_STOP
|
||||||
}
|
}
|
||||||
tor_free(err);
|
tor_free(err);
|
||||||
tor_free(enc);
|
tor_free(enc);
|
||||||
@ -176,7 +178,7 @@ bool
|
|||||||
typed_var_eq_ex(const void *a, const void *b, const var_type_def_t *def)
|
typed_var_eq_ex(const void *a, const void *b, const var_type_def_t *def)
|
||||||
{
|
{
|
||||||
if (BUG(!def))
|
if (BUG(!def))
|
||||||
return false;
|
return false; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
if (def->fns->eq) {
|
if (def->fns->eq) {
|
||||||
// Use a provided eq function if we got one.
|
// Use a provided eq function if we got one.
|
||||||
@ -200,7 +202,7 @@ bool
|
|||||||
typed_var_ok_ex(const void *value, const var_type_def_t *def)
|
typed_var_ok_ex(const void *value, const var_type_def_t *def)
|
||||||
{
|
{
|
||||||
if (BUG(!def))
|
if (BUG(!def))
|
||||||
return false;
|
return false; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
if (def->fns->ok)
|
if (def->fns->ok)
|
||||||
return def->fns->ok(value, def->params);
|
return def->fns->ok(value, def->params);
|
||||||
|
@ -48,15 +48,17 @@ typedef struct test_struct_t {
|
|||||||
|
|
||||||
static test_struct_t test_struct_t_dummy;
|
static test_struct_t test_struct_t_dummy;
|
||||||
|
|
||||||
#define VAR(name,conftype,member,initvalue) \
|
#define VAR(varname,conftype,member,initvalue) \
|
||||||
{ name, CONFIG_TYPE_##conftype, offsetof(test_struct_t, member), \
|
{ { .name = varname, \
|
||||||
|
.type = CONFIG_TYPE_##conftype, \
|
||||||
|
.offset = offsetof(test_struct_t, member), }, \
|
||||||
initvalue CONF_TEST_MEMBERS(test_struct_t, conftype, member) }
|
initvalue CONF_TEST_MEMBERS(test_struct_t, conftype, member) }
|
||||||
|
|
||||||
#define V(name,conftype,initvalue) \
|
#define V(name,conftype,initvalue) \
|
||||||
VAR( #name, conftype, name, initvalue )
|
VAR( #name, conftype, name, initvalue )
|
||||||
|
|
||||||
#define OBSOLETE(name) \
|
#define OBSOLETE(varname) \
|
||||||
{ name, CONFIG_TYPE_OBSOLETE, 0, NULL, {.INT=NULL} }
|
{ { .name=varname, .type=CONFIG_TYPE_OBSOLETE }, NULL, {.INT=NULL} }
|
||||||
|
|
||||||
static config_var_t test_vars[] = {
|
static config_var_t test_vars[] = {
|
||||||
V(s, STRING, "hello"),
|
V(s, STRING, "hello"),
|
||||||
@ -79,7 +81,14 @@ static config_var_t test_vars[] = {
|
|||||||
VAR("LineTypeA", LINELIST_S, mixed_lines, NULL),
|
VAR("LineTypeA", LINELIST_S, mixed_lines, NULL),
|
||||||
VAR("LineTypeB", LINELIST_S, mixed_lines, NULL),
|
VAR("LineTypeB", LINELIST_S, mixed_lines, NULL),
|
||||||
OBSOLETE("obsolete"),
|
OBSOLETE("obsolete"),
|
||||||
V(routerset, ROUTERSET, NULL),
|
{
|
||||||
|
{ .name = "routerset",
|
||||||
|
.type = CONFIG_TYPE_ROUTERSET,
|
||||||
|
.type_def = &ROUTERSET_type_defn,
|
||||||
|
.offset = offsetof(test_struct_t, routerset),
|
||||||
|
},
|
||||||
|
NULL, {.INT=NULL}
|
||||||
|
},
|
||||||
VAR("__HiddenInt", POSINT, hidden_int, "0"),
|
VAR("__HiddenInt", POSINT, hidden_int, "0"),
|
||||||
VAR("MixedHiddenLines", LINELIST_V, mixed_hidden_lines, NULL),
|
VAR("MixedHiddenLines", LINELIST_V, mixed_hidden_lines, NULL),
|
||||||
VAR("__HiddenLineA", LINELIST_S, mixed_hidden_lines, NULL),
|
VAR("__HiddenLineA", LINELIST_S, mixed_hidden_lines, NULL),
|
||||||
@ -122,8 +131,11 @@ static void test_free_cb(void *options);
|
|||||||
|
|
||||||
static config_format_t test_fmt = {
|
static config_format_t test_fmt = {
|
||||||
sizeof(test_struct_t),
|
sizeof(test_struct_t),
|
||||||
|
{
|
||||||
|
"test_struct_t",
|
||||||
TEST_MAGIC,
|
TEST_MAGIC,
|
||||||
offsetof(test_struct_t, magic),
|
offsetof(test_struct_t, magic),
|
||||||
|
},
|
||||||
test_abbrevs,
|
test_abbrevs,
|
||||||
test_deprecation_notes,
|
test_deprecation_notes,
|
||||||
test_vars,
|
test_vars,
|
||||||
@ -278,6 +290,8 @@ test_confparse_assign_simple(void *arg)
|
|||||||
tt_str_op(tst->mixed_hidden_lines->next->value, OP_EQ, "ABC");
|
tt_str_op(tst->mixed_hidden_lines->next->value, OP_EQ, "ABC");
|
||||||
tt_assert(!tst->mixed_hidden_lines->next->next);
|
tt_assert(!tst->mixed_hidden_lines->next->next);
|
||||||
|
|
||||||
|
tt_assert(config_check_ok(&test_fmt, tst, LOG_ERR));
|
||||||
|
|
||||||
done:
|
done:
|
||||||
config_free(&test_fmt, tst);
|
config_free(&test_fmt, tst);
|
||||||
}
|
}
|
||||||
@ -332,6 +346,8 @@ test_confparse_assign_deprecated(void *arg)
|
|||||||
|
|
||||||
tt_int_op(tst->deprecated_int, OP_EQ, 7);
|
tt_int_op(tst->deprecated_int, OP_EQ, 7);
|
||||||
|
|
||||||
|
tt_assert(config_check_ok(&test_fmt, tst, LOG_ERR));
|
||||||
|
|
||||||
done:
|
done:
|
||||||
teardown_capture_of_logs();
|
teardown_capture_of_logs();
|
||||||
config_free(&test_fmt, tst);
|
config_free(&test_fmt, tst);
|
||||||
@ -477,6 +493,8 @@ static const badval_test_t bv_badabool =
|
|||||||
static const badval_test_t bv_badtime = { "time lunchtime\n", "Invalid time" };
|
static const badval_test_t bv_badtime = { "time lunchtime\n", "Invalid time" };
|
||||||
static const badval_test_t bv_virt = { "MixedLines 7\n", "virtual option" };
|
static const badval_test_t bv_virt = { "MixedLines 7\n", "virtual option" };
|
||||||
static const badval_test_t bv_rs = { "Routerset 2.2.2.2.2\n", "Invalid" };
|
static const badval_test_t bv_rs = { "Routerset 2.2.2.2.2\n", "Invalid" };
|
||||||
|
static const badval_test_t bv_big_interval =
|
||||||
|
{ "interval 1000 months", "too large" };
|
||||||
|
|
||||||
/* Try config_dump(), and make sure it behaves correctly */
|
/* Try config_dump(), and make sure it behaves correctly */
|
||||||
static void
|
static void
|
||||||
@ -757,12 +775,19 @@ test_confparse_get_assigned(void *arg)
|
|||||||
/* Another variant, which accepts and stores unrecognized lines.*/
|
/* Another variant, which accepts and stores unrecognized lines.*/
|
||||||
#define ETEST_MAGIC 13371337
|
#define ETEST_MAGIC 13371337
|
||||||
|
|
||||||
static config_var_t extra = VAR("__extra", LINELIST, extra_lines, NULL);
|
static struct_member_t extra = {
|
||||||
|
.name = "__extra",
|
||||||
|
.type = CONFIG_TYPE_LINELIST,
|
||||||
|
.offset = offsetof(test_struct_t, extra_lines),
|
||||||
|
};
|
||||||
|
|
||||||
static config_format_t etest_fmt = {
|
static config_format_t etest_fmt = {
|
||||||
sizeof(test_struct_t),
|
sizeof(test_struct_t),
|
||||||
|
{
|
||||||
|
"test_struct_t (with extra lines)",
|
||||||
ETEST_MAGIC,
|
ETEST_MAGIC,
|
||||||
offsetof(test_struct_t, magic),
|
offsetof(test_struct_t, magic),
|
||||||
|
},
|
||||||
test_abbrevs,
|
test_abbrevs,
|
||||||
test_deprecation_notes,
|
test_deprecation_notes,
|
||||||
test_vars,
|
test_vars,
|
||||||
@ -866,6 +891,18 @@ test_confparse_unitparse(void *args)
|
|||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_confparse_check_ok_fail(void *arg)
|
||||||
|
{
|
||||||
|
(void)arg;
|
||||||
|
test_struct_t *tst = config_new(&test_fmt);
|
||||||
|
tst->pos = -10;
|
||||||
|
tt_assert(! config_check_ok(&test_fmt, tst, LOG_INFO));
|
||||||
|
|
||||||
|
done:
|
||||||
|
config_free(&test_fmt, tst);
|
||||||
|
}
|
||||||
|
|
||||||
#define CONFPARSE_TEST(name, flags) \
|
#define CONFPARSE_TEST(name, flags) \
|
||||||
{ #name, test_confparse_ ## name, flags, NULL, NULL }
|
{ #name, test_confparse_ ## name, flags, NULL, NULL }
|
||||||
|
|
||||||
@ -893,6 +930,7 @@ struct testcase_t confparse_tests[] = {
|
|||||||
BADVAL_TEST(badtime),
|
BADVAL_TEST(badtime),
|
||||||
BADVAL_TEST(virt),
|
BADVAL_TEST(virt),
|
||||||
BADVAL_TEST(rs),
|
BADVAL_TEST(rs),
|
||||||
|
BADVAL_TEST(big_interval),
|
||||||
CONFPARSE_TEST(dump, 0),
|
CONFPARSE_TEST(dump, 0),
|
||||||
CONFPARSE_TEST(reset, 0),
|
CONFPARSE_TEST(reset, 0),
|
||||||
CONFPARSE_TEST(reassign, 0),
|
CONFPARSE_TEST(reassign, 0),
|
||||||
@ -900,5 +938,6 @@ struct testcase_t confparse_tests[] = {
|
|||||||
CONFPARSE_TEST(get_assigned, 0),
|
CONFPARSE_TEST(get_assigned, 0),
|
||||||
CONFPARSE_TEST(extra_lines, 0),
|
CONFPARSE_TEST(extra_lines, 0),
|
||||||
CONFPARSE_TEST(unitparse, 0),
|
CONFPARSE_TEST(unitparse, 0),
|
||||||
|
CONFPARSE_TEST(check_ok_fail, 0),
|
||||||
END_OF_TESTCASES
|
END_OF_TESTCASES
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user