Browse Source

Retain unrecognized options in state file, so that we can be forward-compatible.

svn:r5985
Nick Mathewson 19 years ago
parent
commit
e7b2d5cd47
3 changed files with 55 additions and 13 deletions
  1. 1 1
      doc/TODO
  2. 52 12
      src/or/config.c
  3. 2 0
      src/or/or.h

+ 1 - 1
doc/TODO

@@ -59,7 +59,7 @@ R   - Clients use it. (But not till the directories have upgraded!)
   - make log entries include function names in win32 again.
   - make log entries include function names in win32 again.
   - Make "setconf" and "hup" behavior cleaner for LINELIST config
   - Make "setconf" and "hup" behavior cleaner for LINELIST config
     options (e.g. Log). Bug 238.
     options (e.g. Log). Bug 238.
-  - Were we going to load unrecognized 'state' variables into some
+  o Were we going to load unrecognized 'state' variables into some
     list somewhere, and write them out whenever we update the state?
     list somewhere, and write them out whenever we update the state?
     To be forwards and backwards compatible.
     To be forwards and backwards compatible.
 R - streamline how we define a guard node as 'up'. document it
 R - streamline how we define a guard node as 'up'. document it

+ 52 - 12
src/or/config.c

@@ -102,6 +102,10 @@ typedef struct config_var_t {
 /** Return the offset of <b>member</b> within the type <b>tp</b>, in bytes */
 /** Return the offset of <b>member</b> within the type <b>tp</b>, in bytes */
 #define STRUCT_OFFSET(tp, member) \
 #define STRUCT_OFFSET(tp, member) \
   ((off_t) (((char*)&((tp*)0)->member)-(char*)0))
   ((off_t) (((char*)&((tp*)0)->member)-(char*)0))
+
+#define STRUCT_VAR_P(st, off) \
+  ((void*) ( ((char*)st) + off ) )
+
 /** An entry for config_vars: "The option <b>name</b> has type
 /** An entry for config_vars: "The option <b>name</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>"
@@ -313,12 +317,14 @@ typedef struct {
   config_var_t *vars;
   config_var_t *vars;
   validate_fn_t validate_fn;
   validate_fn_t validate_fn;
   config_var_description_t *descriptions;
   config_var_description_t *descriptions;
+  config_var_t *extra; /**< If present, a LINELIST variable for unrecognized
+                        * lines.  Otherwise, unrecognized lines are an error. */
 } config_format_t;
 } config_format_t;
 
 
 #define CHECK(fmt, cfg) do {                                            \
 #define CHECK(fmt, cfg) do {                                            \
     tor_assert(fmt && cfg);                                             \
     tor_assert(fmt && cfg);                                             \
     tor_assert((fmt)->magic ==                                          \
     tor_assert((fmt)->magic ==                                          \
-               *(uint32_t*)(((char*)(cfg))+fmt->magic_offset));         \
+               *(uint32_t*)STRUCT_VAR_P(cfg,fmt->magic_offset));        \
   } while (0)
   } while (0)
 
 
 /** Largest allowed config line */
 /** Largest allowed config line */
@@ -389,11 +395,16 @@ static config_format_t options_format = {
   _option_abbrevs,
   _option_abbrevs,
   _option_vars,
   _option_vars,
   (validate_fn_t)options_validate,
   (validate_fn_t)options_validate,
-  options_description
+  options_description,
+  NULL
 };
 };
 
 
 #define OR_STATE_MAGIC 0x57A73f57
 #define OR_STATE_MAGIC 0x57A73f57
 
 
+static config_var_t state_extra_var = {
+  "__extra", CONFIG_TYPE_LINELIST, STRUCT_OFFSET(or_state_t, ExtraLines), NULL
+};
+
 static config_format_t state_format = {
 static config_format_t state_format = {
   sizeof(or_state_t),
   sizeof(or_state_t),
   OR_STATE_MAGIC,
   OR_STATE_MAGIC,
@@ -401,7 +412,8 @@ static config_format_t state_format = {
   _state_abbrevs,
   _state_abbrevs,
   _state_vars,
   _state_vars,
   (validate_fn_t)or_state_validate,
   (validate_fn_t)or_state_validate,
-  state_description
+  state_description,
+  &state_extra_var,
 };
 };
 
 
 /*
 /*
@@ -421,7 +433,7 @@ static void *
 config_alloc(config_format_t *fmt)
 config_alloc(config_format_t *fmt)
 {
 {
   void *opts = opts = tor_malloc_zero(fmt->size);
   void *opts = opts = tor_malloc_zero(fmt->size);
-  *(uint32_t*)(((char*)opts)+fmt->magic_offset) = fmt->magic;
+  *(uint32_t*)STRUCT_VAR_P(opts, fmt->magic_offset) = fmt->magic;
   CHECK(fmt, opts);
   CHECK(fmt, opts);
   return opts;
   return opts;
 }
 }
@@ -977,7 +989,7 @@ config_assign_value(config_format_t *fmt, or_options_t *options,
   var = config_find_option(fmt, c->key);
   var = config_find_option(fmt, c->key);
   tor_assert(var);
   tor_assert(var);
 
 
-  lvalue = ((char*)options) + var->var_offset;
+  lvalue = STRUCT_VAR_P(options, var->var_offset);
 
 
   switch (var->type) {
   switch (var->type) {
 
 
@@ -1085,8 +1097,15 @@ config_assign_line(config_format_t *fmt, or_options_t *options,
 
 
   var = config_find_option(fmt, c->key);
   var = config_find_option(fmt, c->key);
   if (!var) {
   if (!var) {
-    warn(LD_CONFIG, "Unknown option '%s'.  Failing.", c->key);
-    return -1;
+    if (fmt->extra) {
+      void *lvalue = STRUCT_VAR_P(options, fmt->extra->var_offset);
+      info(LD_CONFIG, "Found unrecognized option '%s'; saving it.", c->key);
+      config_line_append((config_line_t**)lvalue, c->key, c->value);
+      return 0;
+    } else {
+      warn(LD_CONFIG, "Unknown option '%s'.  Failing.", c->key);
+      return -1;
+    }
   }
   }
   /* Put keyword into canonical case. */
   /* Put keyword into canonical case. */
   if (strcmp(var->name, c->key)) {
   if (strcmp(var->name, c->key)) {
@@ -1183,7 +1202,7 @@ get_assigned_option(config_format_t *fmt, or_options_t *options,
          "Can't return context-sensitive '%s' on its own", key);
          "Can't return context-sensitive '%s' on its own", key);
     return NULL;
     return NULL;
   }
   }
-  value = ((char*)options) + var->var_offset;
+  value = STRUCT_VAR_P(options, var->var_offset);
 
 
   if (var->type == CONFIG_TYPE_LINELIST ||
   if (var->type == CONFIG_TYPE_LINELIST ||
       var->type == CONFIG_TYPE_LINELIST_V) {
       var->type == CONFIG_TYPE_LINELIST_V) {
@@ -1385,7 +1404,7 @@ options_trial_assign(config_line_t *list, int use_defaults, int clear_first)
 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)
 {
 {
-  void *lvalue = ((char*)options) + var->var_offset;
+  void *lvalue = STRUCT_VAR_P(options, var->var_offset);
   switch (var->type) {
   switch (var->type) {
     case CONFIG_TYPE_STRING:
     case CONFIG_TYPE_STRING:
       tor_free(*(char**)lvalue);
       tor_free(*(char**)lvalue);
@@ -1436,7 +1455,7 @@ option_reset(config_format_t *fmt, or_options_t *options,
   option_clear(fmt, options, var); /* clear it first */
   option_clear(fmt, options, var); /* clear it first */
   if (!use_defaults)
   if (!use_defaults)
     return; /* all done */
     return; /* all done */
-  lvalue = ((char*)options) + var->var_offset;
+  lvalue = STRUCT_VAR_P(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));
     c->key = tor_strdup(var->name);
     c->key = tor_strdup(var->name);
@@ -1588,6 +1607,11 @@ config_free(config_format_t *fmt, void *options)
 
 
   for (i=0; fmt->vars[i].name; ++i)
   for (i=0; fmt->vars[i].name; ++i)
     option_clear(fmt, options, &(fmt->vars[i]));
     option_clear(fmt, options, &(fmt->vars[i]));
+  if (fmt->extra) {
+    config_line_t **linep = STRUCT_VAR_P(options, fmt->extra->var_offset);
+    config_free_lines(*linep);
+    *linep = NULL;
+  }
   tor_free(options);
   tor_free(options);
 }
 }
 
 
@@ -1728,7 +1752,7 @@ config_dump(config_format_t *fmt, void *options, int minimal)
       char *tmp;
       char *tmp;
       tmp = tor_malloc(len);
       tmp = tor_malloc(len);
       if (tor_snprintf(tmp, len, "%s %s\n", line->key, line->value)<0) {
       if (tor_snprintf(tmp, len, "%s %s\n", line->key, line->value)<0) {
-        err(LD_BUG,"Internal error writing log option");
+        err(LD_BUG,"Internal error writing option value");
         tor_assert(0);
         tor_assert(0);
       }
       }
       smartlist_add(elements, tmp);
       smartlist_add(elements, tmp);
@@ -1736,6 +1760,20 @@ config_dump(config_format_t *fmt, void *options, int minimal)
     config_free_lines(assigned);
     config_free_lines(assigned);
   }
   }
 
 
+  if (fmt->extra) {
+    line = *(config_line_t**)STRUCT_VAR_P(options, fmt->extra->var_offset);
+    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) {
+        err(LD_BUG,"Internal error writing option value");
+        tor_assert(0);
+      }
+      smartlist_add(elements, tmp);
+    }
+  }
+
   result = smartlist_join_strings(elements, "", 0, NULL);
   result = smartlist_join_strings(elements, "", 0, NULL);
   SMARTLIST_FOREACH(elements, char *, cp, tor_free(cp));
   SMARTLIST_FOREACH(elements, char *, cp, tor_free(cp));
   smartlist_free(elements);
   smartlist_free(elements);
@@ -1855,7 +1893,9 @@ options_validate(or_options_t *old_options, or_options_t *options,
        !strcmpstart(uname, "Windows 98") ||
        !strcmpstart(uname, "Windows 98") ||
        !strcmpstart(uname, "Windows Me"))) {
        !strcmpstart(uname, "Windows Me"))) {
     log(LOG_WARN, LD_CONFIG, "Tor is running as a server, but you are "
     log(LOG_WARN, LD_CONFIG, "Tor is running as a server, but you are "
-        "running %s; this probably won't work. See http://wiki.noreply.org/noreply/TheOnionRouter/TorFAQ#ServerOS for details.", get_uname());
+        "running %s; this probably won't work. See "
+        "http://wiki.noreply.org/noreply/TheOnionRouter/TorFAQ#ServerOS "
+        "for details.", get_uname());
   }
   }
 
 
   if (options->ORPort == 0 && options->ORListenAddress != NULL)
   if (options->ORPort == 0 && options->ORListenAddress != NULL)

+ 2 - 0
src/or/or.h

@@ -1398,6 +1398,8 @@ typedef struct {
   smartlist_t *BWHistoryWriteValues;
   smartlist_t *BWHistoryWriteValues;
 
 
   char *TorVersion;
   char *TorVersion;
+
+  config_line_t *ExtraLines;
 } or_state_t;
 } or_state_t;
 
 
 #define MAX_SOCKS_REPLY_LEN 1024
 #define MAX_SOCKS_REPLY_LEN 1024