Nick Mathewson 15 лет назад
Родитель
Сommit
9265190b16
3 измененных файлов с 38 добавлено и 3 удалено
  1. 5 0
      changes/bug1384
  2. 2 1
      doc/tor.1.txt
  3. 31 2
      src/or/config.c

+ 5 - 0
changes/bug1384

@@ -0,0 +1,5 @@
+  o Minor features:
+    - Warn when the same option is provided more then once in a torrc file,
+      on the command line, or in a single SETCONF statement, and option
+      is one that only accepts a single value. Closes bug 1384.
+

+ 2 - 1
doc/tor.1.txt

@@ -64,7 +64,8 @@ OPTIONS
 Other options can be specified either on the command-line (--option
     value), or in the configuration file (option value or option "value").
     Options are case-insensitive. C-style escaped characters are allowed inside
-    quoted values.
+    quoted values.   Options on the command line take precedence over
+    options found in the configuration file.
 
 **BandwidthRate** __N__ **bytes**|**KB**|**MB**|**GB**::
     A token bucket limits the average incoming bandwidth usage on this node to

+ 31 - 2
src/or/config.c

@@ -1562,6 +1562,16 @@ config_find_option(config_format_t *fmt, const char *key)
   return NULL;
 }
 
+/** Return the number of option entries in <b>fmt</b>. */
+static int
+config_count_options(config_format_t *fmt)
+{
+  int i;
+  for (i=0; fmt->vars[i].name; ++i)
+    ;
+  return i;
+}
+
 /*
  * Functions to assign config options.
  */
@@ -1706,7 +1716,7 @@ config_assign_value(config_format_t *fmt, or_options_t *options,
 static int
 config_assign_line(config_format_t *fmt, or_options_t *options,
                    config_line_t *c, int use_defaults,
-                   int clear_first, char **msg)
+                   int clear_first, bitarray_t *options_seen, char **msg)
 {
   config_var_t *var;
 
@@ -1726,6 +1736,7 @@ config_assign_line(config_format_t *fmt, or_options_t *options,
       return -1;
     }
   }
+
   /* Put keyword into canonical case. */
   if (strcmp(var->name, c->key)) {
     tor_free(c->key);
@@ -1748,6 +1759,18 @@ config_assign_line(config_format_t *fmt, or_options_t *options,
     return 0;
   }
 
+  if (options_seen && (var->type != CONFIG_TYPE_LINELIST &&
+                       var->type != CONFIG_TYPE_LINELIST_S)) {
+    /* We're tracking which options we've seen, and this option is not
+     * supposed to occur more than once. */
+    int var_index = (int)(var - fmt->vars);
+    if (bitarray_is_set(options_seen, var_index)) {
+      log_warn(LD_CONFIG, "Option '%s' used more than once; all but the last "
+               "value will be ignored.", var->name);
+    }
+    bitarray_set(options_seen, var_index);
+  }
+
   if (config_assign_value(fmt, options, c, msg) < 0)
     return -2;
   return 0;
@@ -2016,6 +2039,8 @@ config_assign(config_format_t *fmt, void *options, config_line_t *list,
               int use_defaults, int clear_first, char **msg)
 {
   config_line_t *p;
+  bitarray_t *options_seen;
+  const int n_options = config_count_options(fmt);
 
   CHECK(fmt, options);
 
@@ -2035,14 +2060,18 @@ config_assign(config_format_t *fmt, void *options, config_line_t *list,
       config_reset_line(fmt, 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, use_defaults,
-                              clear_first, msg)))
+                              clear_first, options_seen, msg))) {
+      bitarray_free(options_seen);
       return r;
+    }
     list = list->next;
   }
+  bitarray_free(options_seen);
   return 0;
 }