diff --git a/doc/TODO b/doc/TODO index 7147a8ab47..cc74630274 100644 --- a/doc/TODO +++ b/doc/TODO @@ -53,7 +53,10 @@ ARMA - arma claims o stop calling a *_policy an exit_policy_t - Regenerate our server descriptor when a relevant option is changed from control.c. - - Writing out the machine-readable torrc file + . Writing out the machine-readable torrc file + o Function to check whether an option has changed. + o Function to generate the contents for a torrc file. + - Function to safely replace a torrc file. - fix print_usage() - Download and use running-routers - document signals in man page diff --git a/src/or/config.c b/src/or/config.c index dadaadbad9..dc1816a0a9 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -160,6 +160,8 @@ static config_var_t config_vars[] = { static void option_reset(or_options_t *options, config_var_t *var); static void options_free(or_options_t *options); +static int option_is_same(or_options_t *o1, or_options_t *o2, + config_var_t *var); static or_options_t *options_dup(or_options_t *old); static int options_validate(or_options_t *options); static int options_transition_allowed(or_options_t *old, or_options_t *new); @@ -311,6 +313,18 @@ options_act(void) { return -1; } +#if 0 + { + char *smin, *smax; + smin = config_dump_options(options, 1); + smax = config_dump_options(options, 0); + log_fn(LOG_DEBUG, "These are our options:\n%s",smax); + log_fn(LOG_DEBUG, "We changed these options:\n%s",smin); + tor_free(smin); + tor_free(smax); + } +#endif + return 0; } @@ -938,6 +952,71 @@ options_free(or_options_t *options) } } +/** Return true iff the option var has the same value in o1 + * and o2. Must not be called for LINELIST_S or OBSOLETE options. + */ +static int +option_is_same(or_options_t *o1, or_options_t *o2, config_var_t *var) +{ + void *v1, *v2; + tor_assert(o1); + tor_assert(o2); + tor_assert(var); + + v1 = ((char*)o1) + var-> var_offset; + v2 = ((char*)o2) + var-> var_offset; + switch (var->type) + { + case CONFIG_TYPE_UINT: + case CONFIG_TYPE_BOOL: + return (*(int*)v1) == (*(int*)v2); + case CONFIG_TYPE_STRING: { + const char *s1 = *(const char**)v1; + const char *s2 = *(const char**)v2; + return (!s1 && !s2) || (s1 && s2 && !strcmp(s1, s2)); + } + case CONFIG_TYPE_DOUBLE: + return (*(double*)v1) == (*(double*)v2); + case CONFIG_TYPE_CSV: { + smartlist_t *sl1 = *(smartlist_t**)v1; + smartlist_t *sl2 = *(smartlist_t**)v2; + int i; + if ((sl1 && !sl2) || (!sl1 && sl2)) + return 0; + else if (!sl1 && !sl2) + return 1; + else if (smartlist_len(sl1) != smartlist_len(sl2)) + return 0; + for (i=0;ikey,cl2->key) || strcmp(cl1->value,cl2->value)) + return 0; + cl1 = cl1->next; + cl2 = cl2->next; + } + if (!cl1 && !cl2) + return 1; + else + return 0; + } + case CONFIG_TYPE_LINELIST_S: + case CONFIG_TYPE_OBSOLETE: + default: + log_fn(LOG_ERR,"Internal error: can't compare configuration option '%s'", + var->name); + tor_assert(0); + } +} + /** Copy storage held by old into a new or_options_t and return it. */ static or_options_t * options_dup(or_options_t *old) @@ -981,6 +1060,50 @@ options_init(or_options_t *options) } } +/** Return a string containing a possible configuration file that would give + * the configuration in options. If minimal is true, do not + * include options that are the same as Tor's defaults. + */ +char * +config_dump_options(or_options_t *options, int minimal) +{ + smartlist_t *elements; + or_options_t *defaults; + struct config_line_t *line; + char *result; + int i; + + defaults = tor_malloc_zero(sizeof(or_options_t)); + options_init(defaults); + options_validate(defaults); /* ??? will this work? */ + + elements = smartlist_create(); + for (i=0; config_vars[i].name; ++i) { + if (config_vars[i].type == CONFIG_TYPE_OBSOLETE || + config_vars[i].type == CONFIG_TYPE_LINELIST_S) + continue; + if (minimal && option_is_same(options, defaults, &config_vars[i])) + continue; + line = config_get_assigned_option(options, config_vars[i].name); + for (; line; line = line->next) { + size_t len = strlen(line->key) + strlen(line->value) + 3; + char *tmp; + tmp = tor_malloc(len); + if (tor_snprintf(tmp, len, "%s %s\n", line->key, line->value)<0) { + log_fn(LOG_ERR, "Internal error writing log option"); + tor_assert(0); + } + smartlist_add(elements, tmp); + } + config_free_lines(line); + } + + result = smartlist_join_strings(elements, "", 0, NULL); + SMARTLIST_FOREACH(elements, char *, cp, tor_free(cp)); + smartlist_free(elements); + return result; +} + /** Return 0 if every setting in options is reasonable. Else * warn and return -1. Should have no side effects, except for * normalizing the contents of options. */ diff --git a/src/or/or.h b/src/or/or.h index dcd38e8ccc..35a4879211 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -1116,6 +1116,7 @@ struct config_line_t *config_get_assigned_option(or_options_t *options, const char *key); struct config_line_t *config_line_prepend(struct config_line_t *front, const char *key, const char *val); +char *config_dump_options(or_options_t *options, int minimal); /********************************* connection.c ***************************/