diff options
author | Nick Mathewson <nickm@torproject.org> | 2019-06-14 08:42:24 -0400 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2019-06-24 17:50:43 -0400 |
commit | c60a85d22ab87fef5a7de2fee616ad112835177b (patch) | |
tree | 246892533312b309894449df9760df7cd33a9a3e /src/app/config/confparse.c | |
parent | 5a2ab886baaa125fe715acca8f7daf35031855aa (diff) | |
download | tor-c60a85d22ab87fef5a7de2fee616ad112835177b.tar.gz tor-c60a85d22ab87fef5a7de2fee616ad112835177b.zip |
Add a "typed_var" abstraction to implement lvalue access in C.
Right now, this has been done at a high level by confparse.c, but it
makes more sense to lower it.
This API is radically un-typesafe as it stands; we'll be wrapping it
in a safer API as we do #30914 and lower the struct manipulation
code as well.
Closes ticket 30864.
Diffstat (limited to 'src/app/config/confparse.c')
-rw-r--r-- | src/app/config/confparse.c | 349 |
1 files changed, 28 insertions, 321 deletions
diff --git a/src/app/config/confparse.c b/src/app/config/confparse.c index 296e7c2a39..bc2ab24e4f 100644 --- a/src/app/config/confparse.c +++ b/src/app/config/confparse.c @@ -30,6 +30,8 @@ #include "lib/container/bitarray.h" #include "lib/encoding/confline.h" +#include "lib/confmgt/typedvar.h" + static void config_reset(const config_format_t *fmt, void *options, const config_var_t *var, int use_defaults); @@ -160,7 +162,6 @@ static int config_assign_value(const config_format_t *fmt, void *options, config_line_t *c, char **msg) { - int i, ok; const config_var_t *var; void *lvalue; @@ -168,144 +169,14 @@ config_assign_value(const config_format_t *fmt, void *options, var = config_find_option(fmt, c->key); tor_assert(var); + tor_assert(!strcmp(c->key, var->name)); lvalue = STRUCT_VAR_P(options, var->var_offset); - switch (var->type) { - - case CONFIG_TYPE_INT: - case CONFIG_TYPE_POSINT: - i = (int)tor_parse_long(c->value, 10, - var->type==CONFIG_TYPE_INT ? INT_MIN : 0, - INT_MAX, - &ok, NULL); - if (!ok) { - tor_asprintf(msg, - "Int keyword '%s %s' is malformed or out of bounds.", - c->key, c->value); - return -1; - } - *(int *)lvalue = i; - break; - - case CONFIG_TYPE_UINT64: { - uint64_t u64 = tor_parse_uint64(c->value, 10, - 0, UINT64_MAX, &ok, NULL); - if (!ok) { - tor_asprintf(msg, - "uint64 keyword '%s %s' is malformed or out of bounds.", - c->key, c->value); - return -1; - } - *(uint64_t *)lvalue = u64; - break; - } + if (var->type == CONFIG_TYPE_ROUTERSET) { + // XXXX make the backend extensible so that we don't have to + // XXXX handle ROUTERSET specially. - case CONFIG_TYPE_CSV_INTERVAL: { - /* We used to have entire smartlists here. But now that all of our - * download schedules use exponential backoff, only the first part - * matters. */ - const char *comma = strchr(c->value, ','); - const char *val = c->value; - char *tmp = NULL; - if (comma) { - tmp = tor_strndup(c->value, comma - c->value); - val = tmp; - } - - i = config_parse_interval(val, &ok); - if (!ok) { - tor_asprintf(msg, - "Interval '%s %s' is malformed or out of bounds.", - c->key, c->value); - tor_free(tmp); - return -1; - } - *(int *)lvalue = i; - tor_free(tmp); - break; - } - - case CONFIG_TYPE_INTERVAL: { - i = config_parse_interval(c->value, &ok); - if (!ok) { - tor_asprintf(msg, - "Interval '%s %s' is malformed or out of bounds.", - c->key, c->value); - return -1; - } - *(int *)lvalue = i; - break; - } - - case CONFIG_TYPE_MSEC_INTERVAL: { - i = config_parse_msec_interval(c->value, &ok); - if (!ok) { - tor_asprintf(msg, - "Msec interval '%s %s' is malformed or out of bounds.", - c->key, c->value); - return -1; - } - *(int *)lvalue = i; - break; - } - - case CONFIG_TYPE_MEMUNIT: { - uint64_t u64 = config_parse_memunit(c->value, &ok); - if (!ok) { - tor_asprintf(msg, - "Value '%s %s' is malformed or out of bounds.", - c->key, c->value); - return -1; - } - *(uint64_t *)lvalue = u64; - break; - } - - case CONFIG_TYPE_BOOL: - i = (int)tor_parse_long(c->value, 10, 0, 1, &ok, NULL); - if (!ok) { - tor_asprintf(msg, - "Boolean '%s %s' expects 0 or 1.", - c->key, c->value); - return -1; - } - *(int *)lvalue = i; - break; - - case CONFIG_TYPE_AUTOBOOL: - if (!strcasecmp(c->value, "auto")) - *(int *)lvalue = -1; - else if (!strcmp(c->value, "0")) - *(int *)lvalue = 0; - else if (!strcmp(c->value, "1")) - *(int *)lvalue = 1; - else { - tor_asprintf(msg, "Boolean '%s %s' expects 0, 1, or 'auto'.", - c->key, c->value); - return -1; - } - break; - - case CONFIG_TYPE_STRING: - case CONFIG_TYPE_FILENAME: - tor_free(*(char **)lvalue); - *(char **)lvalue = tor_strdup(c->value); - break; - - case CONFIG_TYPE_DOUBLE: - *(double *)lvalue = atof(c->value); - break; - - case CONFIG_TYPE_ISOTIME: - if (parse_iso_time(c->value, (time_t *)lvalue)) { - tor_asprintf(msg, - "Invalid time '%s' for keyword '%s'", c->value, c->key); - return -1; - } - break; - - case CONFIG_TYPE_ROUTERSET: if (*(routerset_t**)lvalue) { routerset_free(*(routerset_t**)lvalue); } @@ -315,50 +186,10 @@ config_assign_value(const config_format_t *fmt, void *options, c->value, c->key); return -1; } - break; - - case CONFIG_TYPE_CSV: - if (*(smartlist_t**)lvalue) { - SMARTLIST_FOREACH(*(smartlist_t**)lvalue, char *, cp, tor_free(cp)); - smartlist_clear(*(smartlist_t**)lvalue); - } else { - *(smartlist_t**)lvalue = smartlist_new(); - } - - smartlist_split_string(*(smartlist_t**)lvalue, c->value, ",", - SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); - break; - - case CONFIG_TYPE_LINELIST: - case CONFIG_TYPE_LINELIST_S: - { - config_line_t *lastval = *(config_line_t**)lvalue; - if (lastval && lastval->fragile) { - if (c->command != CONFIG_LINE_APPEND) { - config_free_lines(lastval); - *(config_line_t**)lvalue = NULL; - } else { - lastval->fragile = 0; - } - } - - config_line_append((config_line_t**)lvalue, c->key, c->value); - } - break; - case CONFIG_TYPE_OBSOLETE: - log_warn(LD_CONFIG, "Skipping obsolete configuration option '%s'", c->key); - break; - case CONFIG_TYPE_LINELIST_V: - tor_asprintf(msg, - "You may not provide a value for virtual option '%s'", c->key); - return -1; - // LCOV_EXCL_START - default: - tor_assert_unreached(); - break; - // LCOV_EXCL_STOP + return 0; } - return 0; + + return typed_var_kvassign(lvalue, c, msg, var->type); } /** Mark every linelist in <b>options</b> "fragile", so that fresh assignments @@ -544,100 +375,15 @@ config_get_assigned_option(const config_format_t *fmt, const void *options, } value = STRUCT_VAR_P(options, var->var_offset); - result = tor_malloc_zero(sizeof(config_line_t)); - result->key = tor_strdup(var->name); - switch (var->type) - { - case CONFIG_TYPE_STRING: - case CONFIG_TYPE_FILENAME: - if (*(char**)value) { - result->value = tor_strdup(*(char**)value); - } else { - tor_free(result->key); - tor_free(result); - return NULL; - } - break; - case CONFIG_TYPE_ISOTIME: - if (*(time_t*)value) { - result->value = tor_malloc(ISO_TIME_LEN+1); - format_iso_time(result->value, *(time_t*)value); - } else { - tor_free(result->key); - tor_free(result); - } - escape_val = 0; /* Can't need escape. */ - break; - case CONFIG_TYPE_CSV_INTERVAL: - case CONFIG_TYPE_INTERVAL: - case CONFIG_TYPE_MSEC_INTERVAL: - case CONFIG_TYPE_POSINT: - case CONFIG_TYPE_INT: - /* This means every or_options_t uint or bool element - * needs to be an int. Not, say, a uint16_t or char. */ - tor_asprintf(&result->value, "%d", *(int*)value); - escape_val = 0; /* Can't need escape. */ - break; - case CONFIG_TYPE_UINT64: /* Fall through */ - case CONFIG_TYPE_MEMUNIT: - tor_asprintf(&result->value, "%"PRIu64, - (*(uint64_t*)value)); - escape_val = 0; /* Can't need escape. */ - break; - case CONFIG_TYPE_DOUBLE: - tor_asprintf(&result->value, "%f", *(double*)value); - escape_val = 0; /* Can't need escape. */ - break; - - case CONFIG_TYPE_AUTOBOOL: - if (*(int*)value == -1) { - result->value = tor_strdup("auto"); - escape_val = 0; - break; - } - /* fall through */ - case CONFIG_TYPE_BOOL: - result->value = tor_strdup(*(int*)value ? "1" : "0"); - escape_val = 0; /* Can't need escape. */ - break; - case CONFIG_TYPE_ROUTERSET: - result->value = routerset_to_string(*(routerset_t**)value); - break; - case CONFIG_TYPE_CSV: - if (*(smartlist_t**)value) - result->value = - smartlist_join_strings(*(smartlist_t**)value, ",", 0, NULL); - else - result->value = tor_strdup(""); - break; - case CONFIG_TYPE_OBSOLETE: - log_fn(LOG_INFO, LD_CONFIG, - "You asked me for the value of an obsolete config option '%s'.", - key); - tor_free(result->key); - tor_free(result); - return NULL; - case CONFIG_TYPE_LINELIST_S: - tor_free(result->key); - tor_free(result); - result = config_lines_dup_and_filter(*(const config_line_t **)value, - key); - break; - case CONFIG_TYPE_LINELIST: - case CONFIG_TYPE_LINELIST_V: - tor_free(result->key); - tor_free(result); - result = config_lines_dup(*(const config_line_t**)value); - break; - // LCOV_EXCL_START - default: - tor_free(result->key); - tor_free(result); - log_warn(LD_BUG,"Unknown type %d for known key '%s'", - var->type, key); - return NULL; - // LCOV_EXCL_STOP - } + if (var->type == CONFIG_TYPE_ROUTERSET) { + // XXXX make the backend extensible so that we don't have to + // XXXX handle ROUTERSET specially. + result = tor_malloc_zero(sizeof(config_line_t)); + result->key = tor_strdup(var->name); + result->value = routerset_to_string(*(routerset_t**)value); + } else { + result = typed_var_kvencode(var->name, value, var->type); + } if (escape_val) { config_line_t *line; @@ -765,56 +511,17 @@ config_clear(const config_format_t *fmt, void *options, { void *lvalue = STRUCT_VAR_P(options, var->var_offset); (void)fmt; /* unused */ - switch (var->type) { - case CONFIG_TYPE_STRING: - case CONFIG_TYPE_FILENAME: - tor_free(*(char**)lvalue); - break; - case CONFIG_TYPE_DOUBLE: - *(double*)lvalue = 0.0; - break; - case CONFIG_TYPE_ISOTIME: - *(time_t*)lvalue = 0; - break; - case CONFIG_TYPE_CSV_INTERVAL: - case CONFIG_TYPE_INTERVAL: - case CONFIG_TYPE_MSEC_INTERVAL: - case CONFIG_TYPE_POSINT: - case CONFIG_TYPE_INT: - case CONFIG_TYPE_BOOL: - *(int*)lvalue = 0; - break; - case CONFIG_TYPE_AUTOBOOL: - *(int*)lvalue = -1; - break; - case CONFIG_TYPE_UINT64: - case CONFIG_TYPE_MEMUNIT: - *(uint64_t*)lvalue = 0; - break; - case CONFIG_TYPE_ROUTERSET: - if (*(routerset_t**)lvalue) { - routerset_free(*(routerset_t**)lvalue); - *(routerset_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: - case CONFIG_TYPE_LINELIST_S: - config_free_lines(*(config_line_t **)lvalue); - *(config_line_t **)lvalue = NULL; - break; - case CONFIG_TYPE_LINELIST_V: - /* handled by linelist_s. */ - break; - case CONFIG_TYPE_OBSOLETE: - break; + 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); } /** Clear the option indexed by <b>var</b> in <b>options</b>. Then if |