|
@@ -260,10 +260,10 @@ static void config_line_append(config_line_t **lst,
|
|
static void option_clear(config_format_t *fmt, or_options_t *options,
|
|
static void option_clear(config_format_t *fmt, or_options_t *options,
|
|
config_var_t *var);
|
|
config_var_t *var);
|
|
static void option_reset(config_format_t *fmt, or_options_t *options,
|
|
static void option_reset(config_format_t *fmt, or_options_t *options,
|
|
- config_var_t *var);
|
|
|
|
|
|
+ config_var_t *var, int use_defaults);
|
|
static void config_free(config_format_t *fmt, void *options);
|
|
static void config_free(config_format_t *fmt, void *options);
|
|
static int option_is_same(config_format_t *fmt,
|
|
static int option_is_same(config_format_t *fmt,
|
|
- or_options_t *o1, or_options_t *o2,const char *name);
|
|
|
|
|
|
+ or_options_t *o1, or_options_t *o2, const char *name);
|
|
static or_options_t *options_dup(config_format_t *fmt, or_options_t *old);
|
|
static or_options_t *options_dup(config_format_t *fmt, or_options_t *old);
|
|
static int options_validate(or_options_t *options);
|
|
static int options_validate(or_options_t *options);
|
|
static int options_act(or_options_t *old_options);
|
|
static int options_act(or_options_t *old_options);
|
|
@@ -753,8 +753,14 @@ config_find_option(config_format_t *fmt, const char *key)
|
|
return NULL;
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/*
|
|
|
|
+ * Functions to assign config options.
|
|
|
|
+ */
|
|
|
|
+
|
|
/** <b>c</b>-\>key is known to be a real key. Update <b>options</b>
|
|
/** <b>c</b>-\>key is known to be a real key. Update <b>options</b>
|
|
* with <b>c</b>-\>value and return 0, or return -1 if bad value.
|
|
* with <b>c</b>-\>value and return 0, or return -1 if bad value.
|
|
|
|
+ *
|
|
|
|
+ * Called from config_assign_line() and option_reset().
|
|
*/
|
|
*/
|
|
static int
|
|
static int
|
|
config_assign_value(config_format_t *fmt, or_options_t *options,
|
|
config_assign_value(config_format_t *fmt, or_options_t *options,
|
|
@@ -827,10 +833,10 @@ config_assign_value(config_format_t *fmt, or_options_t *options,
|
|
break;
|
|
break;
|
|
|
|
|
|
case CONFIG_TYPE_CSV:
|
|
case CONFIG_TYPE_CSV:
|
|
- if (*(smartlist_t**)lvalue) {
|
|
|
|
- SMARTLIST_FOREACH(*(smartlist_t**)lvalue, char *, cp, tor_free(cp));
|
|
|
|
- smartlist_clear(*(smartlist_t**)lvalue);
|
|
|
|
- } else {
|
|
|
|
|
|
+ if (!*(smartlist_t**)lvalue) {
|
|
|
|
+// SMARTLIST_FOREACH(*(smartlist_t**)lvalue, char *, cp, tor_free(cp));
|
|
|
|
+// smartlist_clear(*(smartlist_t**)lvalue);
|
|
|
|
+// } else {
|
|
*(smartlist_t**)lvalue = smartlist_create();
|
|
*(smartlist_t**)lvalue = smartlist_create();
|
|
}
|
|
}
|
|
|
|
|
|
@@ -860,12 +866,14 @@ config_assign_value(config_format_t *fmt, or_options_t *options,
|
|
* <b>options</b> with its value and return 0. Otherwise return -1 for bad key,
|
|
* <b>options</b> with its value and return 0. Otherwise return -1 for bad key,
|
|
* -2 for bad value.
|
|
* -2 for bad value.
|
|
*
|
|
*
|
|
- * If 'reset' is set, and we get a line containing no value, restore the
|
|
|
|
- * option to its default value.
|
|
|
|
|
|
+ * If <b>clear_first</b> is set, clear the value first. Then if
|
|
|
|
+ * <b>use_defaults</b> is set, set the value to the default.
|
|
|
|
+ *
|
|
|
|
+ * Called from config_assign().
|
|
*/
|
|
*/
|
|
static int
|
|
static int
|
|
config_assign_line(config_format_t *fmt, or_options_t *options,
|
|
config_assign_line(config_format_t *fmt, or_options_t *options,
|
|
- config_line_t *c, int reset)
|
|
|
|
|
|
+ config_line_t *c, int use_defaults, int clear_first)
|
|
{
|
|
{
|
|
config_var_t *var;
|
|
config_var_t *var;
|
|
|
|
|
|
@@ -883,10 +891,7 @@ config_assign_line(config_format_t *fmt, or_options_t *options,
|
|
}
|
|
}
|
|
|
|
|
|
if (!strlen(c->value)) { /* reset or clear it, then return */
|
|
if (!strlen(c->value)) { /* reset or clear it, then return */
|
|
- if (reset)
|
|
|
|
- option_reset(fmt, options, var);
|
|
|
|
- else
|
|
|
|
- option_clear(fmt, options, var);
|
|
|
|
|
|
+ option_reset(fmt, options, var, use_defaults);
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -895,9 +900,11 @@ config_assign_line(config_format_t *fmt, or_options_t *options,
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
-/** restore the option named <b>key</b> in options to its default value. */
|
|
|
|
|
|
+/** Restore the option named <b>key</b> in options to its default value.
|
|
|
|
+ * Called from config_assign(). */
|
|
static void
|
|
static void
|
|
-config_reset_line(config_format_t *fmt, or_options_t *options, const char *key)
|
|
|
|
|
|
+config_reset_line(config_format_t *fmt, or_options_t *options,
|
|
|
|
+ const char *key, int use_defaults)
|
|
{
|
|
{
|
|
config_var_t *var;
|
|
config_var_t *var;
|
|
|
|
|
|
@@ -907,7 +914,7 @@ config_reset_line(config_format_t *fmt, or_options_t *options, const char *key)
|
|
if (!var)
|
|
if (!var)
|
|
return; /* give error on next pass. */
|
|
return; /* give error on next pass. */
|
|
|
|
|
|
- option_reset(fmt, options, var);
|
|
|
|
|
|
+ option_reset(fmt, options, var, use_defaults);
|
|
}
|
|
}
|
|
|
|
|
|
/** Return true iff key is a valid configuration option. */
|
|
/** Return true iff key is a valid configuration option. */
|
|
@@ -1044,16 +1051,56 @@ get_assigned_option(config_format_t *fmt, or_options_t *options, const char *key
|
|
* If an item is unrecognized, return -1 immediately,
|
|
* If an item is unrecognized, return -1 immediately,
|
|
* else return 0 for success.
|
|
* else return 0 for success.
|
|
*
|
|
*
|
|
- * If <b>reset</b>, then interpret empty lines as meaning "restore to
|
|
|
|
- * default value", and interpret LINELIST* options as replacing (not
|
|
|
|
- * extending) their previous values. Otherwise, interpret empty lines
|
|
|
|
- * as meaning "make the value 0 or null".
|
|
|
|
|
|
+ * If <b>clear_first</b>, interpret config options as replacing (not
|
|
|
|
+ * extending) their previous values. If <b>clear_first</b> is set,
|
|
|
|
+ * then <b>use_defaults</b> to decide if you set to defaults after
|
|
|
|
+ * clearing, or make the value 0 or NULL.
|
|
|
|
+ *
|
|
|
|
+ * Here are the use cases:
|
|
|
|
+ * 1. A non-empty AllowUnverified line in your torrc. Appends to current.
|
|
|
|
+ * 2. An empty AllowUnverified line in your torrc. Should clear it.
|
|
|
|
+ * 3. "RESETCONF AllowUnverified" sets it to default.
|
|
|
|
+ * 4. "SETCONF AllowUnverified" makes it NULL.
|
|
|
|
+ * 5. "SETCONF AllowUnverified=foo" clears it and sets it to "foo".
|
|
*
|
|
*
|
|
|
|
+ * Use_defaults Clear_first
|
|
|
|
+ * 0 0 "append"
|
|
|
|
+ * 1 0 undefined, don't use
|
|
|
|
+ * 0 1 "set to null first"
|
|
|
|
+ * 1 1 "set to defaults first"
|
|
* Return 0 on success, -1 on bad key, -2 on bad value.
|
|
* Return 0 on success, -1 on bad key, -2 on bad value.
|
|
*/
|
|
*/
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+There are three call cases for config_assign() currently.
|
|
|
|
+
|
|
|
|
+Case one: Torrc entry
|
|
|
|
+options_init_from_torrc() calls config_assign(0, 0)
|
|
|
|
+ calls config_assign_line(0, 0).
|
|
|
|
+ if value is empty, calls option_reset(0) and returns.
|
|
|
|
+ calls config_assign_value(), appends.
|
|
|
|
+
|
|
|
|
+Case two: setconf
|
|
|
|
+options_trial_assign() calls config_assign(0, 1)
|
|
|
|
+ calls config_reset_line(0)
|
|
|
|
+ calls option_reset(0)
|
|
|
|
+ calls option_clear().
|
|
|
|
+ calls config_assign_line(0, 1).
|
|
|
|
+ if value is empty, calls option_reset(0) and returns.
|
|
|
|
+ calls config_assign_value(), appends.
|
|
|
|
+
|
|
|
|
+Case three: resetconf
|
|
|
|
+options_trial_assign() calls config_assign(1, 1)
|
|
|
|
+ calls config_reset_line(1)
|
|
|
|
+ calls option_reset(1)
|
|
|
|
+ calls option_clear().
|
|
|
|
+ calls config_assign_value(default)
|
|
|
|
+ calls config_assign_line(1, 1).
|
|
|
|
+ calls option_reset(1) and returns.
|
|
|
|
+*/
|
|
static int
|
|
static int
|
|
-config_assign(config_format_t *fmt,
|
|
|
|
- void *options, config_line_t *list, int reset)
|
|
|
|
|
|
+config_assign(config_format_t *fmt, void *options,
|
|
|
|
+ config_line_t *list, int use_defaults, int clear_first)
|
|
{
|
|
{
|
|
config_line_t *p;
|
|
config_line_t *p;
|
|
|
|
|
|
@@ -1068,17 +1115,17 @@ config_assign(config_format_t *fmt,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- /* pass 2: if we're reading from a resetting source, clear all mentioned
|
|
|
|
- * linelists. */
|
|
|
|
- if (reset) {
|
|
|
|
|
|
+ /* pass 2: if we're reading from a resetting source, clear all
|
|
|
|
+ * mentioned config options, and maybe set to their defaults. */
|
|
|
|
+ if (clear_first) {
|
|
for (p = list; p; p = p->next)
|
|
for (p = list; p; p = p->next)
|
|
- config_reset_line(fmt, options, p->key);
|
|
|
|
|
|
+ config_reset_line(fmt, options, p->key, use_defaults);
|
|
}
|
|
}
|
|
|
|
|
|
/* pass 3: assign. */
|
|
/* pass 3: assign. */
|
|
while (list) {
|
|
while (list) {
|
|
int r;
|
|
int r;
|
|
- if ((r=config_assign_line(fmt, options, list, reset)))
|
|
|
|
|
|
+ if ((r=config_assign_line(fmt, options, list, use_defaults, clear_first)))
|
|
return r;
|
|
return r;
|
|
list = list->next;
|
|
list = list->next;
|
|
}
|
|
}
|
|
@@ -1092,12 +1139,13 @@ config_assign(config_format_t *fmt,
|
|
* keys, -2 on bad values, -3 on bad transition.
|
|
* keys, -2 on bad values, -3 on bad transition.
|
|
*/
|
|
*/
|
|
int
|
|
int
|
|
-options_trial_assign(config_line_t *list, int reset)
|
|
|
|
|
|
+options_trial_assign(config_line_t *list, int use_defaults, int clear_first)
|
|
{
|
|
{
|
|
int r;
|
|
int r;
|
|
or_options_t *trial_options = options_dup(&options_format, get_options());
|
|
or_options_t *trial_options = options_dup(&options_format, get_options());
|
|
|
|
|
|
- if ((r=config_assign(&options_format, trial_options, list, reset)) < 0) {
|
|
|
|
|
|
+ if ((r=config_assign(&options_format, trial_options,
|
|
|
|
+ list, use_defaults, clear_first)) < 0) {
|
|
config_free(&options_format, trial_options);
|
|
config_free(&options_format, trial_options);
|
|
return r;
|
|
return r;
|
|
}
|
|
}
|
|
@@ -1116,7 +1164,8 @@ options_trial_assign(config_line_t *list, int reset)
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
-/** Reset config option <b>var</b> to 0, 0.0, "", or the equivalent. */
|
|
|
|
|
|
+/** Reset config option <b>var</b> to 0, 0.0, NULL, or the equivalent.
|
|
|
|
+ * Called from option_reset() and config_free(). */
|
|
static void
|
|
static void
|
|
option_clear(config_format_t *fmt, or_options_t *options, config_var_t *var)
|
|
option_clear(config_format_t *fmt, or_options_t *options, config_var_t *var)
|
|
{
|
|
{
|
|
@@ -1158,15 +1207,19 @@ option_clear(config_format_t *fmt, or_options_t *options, config_var_t *var)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-/** Replace the option indexed by <b>var</b> in <b>options</b> with its
|
|
|
|
- * default value. */
|
|
|
|
|
|
+/** Clear the option indexed by <b>var</b> in <b>options</b>. Then if
|
|
|
|
+ * <b>use_defaults</b>, set it to its default value.
|
|
|
|
+ * Called by config_init() and option_reset_line() and option_assign_line(). */
|
|
static void
|
|
static void
|
|
-option_reset(config_format_t *fmt, or_options_t *options, config_var_t *var)
|
|
|
|
|
|
+option_reset(config_format_t *fmt, or_options_t *options,
|
|
|
|
+ config_var_t *var, int use_defaults)
|
|
{
|
|
{
|
|
config_line_t *c;
|
|
config_line_t *c;
|
|
void *lvalue;
|
|
void *lvalue;
|
|
CHECK(fmt, options);
|
|
CHECK(fmt, options);
|
|
option_clear(fmt, options, var); /* clear it first */
|
|
option_clear(fmt, options, var); /* clear it first */
|
|
|
|
+ if (!use_defaults)
|
|
|
|
+ return; /* all done */
|
|
lvalue = ((char*)options) + var->var_offset;
|
|
lvalue = ((char*)options) + var->var_offset;
|
|
if (var->initvalue) {
|
|
if (var->initvalue) {
|
|
c = tor_malloc_zero(sizeof(config_line_t));
|
|
c = tor_malloc_zero(sizeof(config_line_t));
|
|
@@ -1327,44 +1380,30 @@ static void
|
|
config_free(config_format_t *fmt, void *options)
|
|
config_free(config_format_t *fmt, void *options)
|
|
{
|
|
{
|
|
int i;
|
|
int i;
|
|
- void *lvalue;
|
|
|
|
|
|
|
|
tor_assert(options);
|
|
tor_assert(options);
|
|
|
|
|
|
- for (i=0; fmt->vars[i].name; ++i) {
|
|
|
|
- lvalue = ((char*)options) + fmt->vars[i].var_offset;
|
|
|
|
- switch (fmt->vars[i].type) {
|
|
|
|
- case CONFIG_TYPE_MEMUNIT:
|
|
|
|
- case CONFIG_TYPE_INTERVAL:
|
|
|
|
- case CONFIG_TYPE_UINT:
|
|
|
|
- case CONFIG_TYPE_BOOL:
|
|
|
|
- case CONFIG_TYPE_DOUBLE:
|
|
|
|
- case CONFIG_TYPE_ISOTIME:
|
|
|
|
- case CONFIG_TYPE_OBSOLETE:
|
|
|
|
- break; /* nothing to free for these config types */
|
|
|
|
- case CONFIG_TYPE_STRING:
|
|
|
|
- tor_free(*(char **)lvalue);
|
|
|
|
- break;
|
|
|
|
- case CONFIG_TYPE_LINELIST:
|
|
|
|
- case CONFIG_TYPE_LINELIST_V:
|
|
|
|
- config_free_lines(*(config_line_t**)lvalue);
|
|
|
|
- *(config_line_t**)lvalue = NULL;
|
|
|
|
- break;
|
|
|
|
- case CONFIG_TYPE_CSV:
|
|
|
|
- if (*(smartlist_t**)lvalue) {
|
|
|
|
- SMARTLIST_FOREACH(*(smartlist_t**)lvalue, char *, cp, tor_free(cp));
|
|
|
|
- smartlist_free(*(smartlist_t**)lvalue);
|
|
|
|
- *(smartlist_t**)lvalue = NULL;
|
|
|
|
- }
|
|
|
|
- break;
|
|
|
|
- case CONFIG_TYPE_LINELIST_S:
|
|
|
|
- /* will be freed by corresponding LINELIST_V. */
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ for (i=0; fmt->vars[i].name; ++i)
|
|
|
|
+ option_clear(fmt, options, &(fmt->vars[i]));
|
|
tor_free(options);
|
|
tor_free(options);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/** Return true iff a and b contain identical keys and values in identical
|
|
|
|
+ * order. */
|
|
|
|
+static int
|
|
|
|
+config_lines_eq(config_line_t *a, config_line_t *b)
|
|
|
|
+{
|
|
|
|
+ while (a && b) {
|
|
|
|
+ if (strcasecmp(a->key, b->key) || strcmp(a->value, b->value))
|
|
|
|
+ return 0;
|
|
|
|
+ a = a->next;
|
|
|
|
+ b = b->next;
|
|
|
|
+ }
|
|
|
|
+ if (a || b)
|
|
|
|
+ return 0;
|
|
|
|
+ return 1;
|
|
|
|
+}
|
|
|
|
+
|
|
/** Return true iff the option <b>var</b> has the same value in <b>o1</b>
|
|
/** Return true iff the option <b>var</b> has the same value in <b>o1</b>
|
|
* and <b>o2</b>. Must not be called for LINELIST_S or OBSOLETE options.
|
|
* and <b>o2</b>. Must not be called for LINELIST_S or OBSOLETE options.
|
|
*/
|
|
*/
|
|
@@ -1379,18 +1418,7 @@ option_is_same(config_format_t *fmt,
|
|
|
|
|
|
c1 = get_assigned_option(fmt, o1, name);
|
|
c1 = get_assigned_option(fmt, o1, name);
|
|
c2 = get_assigned_option(fmt, o2, name);
|
|
c2 = get_assigned_option(fmt, o2, name);
|
|
- while (c1 && c2) {
|
|
|
|
- if (strcasecmp(c1->key, c2->key) ||
|
|
|
|
- strcmp(c1->value, c2->value)) {
|
|
|
|
- r = 0;
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- c1 = c1->next;
|
|
|
|
- c2 = c2->next;
|
|
|
|
- }
|
|
|
|
- if (r && (c1 || c2)) {
|
|
|
|
- r = 0;
|
|
|
|
- }
|
|
|
|
|
|
+ r = config_lines_eq(c1, c2);
|
|
config_free_lines(c1);
|
|
config_free_lines(c1);
|
|
config_free_lines(c2);
|
|
config_free_lines(c2);
|
|
return r;
|
|
return r;
|
|
@@ -1412,7 +1440,7 @@ options_dup(config_format_t *fmt, or_options_t *old)
|
|
continue;
|
|
continue;
|
|
line = get_assigned_option(fmt, old, fmt->vars[i].name);
|
|
line = get_assigned_option(fmt, old, fmt->vars[i].name);
|
|
if (line) {
|
|
if (line) {
|
|
- if (config_assign(fmt, newopts, line, 0) < 0) {
|
|
|
|
|
|
+ if (config_assign(fmt, newopts, line, 0, 0) < 0) {
|
|
log_fn(LOG_WARN,"Bug: config_get_assigned_option() generated "
|
|
log_fn(LOG_WARN,"Bug: config_get_assigned_option() generated "
|
|
"something we couldn't config_assign().");
|
|
"something we couldn't config_assign().");
|
|
tor_assert(0);
|
|
tor_assert(0);
|
|
@@ -1450,7 +1478,7 @@ config_init(config_format_t *fmt, void *options)
|
|
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 */
|
|
- option_reset(fmt, options, var);
|
|
|
|
|
|
+ option_reset(fmt, options, var, 1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -2051,22 +2079,6 @@ options_transition_allowed(or_options_t *old, or_options_t *new_val)
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
-/** Return true iff a and b contain identical keys and values in identical
|
|
|
|
- * order. */
|
|
|
|
-static int
|
|
|
|
-config_lines_eq(config_line_t *a, config_line_t *b)
|
|
|
|
-{
|
|
|
|
- while (a && b) {
|
|
|
|
- if (strcasecmp(a->key, b->key) || strcmp(a->value, b->value))
|
|
|
|
- return 0;
|
|
|
|
- a = a->next;
|
|
|
|
- b = b->next;
|
|
|
|
- }
|
|
|
|
- if (a || b)
|
|
|
|
- return 0;
|
|
|
|
- return 1;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
/** Return 1 if any change from <b>old_options</b> to <b>new_options</b>
|
|
/** Return 1 if any change from <b>old_options</b> to <b>new_options</b>
|
|
* will require us to rotate the cpu and dns workers; else return 0. */
|
|
* will require us to rotate the cpu and dns workers; else return 0. */
|
|
static int
|
|
static int
|
|
@@ -2297,7 +2309,7 @@ options_init_from_torrc(int argc, char **argv)
|
|
tor_free(cf);
|
|
tor_free(cf);
|
|
if (retval < 0)
|
|
if (retval < 0)
|
|
goto err;
|
|
goto err;
|
|
- retval = config_assign(&options_format, newoptions, cl, 0);
|
|
|
|
|
|
+ retval = config_assign(&options_format, newoptions, cl, 0, 0);
|
|
config_free_lines(cl);
|
|
config_free_lines(cl);
|
|
if (retval < 0)
|
|
if (retval < 0)
|
|
goto err;
|
|
goto err;
|
|
@@ -2306,7 +2318,7 @@ options_init_from_torrc(int argc, char **argv)
|
|
/* Go through command-line variables too */
|
|
/* Go through command-line variables too */
|
|
if (config_get_commandlines(argc, argv, &cl) < 0)
|
|
if (config_get_commandlines(argc, argv, &cl) < 0)
|
|
goto err;
|
|
goto err;
|
|
- retval = config_assign(&options_format, newoptions, cl, 0);
|
|
|
|
|
|
+ retval = config_assign(&options_format, newoptions, cl, 0, 0);
|
|
config_free_lines(cl);
|
|
config_free_lines(cl);
|
|
if (retval < 0)
|
|
if (retval < 0)
|
|
goto err;
|
|
goto err;
|
|
@@ -3241,7 +3253,7 @@ or_state_load(void)
|
|
int assign_retval;
|
|
int assign_retval;
|
|
if (config_get_lines(contents, &lines)<0)
|
|
if (config_get_lines(contents, &lines)<0)
|
|
goto done;
|
|
goto done;
|
|
- assign_retval = config_assign(&state_format, new_state, lines, 0);
|
|
|
|
|
|
+ assign_retval = config_assign(&state_format, new_state, lines, 0, 0);
|
|
config_free_lines(lines);
|
|
config_free_lines(lines);
|
|
if (assign_retval<0)
|
|
if (assign_retval<0)
|
|
goto done;
|
|
goto done;
|