summaryrefslogtreecommitdiff
path: root/src/app/config
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2019-07-19 06:45:54 -0400
committerNick Mathewson <nickm@torproject.org>2019-07-24 15:21:56 -0400
commite8dc513bd012c9d7e1a5908c72056d5be52e760e (patch)
treee2ce3e075be6786118b6e8200741e14b595bdca0 /src/app/config
parentc32d485942e766eeea70cab468cc7c727a5be270 (diff)
downloadtor-e8dc513bd012c9d7e1a5908c72056d5be52e760e.tar.gz
tor-e8dc513bd012c9d7e1a5908c72056d5be52e760e.zip
Add a config_mgr_t type to wrap config_format_t
Remember that our goal in the present refactoring is to allow each subsystem to declare its own configuration structure and variables. To do this, each module will get its own config_format_t, and so we'll want a different structure that wraps several config_format_t objects. This is a "config_mgr_t".
Diffstat (limited to 'src/app/config')
-rw-r--r--src/app/config/config.c60
-rw-r--r--src/app/config/config.h5
-rw-r--r--src/app/config/confparse.c145
-rw-r--r--src/app/config/confparse.h47
-rw-r--r--src/app/config/statefile.c33
5 files changed, 191 insertions, 99 deletions
diff --git a/src/app/config/config.c b/src/app/config/config.c
index 4bc807a6fb..76feed0005 100644
--- a/src/app/config/config.c
+++ b/src/app/config/config.c
@@ -843,7 +843,7 @@ static void config_maybe_load_geoip_files_(const or_options_t *options,
static int options_validate_cb(void *old_options, void *options,
void *default_options,
int from_setconf, char **msg);
-static void options_free_cb(void *options);
+static void options_free_cb(const config_mgr_t *, void *options);
static void cleanup_protocol_warning_severity_level(void);
static void set_protocol_warning_severity_level(int warning_severity);
@@ -851,7 +851,7 @@ static void set_protocol_warning_severity_level(int warning_severity);
#define OR_OPTIONS_MAGIC 9090909
/** Configuration format for or_options_t. */
-STATIC const config_format_t options_format = {
+static const config_format_t options_format = {
sizeof(or_options_t),
{
"or_options_t",
@@ -895,6 +895,19 @@ static int in_option_validation = 0;
/* True iff we've initialized libevent */
static int libevent_initialized = 0;
+/* A global configuration manager to handle all configuration objects. */
+static config_mgr_t *options_mgr = NULL;
+
+/** Return the global configuration manager object for torrc options. */
+STATIC const config_mgr_t *
+get_options_mgr(void)
+{
+ if (PREDICT_UNLIKELY(options_mgr == NULL)) {
+ options_mgr = config_mgr_new(&options_format);
+ }
+ return options_mgr;
+}
+
/** Return the contents of our frontpage string, or NULL if not configured. */
MOCK_IMPL(const char*,
get_dirportfrontpage, (void))
@@ -977,14 +990,14 @@ set_options(or_options_t *new_val, char **msg)
if (old_options && old_options != global_options) {
elements = smartlist_new();
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]; // XXXX 29211
const char *var_name = var->member.name;
if (config_var_is_contained(var)) {
/* something else will check this var, or it doesn't need checking */
continue;
}
- if (!config_is_same(&options_format, new_val, old_options, var_name)) {
- line = config_get_assigned_option(&options_format, new_val,
+ if (!config_is_same(get_options_mgr(), new_val, old_options, var_name)) {
+ line = config_get_assigned_option(get_options_mgr(), new_val,
var_name, 1);
if (line) {
@@ -1046,7 +1059,7 @@ or_options_free_(or_options_t *options)
tor_free(options->command_arg);
tor_free(options->master_key_fname);
config_free_lines(options->MyFamily);
- config_free(&options_format, options);
+ config_free(get_options_mgr(), options);
}
/** Release all memory and resources held by global configuration structures.
@@ -1080,6 +1093,8 @@ config_free_all(void)
have_parsed_cmdline = 0;
libevent_initialized = 0;
+
+ config_mgr_free(options_mgr);
}
/** Make <b>address</b> -- a piece of information related to our operation as
@@ -2547,7 +2562,7 @@ config_parse_commandline(int argc, char **argv, int ignore_errors,
param = tor_malloc_zero(sizeof(config_line_t));
param->key = is_cmdline ? tor_strdup(argv[i]) :
- tor_strdup(config_expand_abbrev(&options_format, s, 1, 1));
+ tor_strdup(config_expand_abbrev(get_options_mgr(), s, 1, 1));
param->value = arg;
param->command = command;
param->next = NULL;
@@ -2573,7 +2588,7 @@ config_parse_commandline(int argc, char **argv, int ignore_errors,
int
option_is_recognized(const char *key)
{
- const config_var_t *var = config_find_option(&options_format, key);
+ const config_var_t *var = config_find_option(get_options_mgr(), key);
return (var != NULL);
}
@@ -2582,7 +2597,7 @@ option_is_recognized(const char *key)
const char *
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(get_options_mgr(), key);
return var ? var->member.name : NULL;
}
@@ -2591,7 +2606,7 @@ option_get_canonical_name(const char *key)
config_line_t *
option_get_assignment(const or_options_t *options, const char *key)
{
- return config_get_assigned_option(&options_format, options, key, 1);
+ return config_get_assigned_option(get_options_mgr(), options, key, 1);
}
/** Try assigning <b>list</b> to the global options. You do this by duping
@@ -2607,9 +2622,9 @@ setopt_err_t
options_trial_assign(config_line_t *list, unsigned flags, char **msg)
{
int r;
- or_options_t *trial_options = config_dup(&options_format, get_options());
+ or_options_t *trial_options = config_dup(get_options_mgr(), get_options());
- if ((r=config_assign(&options_format, trial_options,
+ if ((r=config_assign(get_options_mgr(), trial_options,
list, flags, msg)) < 0) {
or_options_free(trial_options);
return r;
@@ -2992,7 +3007,7 @@ is_local_addr, (const tor_addr_t *addr))
or_options_t *
options_new(void)
{
- return config_new(&options_format);
+ return config_new(get_options_mgr());
}
/** Set <b>options</b> to hold reasonable defaults for most options.
@@ -3000,10 +3015,10 @@ options_new(void)
void
options_init(or_options_t *options)
{
- config_init(&options_format, options);
+ config_init(get_options_mgr(), options);
config_line_t *dflts = get_options_defaults();
char *msg=NULL;
- if (config_assign(&options_format, options, dflts,
+ if (config_assign(get_options_mgr(), options, dflts,
CAL_WARN_DEPRECATIONS, &msg)<0) {
log_err(LD_BUG, "Unable to set default options: %s", msg);
tor_free(msg);
@@ -3040,7 +3055,7 @@ options_dump(const or_options_t *options, int how_to_dump)
return NULL;
}
- return config_dump(&options_format, use_defaults, options, minimal, 0);
+ return config_dump(get_options_mgr(), use_defaults, options, minimal, 0);
}
/** Return 0 if every element of sl is a string holding a decimal
@@ -3174,8 +3189,9 @@ options_validate_cb(void *old_options, void *options, void *default_options,
/** Callback to free an or_options_t */
static void
-options_free_cb(void *options)
+options_free_cb(const config_mgr_t *mgr, void *options)
{
+ (void)mgr;
or_options_free_(options);
}
@@ -4435,7 +4451,7 @@ options_validate(or_options_t *old_options, or_options_t *options,
STMT_BEGIN \
if (!options->TestingTorNetwork && \
!options->UsingTestNetworkDefaults_ && \
- !config_is_same(&options_format,options, \
+ !config_is_same(get_options_mgr(),options, \
default_options,#arg)) { \
REJECT(#arg " may only be changed in testing Tor " \
"networks!"); \
@@ -5431,7 +5447,7 @@ options_init_from_string(const char *cf_defaults, const char *cf,
err = SETOPT_ERR_PARSE;
goto err;
}
- retval = config_assign(&options_format, newoptions, cl,
+ retval = config_assign(get_options_mgr(), newoptions, cl,
CAL_WARN_DEPRECATIONS, msg);
config_free_lines(cl);
if (retval < 0) {
@@ -5439,15 +5455,15 @@ options_init_from_string(const char *cf_defaults, const char *cf,
goto err;
}
if (i==0)
- newdefaultoptions = config_dup(&options_format, newoptions);
+ newdefaultoptions = config_dup(get_options_mgr(), newoptions);
}
if (newdefaultoptions == NULL) {
- newdefaultoptions = config_dup(&options_format, global_default_options);
+ newdefaultoptions = config_dup(get_options_mgr(), global_default_options);
}
/* Go through command-line variables too */
- retval = config_assign(&options_format, newoptions,
+ retval = config_assign(get_options_mgr(), newoptions,
global_cmdline_options, CAL_WARN_DEPRECATIONS, msg);
if (retval < 0) {
err = SETOPT_ERR_PARSE;
diff --git a/src/app/config/config.h b/src/app/config/config.h
index c6feb89fe7..44f09e5ee9 100644
--- a/src/app/config/config.h
+++ b/src/app/config/config.h
@@ -247,9 +247,8 @@ int options_any_client_port_set(const or_options_t *options);
#define CL_PORT_DFLT_GROUP_WRITABLE (1u<<7)
STATIC int options_act(const or_options_t *old_options);
-#ifdef TOR_UNIT_TESTS
-extern const struct config_format_t options_format;
-#endif
+struct config_mgr_t;
+STATIC const struct config_mgr_t *get_options_mgr(void);
STATIC port_cfg_t *port_cfg_new(size_t namelen);
#define port_cfg_free(port) \
diff --git a/src/app/config/confparse.c b/src/app/config/confparse.c
index 699fc0e3dd..9c4c6a2778 100644
--- a/src/app/config/confparse.c
+++ b/src/app/config/confparse.c
@@ -37,13 +37,44 @@
#include "lib/string/printf.h"
#include "lib/string/util_string.h"
-static void config_reset(const config_format_t *fmt, void *options,
+static void config_reset(const config_mgr_t *fmt, void *options,
const config_var_t *var, int use_defaults);
+struct config_mgr_t {
+ /** The 'top-level' configuration format. This one is used for legacy
+ * options that have not yet been assigned to different sub-modules.
+ *
+ * (NOTE: for now, this is the only config_format_t that a config_mgr_t
+ * contains. A subsequent commit will add more. XXXX)
+ */
+ const config_format_t *toplevel;
+};
+
+/** Create a new config_mgr_t to manage a set of configuration objects to be
+ * wrapped under <b>toplevel_fmt</b>. */
+config_mgr_t *
+config_mgr_new(const config_format_t *toplevel_fmt)
+{
+ config_mgr_t *mgr = tor_malloc_zero(sizeof(config_mgr_t));
+ mgr->toplevel = toplevel_fmt;
+ return mgr;
+}
+
+/** Release all storage held in <b>mgr</b> */
+void
+config_mgr_free_(config_mgr_t *mgr)
+{
+ if (!mgr)
+ return;
+ memset(mgr, 0, sizeof(*mgr));
+ tor_free(mgr);
+}
+
/** Allocate an empty configuration object of a given format type. */
void *
-config_new(const config_format_t *fmt)
+config_new(const config_mgr_t *mgr)
{
+ const config_format_t *fmt = mgr->toplevel;
void *opts = tor_malloc_zero(fmt->size);
struct_set_magic(opts, &fmt->magic);
CONFIG_CHECK(fmt, opts);
@@ -60,9 +91,10 @@ config_new(const config_format_t *fmt)
* apply abbreviations that work for the config file and the command line.
* If <b>warn_obsolete</b> is set, warn about deprecated names. */
const char *
-config_expand_abbrev(const config_format_t *fmt, const char *option,
+config_expand_abbrev(const config_mgr_t *mgr, const char *option,
int command_line, int warn_obsolete)
{
+ const config_format_t *fmt = mgr->toplevel;
int i;
if (! fmt->abbrevs)
return option;
@@ -90,8 +122,9 @@ config_expand_abbrev(const config_format_t *fmt, const char *option,
* explaining why it is deprecated (which may be an empty string). Return NULL
* if it is not deprecated. The <b>key</b> field must be fully expanded. */
const char *
-config_find_deprecation(const config_format_t *fmt, const char *key)
+config_find_deprecation(const config_mgr_t *mgr, const char *key)
{
+ const config_format_t *fmt = mgr->toplevel;
if (BUG(fmt == NULL) || BUG(key == NULL))
return NULL; // LCOV_EXCL_LINE
if (fmt->deprecations == NULL)
@@ -112,8 +145,9 @@ config_find_deprecation(const config_format_t *fmt, const char *key)
* NULL.
*/
const config_var_t *
-config_find_option(const config_format_t *fmt, const char *key)
+config_find_option(const config_mgr_t *mgr, const char *key)
{
+ const config_format_t *fmt = mgr->toplevel;
int i;
size_t keylen = strlen(key);
if (!keylen)
@@ -139,8 +173,9 @@ config_find_option(const config_format_t *fmt, const char *key)
/** Return the number of option entries in <b>fmt</b>. */
static int
-config_count_options(const config_format_t *fmt)
+config_count_options(const config_mgr_t *mgr)
{
+ const config_format_t *fmt = mgr->toplevel;
int i;
for (i=0; fmt->vars[i].member.name; ++i)
;
@@ -175,14 +210,15 @@ config_var_is_contained(const config_var_t *var)
* Called from config_assign_line() and option_reset().
*/
static int
-config_assign_value(const config_format_t *fmt, void *options,
+config_assign_value(const config_mgr_t *mgr, void *options,
config_line_t *c, char **msg)
{
const config_var_t *var;
+ const config_format_t *fmt = mgr->toplevel;
CONFIG_CHECK(fmt, options);
- var = config_find_option(fmt, c->key);
+ var = config_find_option(mgr, c->key);
tor_assert(var);
tor_assert(!strcmp(c->key, var->member.name));
@@ -192,9 +228,11 @@ config_assign_value(const config_format_t *fmt, void *options,
/** Mark every linelist in <b>options</b> "fragile", so that fresh assignments
* to it will replace old ones. */
static void
-config_mark_lists_fragile(const config_format_t *fmt, void *options)
+config_mark_lists_fragile(const config_mgr_t *mgr, void *options)
{
int i;
+ const config_format_t *fmt = mgr->toplevel;
+
tor_assert(fmt);
tor_assert(options);
@@ -224,10 +262,11 @@ warn_deprecated_option(const char *what, const char *why)
* Called from config_assign().
*/
static int
-config_assign_line(const config_format_t *fmt, void *options,
+config_assign_line(const config_mgr_t *mgr, void *options,
config_line_t *c, unsigned flags,
bitarray_t *options_seen, char **msg)
{
+ const config_format_t *fmt = mgr->toplevel;
const unsigned use_defaults = flags & CAL_USE_DEFAULTS;
const unsigned clear_first = flags & CAL_CLEAR_FIRST;
const unsigned warn_deprecations = flags & CAL_WARN_DEPRECATIONS;
@@ -235,7 +274,7 @@ config_assign_line(const config_format_t *fmt, void *options,
CONFIG_CHECK(fmt, options);
- var = config_find_option(fmt, c->key);
+ var = config_find_option(mgr, c->key);
if (!var) {
if (fmt->extra) {
void *lvalue = STRUCT_VAR_P(options, fmt->extra->offset);
@@ -258,7 +297,7 @@ config_assign_line(const config_format_t *fmt, void *options,
const char *deprecation_msg;
if (warn_deprecations &&
- (deprecation_msg = config_find_deprecation(fmt, var->member.name))) {
+ (deprecation_msg = config_find_deprecation(mgr, var->member.name))) {
warn_deprecated_option(var->member.name, deprecation_msg);
}
@@ -271,14 +310,14 @@ config_assign_line(const config_format_t *fmt, void *options,
log_warn(LD_CONFIG,
"Linelist option '%s' has no value. Skipping.", c->key);
} else { /* not already cleared */
- config_reset(fmt, options, var, use_defaults);
+ config_reset(mgr, options, var, use_defaults);
}
}
return 0;
} else if (c->command == CONFIG_LINE_CLEAR && !clear_first) {
// XXXX This is unreachable, since a CLEAR line always has an
// XXXX empty value.
- config_reset(fmt, options, var, use_defaults); // LCOV_EXCL_LINE
+ config_reset(mgr, options, var, use_defaults); // LCOV_EXCL_LINE
}
if (options_seen && ! config_var_is_cumulative(var)) {
@@ -292,7 +331,7 @@ config_assign_line(const config_format_t *fmt, void *options,
bitarray_set(options_seen, var_index);
}
- if (config_assign_value(fmt, options, c, msg) < 0)
+ if (config_assign_value(mgr, options, c, msg) < 0)
return -2;
return 0;
}
@@ -300,18 +339,19 @@ config_assign_line(const config_format_t *fmt, void *options,
/** Restore the option named <b>key</b> in options to its default value.
* Called from config_assign(). */
STATIC void
-config_reset_line(const config_format_t *fmt, void *options,
+config_reset_line(const config_mgr_t *mgr, void *options,
const char *key, int use_defaults)
{
+ const config_format_t *fmt = mgr->toplevel;
const config_var_t *var;
CONFIG_CHECK(fmt, options);
- var = config_find_option(fmt, key);
+ var = config_find_option(mgr, key);
if (!var)
return; /* give error on next pass. */
- config_reset(fmt, options, var, use_defaults);
+ config_reset(mgr, options, var, use_defaults);
}
/** Return true iff value needs to be quoted and escaped to be used in
@@ -345,16 +385,18 @@ config_value_needs_escape(const char *value)
* value needs to be quoted before it's put in a config file, quote and
* escape that value. Return NULL if no such key exists. */
config_line_t *
-config_get_assigned_option(const config_format_t *fmt, const void *options,
+config_get_assigned_option(const config_mgr_t *mgr, const void *options,
const char *key, int escape_val)
{
const config_var_t *var;
config_line_t *result;
+ const config_format_t *fmt = mgr->toplevel;
+
tor_assert(options && key);
CONFIG_CHECK(fmt, options);
- var = config_find_option(fmt, key);
+ var = config_find_option(mgr, key);
if (!var) {
log_warn(LD_CONFIG, "Unknown option '%s'. Failing.", key);
return NULL;
@@ -432,12 +474,13 @@ options_trial_assign() calls config_assign(1, 1)
returns.
*/
int
-config_assign(const config_format_t *fmt, void *options, config_line_t *list,
+config_assign(const config_mgr_t *mgr, void *options, config_line_t *list,
unsigned config_assign_flags, char **msg)
{
config_line_t *p;
bitarray_t *options_seen;
- const int n_options = config_count_options(fmt);
+ const config_format_t *fmt = mgr->toplevel;
+ const int n_options = config_count_options(mgr);
const unsigned clear_first = config_assign_flags & CAL_CLEAR_FIRST;
const unsigned use_defaults = config_assign_flags & CAL_USE_DEFAULTS;
@@ -445,7 +488,7 @@ config_assign(const config_format_t *fmt, void *options, config_line_t *list,
/* pass 1: normalize keys */
for (p = list; p; p = p->next) {
- const char *full = config_expand_abbrev(fmt, p->key, 0, 1);
+ const char *full = config_expand_abbrev(mgr, p->key, 0, 1);
if (strcmp(full,p->key)) {
tor_free(p->key);
p->key = tor_strdup(full);
@@ -456,14 +499,14 @@ config_assign(const config_format_t *fmt, void *options, config_line_t *list,
* mentioned config options, and maybe set to their defaults. */
if (clear_first) {
for (p = list; p; p = p->next)
- config_reset_line(fmt, options, p->key, use_defaults);
+ config_reset_line(mgr, options, p->key, use_defaults);
}
options_seen = bitarray_init_zero(n_options);
/* pass 3: assign. */
while (list) {
int r;
- if ((r=config_assign_line(fmt, options, list, config_assign_flags,
+ if ((r=config_assign_line(mgr, options, list, config_assign_flags,
options_seen, msg))) {
bitarray_free(options_seen);
return r;
@@ -475,7 +518,7 @@ config_assign(const config_format_t *fmt, void *options, config_line_t *list,
/** Now we're done assigning a group of options to the configuration.
* Subsequent group assignments should _replace_ linelists, not extend
* them. */
- config_mark_lists_fragile(fmt, options);
+ config_mark_lists_fragile(mgr, options);
return 0;
}
@@ -483,12 +526,9 @@ config_assign(const config_format_t *fmt, void *options, config_line_t *list,
/** Reset config option <b>var</b> to 0, 0.0, NULL, or the equivalent.
* Called from config_reset() and config_free(). */
static void
-config_clear(const config_format_t *fmt, void *options,
+config_clear(void *options,
const config_var_t *var)
{
-
- (void)fmt; /* unused */
-
struct_var_free(options, &var->member);
}
@@ -496,20 +536,21 @@ config_clear(const config_format_t *fmt, void *options,
* <b>use_defaults</b>, set it to its default value.
* Called by config_init() and option_reset_line() and option_assign_line(). */
static void
-config_reset(const config_format_t *fmt, void *options,
+config_reset(const config_mgr_t *mgr, void *options,
const config_var_t *var, int use_defaults)
{
+ const config_format_t *fmt = mgr->toplevel;
config_line_t *c;
char *msg = NULL;
CONFIG_CHECK(fmt, options);
- config_clear(fmt, options, var); /* clear it first */
+ config_clear(options, var); /* clear it first */
if (!use_defaults)
return; /* all done */
if (var->initvalue) {
c = tor_malloc_zero(sizeof(config_line_t));
c->key = tor_strdup(var->member.name);
c->value = tor_strdup(var->initvalue);
- if (config_assign_value(fmt, options, c, &msg) < 0) {
+ if (config_assign_value(mgr, options, c, &msg) < 0) {
// LCOV_EXCL_START
log_warn(LD_BUG, "Failed to assign default: %s", msg);
tor_free(msg); /* if this happens it's a bug */
@@ -521,9 +562,10 @@ config_reset(const config_format_t *fmt, void *options,
/** Release storage held by <b>options</b>. */
void
-config_free_(const config_format_t *fmt, void *options)
+config_free_(const config_mgr_t *mgr, void *options)
{
int i;
+ const config_format_t *fmt = mgr->toplevel;
if (!options)
return;
@@ -531,7 +573,7 @@ config_free_(const config_format_t *fmt, void *options)
tor_assert(fmt);
for (i=0; fmt->vars[i].member.name; ++i)
- config_clear(fmt, options, &(fmt->vars[i]));
+ config_clear(options, &(fmt->vars[i]));
if (fmt->extra) {
config_line_t **linep = STRUCT_VAR_P(options, fmt->extra->offset);
@@ -545,14 +587,15 @@ config_free_(const config_format_t *fmt, void *options)
* and <b>o2</b>. Must not be called for LINELIST_S or OBSOLETE options.
*/
int
-config_is_same(const config_format_t *fmt,
+config_is_same(const config_mgr_t *mgr,
const void *o1, const void *o2,
const char *name)
{
+ const config_format_t *fmt = mgr->toplevel;
CONFIG_CHECK(fmt, o1);
CONFIG_CHECK(fmt, o2);
- const config_var_t *var = config_find_option(fmt, name);
+ const config_var_t *var = config_find_option(mgr, name);
if (!var) {
return true;
}
@@ -562,12 +605,13 @@ config_is_same(const config_format_t *fmt,
/** Copy storage held by <b>old</b> into a new or_options_t and return it. */
void *
-config_dup(const config_format_t *fmt, const void *old)
+config_dup(const config_mgr_t *mgr, const void *old)
{
+ const config_format_t *fmt = mgr->toplevel;
void *newopts;
int i;
- newopts = config_new(fmt);
+ newopts = config_new(mgr);
for (i=0; fmt->vars[i].member.name; ++i) {
if (config_var_is_contained(&fmt->vars[i])) {
// Something else will copy this option, or it doesn't need copying.
@@ -586,9 +630,10 @@ config_dup(const config_format_t *fmt, const void *old)
/** Set all vars in the configuration object <b>options</b> to their default
* values. */
void
-config_init(const config_format_t *fmt, void *options)
+config_init(const config_mgr_t *mgr, void *options)
{
int i;
+ const config_format_t *fmt = mgr->toplevel;
const config_var_t *var;
CONFIG_CHECK(fmt, options);
@@ -596,7 +641,7 @@ config_init(const config_format_t *fmt, void *options)
var = &fmt->vars[i];
if (!var->initvalue)
continue; /* defaults to NULL or 0 */
- config_reset(fmt, options, var, 1);
+ config_reset(mgr, options, var, 1);
}
}
@@ -605,11 +650,12 @@ config_init(const config_format_t *fmt, void *options)
* Else, if comment_defaults, write default values as comments.
*/
char *
-config_dump(const config_format_t *fmt, const void *default_options,
+config_dump(const config_mgr_t *mgr, const void *default_options,
const void *options, int minimal,
int comment_defaults)
{
smartlist_t *elements;
+ const config_format_t *fmt = mgr->toplevel;
const void *defaults = default_options;
void *defaults_tmp = NULL;
config_line_t *line, *assigned;
@@ -618,8 +664,8 @@ config_dump(const config_format_t *fmt, const void *default_options,
char *msg = NULL;
if (defaults == NULL) {
- defaults = defaults_tmp = config_new(fmt);
- config_init(fmt, defaults_tmp);
+ defaults = defaults_tmp = config_new(mgr);
+ config_init(mgr, defaults_tmp);
}
/* XXX use a 1 here so we don't add a new log line while dumping */
@@ -643,15 +689,15 @@ config_dump(const config_format_t *fmt, const void *default_options,
/* Don't save 'hidden' control variables. */
if (fmt->vars[i].flags & CVFLAG_NODUMP)
continue;
- if (minimal && config_is_same(fmt, options, defaults,
+ if (minimal && config_is_same(mgr, options, defaults,
fmt->vars[i].member.name))
continue;
else if (comment_defaults &&
- config_is_same(fmt, options, defaults, fmt->vars[i].member.name))
+ config_is_same(mgr, options, defaults, fmt->vars[i].member.name))
comment_option = 1;
line = assigned =
- config_get_assigned_option(fmt, options, fmt->vars[i].member.name, 1);
+ config_get_assigned_option(mgr, options, fmt->vars[i].member.name, 1);
for (; line; line = line->next) {
if (!strcmpstart(line->key, "__")) {
@@ -677,7 +723,7 @@ config_dump(const config_format_t *fmt, const void *default_options,
SMARTLIST_FOREACH(elements, char *, cp, tor_free(cp));
smartlist_free(elements);
if (defaults_tmp) {
- fmt->free_fn(defaults_tmp);
+ fmt->free_fn(mgr, defaults_tmp);
}
return result;
}
@@ -687,8 +733,9 @@ config_dump(const config_format_t *fmt, const void *default_options,
* Return false otherwise. Log errors at level <b>severity</b>.
*/
bool
-config_check_ok(const config_format_t *fmt, const void *options, int severity)
+config_check_ok(const config_mgr_t *mgr, const void *options, int severity)
{
+ const config_format_t *fmt = mgr->toplevel;
bool all_ok = true;
for (int i=0; fmt->vars[i].member.name; ++i) {
if (!struct_var_ok(options, &fmt->vars[i].member)) {
diff --git a/src/app/config/confparse.h b/src/app/config/confparse.h
index 3633c2a80b..a6a2450aee 100644
--- a/src/app/config/confparse.h
+++ b/src/app/config/confparse.h
@@ -39,8 +39,10 @@ typedef struct config_deprecation_t {
* of arguments. */
typedef int (*validate_fn_t)(void*,void*,void*,int,char**);
+struct config_mgr_t;
+
/** Callback to free a configuration object. */
-typedef void (*free_cfg_fn_t)(void*);
+typedef void (*free_cfg_fn_t)(const struct config_mgr_t *mgr, void*);
/** Information on the keys, value types, key-to-struct-member mappings,
* variable descriptions, validation functions, and abbreviations for a
@@ -61,6 +63,19 @@ typedef struct config_format_t {
const struct_member_t *extra;
} config_format_t;
+/**
+ * A collection of config_format_t objects to describe several objects
+ * that are all configured with the same configuration file.
+ *
+ * (NOTE: for now, this only handles a single config_format_t.)
+ **/
+typedef struct config_mgr_t config_mgr_t;
+
+config_mgr_t *config_mgr_new(const config_format_t *toplevel_fmt);
+void config_mgr_free_(config_mgr_t *mgr);
+#define config_mgr_free(mgr) \
+ FREE_AND_NULL(config_mgr_t, config_mgr_free_, (mgr))
+
/** Macro: assert that <b>cfg</b> has the right magic field for format
* <b>fmt</b>. */
#define CONFIG_CHECK(fmt, cfg) STMT_BEGIN \
@@ -72,34 +87,34 @@ typedef struct config_format_t {
#define CAL_CLEAR_FIRST (1u<<1)
#define CAL_WARN_DEPRECATIONS (1u<<2)
-void *config_new(const config_format_t *fmt);
-void config_free_(const config_format_t *fmt, void *options);
-#define config_free(fmt, options) do { \
- config_free_((fmt), (options)); \
+void *config_new(const config_mgr_t *fmt);
+void config_free_(const config_mgr_t *fmt, void *options);
+#define config_free(mgr, options) do { \
+ config_free_((mgr), (options)); \
(options) = NULL; \
} while (0)
-struct config_line_t *config_get_assigned_option(const config_format_t *fmt,
+struct config_line_t *config_get_assigned_option(const config_mgr_t *mgr,
const void *options, const char *key,
int escape_val);
-int config_is_same(const config_format_t *fmt,
+int config_is_same(const config_mgr_t *fmt,
const void *o1, const void *o2,
const char *name);
-void config_init(const config_format_t *fmt, void *options);
-void *config_dup(const config_format_t *fmt, const void *old);
-char *config_dump(const config_format_t *fmt, const void *default_options,
+void config_init(const config_mgr_t *mgr, void *options);
+void *config_dup(const config_mgr_t *mgr, const void *old);
+char *config_dump(const config_mgr_t *mgr, const void *default_options,
const void *options, int minimal,
int comment_defaults);
-bool config_check_ok(const config_format_t *fmt, const void *options,
+bool config_check_ok(const config_mgr_t *mgr, const void *options,
int severity);
-int config_assign(const config_format_t *fmt, void *options,
+int config_assign(const config_mgr_t *mgr, void *options,
struct config_line_t *list,
unsigned flags, char **msg);
-const char *config_find_deprecation(const config_format_t *fmt,
+const char *config_find_deprecation(const config_mgr_t *mgr,
const char *key);
-const config_var_t *config_find_option(const config_format_t *fmt,
+const config_var_t *config_find_option(const config_mgr_t *mgr,
const char *key);
-const char *config_expand_abbrev(const config_format_t *fmt,
+const char *config_expand_abbrev(const config_mgr_t *mgr,
const char *option,
int command_line, int warn_obsolete);
void warn_deprecated_option(const char *what, const char *why);
@@ -117,7 +132,7 @@ bool config_var_is_contained(const config_var_t *var);
#define CFG_EQ_ROUTERSET(a,b,opt) routerset_equal((a)->opt, (b)->opt)
#ifdef CONFPARSE_PRIVATE
-STATIC void config_reset_line(const config_format_t *fmt, void *options,
+STATIC void config_reset_line(const config_mgr_t *mgr, void *options,
const char *key, int use_defaults);
#endif
diff --git a/src/app/config/statefile.c b/src/app/config/statefile.c
index d997d3932e..a44bcf6fb5 100644
--- a/src/app/config/statefile.c
+++ b/src/app/config/statefile.c
@@ -145,7 +145,7 @@ static int or_state_validate_cb(void *old_options, void *options,
void *default_options,
int from_setconf, char **msg);
-static void or_state_free_cb(void *state);
+static void or_state_free_cb(const config_mgr_t *mgr, void *state);
/** Magic value for or_state_t. */
#define OR_STATE_MAGIC 0x57A73f57
@@ -174,6 +174,19 @@ static const config_format_t state_format = {
&state_extra_var,
};
+/* A global configuration manager for state-file objects */
+static config_mgr_t *state_mgr = NULL;
+
+/** Return the configuration manager for state-file objects. */
+static const config_mgr_t *
+get_state_mgr(void)
+{
+ if (PREDICT_UNLIKELY(state_mgr == NULL)) {
+ state_mgr = config_mgr_new(&state_format);
+ }
+ return state_mgr;
+}
+
/** Persistent serialized state. */
static or_state_t *global_state = NULL;
@@ -269,8 +282,9 @@ or_state_validate_cb(void *old_state, void *state, void *default_state,
}
static void
-or_state_free_cb(void *state)
+or_state_free_cb(const config_mgr_t *mgr, void *state)
{
+ (void)mgr;
or_state_free_(state);
}
@@ -298,7 +312,7 @@ or_state_set(or_state_t *new_state)
char *err = NULL;
int ret = 0;
tor_assert(new_state);
- config_free(&state_format, global_state);
+ config_free(get_state_mgr(), global_state);
global_state = new_state;
if (entry_guards_parse_state(global_state, 1, &err)<0) {
log_warn(LD_GENERAL,"%s",err);
@@ -363,7 +377,7 @@ or_state_new(void)
{
or_state_t *new_state = tor_malloc_zero(sizeof(or_state_t));
new_state->magic_ = OR_STATE_MAGIC;
- config_init(&state_format, new_state);
+ config_init(get_state_mgr(), new_state);
return new_state;
}
@@ -404,7 +418,7 @@ or_state_load(void)
int assign_retval;
if (config_get_lines(contents, &lines, 0)<0)
goto done;
- assign_retval = config_assign(&state_format, new_state,
+ assign_retval = config_assign(get_state_mgr(), new_state,
lines, 0, &errmsg);
config_free_lines(lines);
if (assign_retval<0)
@@ -431,7 +445,7 @@ or_state_load(void)
or_state_save_broken(fname);
tor_free(contents);
- config_free(&state_format, new_state);
+ config_free(get_state_mgr(), new_state);
new_state = or_state_new();
} else if (contents) {
@@ -464,7 +478,7 @@ or_state_load(void)
tor_free(fname);
tor_free(contents);
if (new_state)
- config_free(&state_format, new_state);
+ config_free(get_state_mgr(), new_state);
return r;
}
@@ -517,7 +531,7 @@ or_state_save(time_t now)
tor_free(global_state->TorVersion);
tor_asprintf(&global_state->TorVersion, "Tor %s", get_version());
- state = config_dump(&state_format, NULL, global_state, 1, 0);
+ state = config_dump(get_state_mgr(), NULL, global_state, 1, 0);
format_local_iso_time(tbuf, now);
tor_asprintf(&contents,
"# Tor state file last generated on %s local time\n"
@@ -727,7 +741,7 @@ or_state_free_(or_state_t *state)
if (!state)
return;
- config_free(&state_format, state);
+ config_free(get_state_mgr(), state);
}
void
@@ -735,4 +749,5 @@ or_state_free_all(void)
{
or_state_free(global_state);
global_state = NULL;
+ config_mgr_free(state_mgr);
}