tor  0.4.0.1-alpha
confparse.c
Go to the documentation of this file.
1 /* Copyright (c) 2001 Matej Pfajfar.
2  * Copyright (c) 2001-2004, Roger Dingledine.
3  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
4  * Copyright (c) 2007-2019, The Tor Project, Inc. */
5 /* See LICENSE for licensing information */
6 
24 #include "core/or/or.h"
25 #include "app/config/confparse.h"
26 #include "feature/nodelist/routerset.h"
27 
28 #include "lib/container/bitarray.h"
29 #include "lib/encoding/confline.h"
30 
31 static uint64_t config_parse_memunit(const char *s, int *ok);
32 static int config_parse_msec_interval(const char *s, int *ok);
33 static int config_parse_interval(const char *s, int *ok);
34 static void config_reset(const config_format_t *fmt, void *options,
35  const config_var_t *var, int use_defaults);
36 
38 void *
40 {
41  void *opts = tor_malloc_zero(fmt->size);
42  *(uint32_t*)STRUCT_VAR_P(opts, fmt->magic_offset) = fmt->magic;
43  CONFIG_CHECK(fmt, opts);
44  return opts;
45 }
46 
47 /*
48  * Functions to parse config options
49  */
50 
56 const char *
57 config_expand_abbrev(const config_format_t *fmt, const char *option,
58  int command_line, int warn_obsolete)
59 {
60  int i;
61  if (! fmt->abbrevs)
62  return option;
63  for (i=0; fmt->abbrevs[i].abbreviated; ++i) {
64  /* Abbreviations are case insensitive. */
65  if (!strcasecmp(option,fmt->abbrevs[i].abbreviated) &&
66  (command_line || !fmt->abbrevs[i].commandline_only)) {
67  if (warn_obsolete && fmt->abbrevs[i].warn) {
68  log_warn(LD_CONFIG,
69  "The configuration option '%s' is deprecated; "
70  "use '%s' instead.",
71  fmt->abbrevs[i].abbreviated,
72  fmt->abbrevs[i].full);
73  }
74  /* Keep going through the list in case we want to rewrite it more.
75  * (We could imagine recursing here, but I don't want to get the
76  * user into an infinite loop if we craft our list wrong.) */
77  option = fmt->abbrevs[i].full;
78  }
79  }
80  return option;
81 }
82 
86 const char *
87 config_find_deprecation(const config_format_t *fmt, const char *key)
88 {
89  if (BUG(fmt == NULL) || BUG(key == NULL))
90  return NULL;
91  if (fmt->deprecations == NULL)
92  return NULL;
93 
94  const config_deprecation_t *d;
95  for (d = fmt->deprecations; d->name; ++d) {
96  if (!strcasecmp(d->name, key)) {
97  return d->why_deprecated ? d->why_deprecated : "";
98  }
99  }
100  return NULL;
101 }
102 
104 config_var_t *
106 {
107  int i;
108  size_t keylen = strlen(key);
109  if (!keylen)
110  return NULL; /* if they say "--" on the command line, it's not an option */
111  /* First, check for an exact (case-insensitive) match */
112  for (i=0; fmt->vars[i].name; ++i) {
113  if (!strcasecmp(key, fmt->vars[i].name)) {
114  return &fmt->vars[i];
115  }
116  }
117  /* If none, check for an abbreviated match */
118  for (i=0; fmt->vars[i].name; ++i) {
119  if (!strncasecmp(key, fmt->vars[i].name, keylen)) {
120  log_warn(LD_CONFIG, "The abbreviation '%s' is deprecated. "
121  "Please use '%s' instead",
122  key, fmt->vars[i].name);
123  return &fmt->vars[i];
124  }
125  }
126  /* Okay, unrecognized option */
127  return NULL;
128 }
129 
135 const config_var_t *
136 config_find_option(const config_format_t *fmt, const char *key)
137 {
138  return config_find_option_mutable((config_format_t*)fmt, key);
139 }
140 
142 static int
144 {
145  int i;
146  for (i=0; fmt->vars[i].name; ++i)
147  ;
148  return i;
149 }
150 
151 /*
152  * Functions to assign config options.
153  */
154 
160 static int
161 config_assign_value(const config_format_t *fmt, void *options,
162  config_line_t *c, char **msg)
163 {
164  int i, ok;
165  const config_var_t *var;
166  void *lvalue;
167 
168  CONFIG_CHECK(fmt, options);
169 
170  var = config_find_option(fmt, c->key);
171  tor_assert(var);
172 
173  lvalue = STRUCT_VAR_P(options, var->var_offset);
174 
175  switch (var->type) {
176 
177  case CONFIG_TYPE_PORT:
178  if (!strcasecmp(c->value, "auto")) {
179  *(int *)lvalue = CFG_AUTO_PORT;
180  break;
181  }
182  /* fall through */
183  case CONFIG_TYPE_INT:
184  case CONFIG_TYPE_UINT:
185  i = (int)tor_parse_long(c->value, 10,
186  var->type==CONFIG_TYPE_INT ? INT_MIN : 0,
187  var->type==CONFIG_TYPE_PORT ? 65535 : INT_MAX,
188  &ok, NULL);
189  if (!ok) {
190  tor_asprintf(msg,
191  "Int keyword '%s %s' is malformed or out of bounds.",
192  c->key, c->value);
193  return -1;
194  }
195  *(int *)lvalue = i;
196  break;
197 
198  case CONFIG_TYPE_UINT64: {
199  uint64_t u64 = tor_parse_uint64(c->value, 10,
200  0, UINT64_MAX, &ok, NULL);
201  if (!ok) {
202  tor_asprintf(msg,
203  "uint64 keyword '%s %s' is malformed or out of bounds.",
204  c->key, c->value);
205  return -1;
206  }
207  *(uint64_t *)lvalue = u64;
208  break;
209  }
210 
212  /* We used to have entire smartlists here. But now that all of our
213  * download schedules use exponential backoff, only the first part
214  * matters. */
215  const char *comma = strchr(c->value, ',');
216  const char *val = c->value;
217  char *tmp = NULL;
218  if (comma) {
219  tmp = tor_strndup(c->value, comma - c->value);
220  val = tmp;
221  }
222 
223  i = config_parse_interval(val, &ok);
224  if (!ok) {
225  tor_asprintf(msg,
226  "Interval '%s %s' is malformed or out of bounds.",
227  c->key, c->value);
228  return -1;
229  }
230  *(int *)lvalue = i;
231  tor_free(tmp);
232  break;
233  }
234 
235  case CONFIG_TYPE_INTERVAL: {
236  i = config_parse_interval(c->value, &ok);
237  if (!ok) {
238  tor_asprintf(msg,
239  "Interval '%s %s' is malformed or out of bounds.",
240  c->key, c->value);
241  return -1;
242  }
243  *(int *)lvalue = i;
244  break;
245  }
246 
248  i = config_parse_msec_interval(c->value, &ok);
249  if (!ok) {
250  tor_asprintf(msg,
251  "Msec interval '%s %s' is malformed or out of bounds.",
252  c->key, c->value);
253  return -1;
254  }
255  *(int *)lvalue = i;
256  break;
257  }
258 
259  case CONFIG_TYPE_MEMUNIT: {
260  uint64_t u64 = config_parse_memunit(c->value, &ok);
261  if (!ok) {
262  tor_asprintf(msg,
263  "Value '%s %s' is malformed or out of bounds.",
264  c->key, c->value);
265  return -1;
266  }
267  *(uint64_t *)lvalue = u64;
268  break;
269  }
270 
271  case CONFIG_TYPE_BOOL:
272  i = (int)tor_parse_long(c->value, 10, 0, 1, &ok, NULL);
273  if (!ok) {
274  tor_asprintf(msg,
275  "Boolean '%s %s' expects 0 or 1.",
276  c->key, c->value);
277  return -1;
278  }
279  *(int *)lvalue = i;
280  break;
281 
283  if (!strcasecmp(c->value, "auto"))
284  *(int *)lvalue = -1;
285  else if (!strcmp(c->value, "0"))
286  *(int *)lvalue = 0;
287  else if (!strcmp(c->value, "1"))
288  *(int *)lvalue = 1;
289  else {
290  tor_asprintf(msg, "Boolean '%s %s' expects 0, 1, or 'auto'.",
291  c->key, c->value);
292  return -1;
293  }
294  break;
295 
296  case CONFIG_TYPE_STRING:
298  tor_free(*(char **)lvalue);
299  *(char **)lvalue = tor_strdup(c->value);
300  break;
301 
302  case CONFIG_TYPE_DOUBLE:
303  *(double *)lvalue = atof(c->value);
304  break;
305 
306  case CONFIG_TYPE_ISOTIME:
307  if (parse_iso_time(c->value, (time_t *)lvalue)) {
308  tor_asprintf(msg,
309  "Invalid time '%s' for keyword '%s'", c->value, c->key);
310  return -1;
311  }
312  break;
313 
315  if (*(routerset_t**)lvalue) {
316  routerset_free(*(routerset_t**)lvalue);
317  }
318  *(routerset_t**)lvalue = routerset_new();
319  if (routerset_parse(*(routerset_t**)lvalue, c->value, c->key)<0) {
320  tor_asprintf(msg, "Invalid exit list '%s' for option '%s'",
321  c->value, c->key);
322  return -1;
323  }
324  break;
325 
326  case CONFIG_TYPE_CSV:
327  if (*(smartlist_t**)lvalue) {
328  SMARTLIST_FOREACH(*(smartlist_t**)lvalue, char *, cp, tor_free(cp));
329  smartlist_clear(*(smartlist_t**)lvalue);
330  } else {
331  *(smartlist_t**)lvalue = smartlist_new();
332  }
333 
334  smartlist_split_string(*(smartlist_t**)lvalue, c->value, ",",
335  SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
336  break;
337 
340  {
341  config_line_t *lastval = *(config_line_t**)lvalue;
342  if (lastval && lastval->fragile) {
343  if (c->command != CONFIG_LINE_APPEND) {
344  config_free_lines(lastval);
345  *(config_line_t**)lvalue = NULL;
346  } else {
347  lastval->fragile = 0;
348  }
349  }
350 
351  config_line_append((config_line_t**)lvalue, c->key, c->value);
352  }
353  break;
355  log_warn(LD_CONFIG, "Skipping obsolete configuration option '%s'", c->key);
356  break;
358  tor_asprintf(msg,
359  "You may not provide a value for virtual option '%s'", c->key);
360  return -1;
361  default:
362  tor_assert(0);
363  break;
364  }
365  return 0;
366 }
367 
370 static void
371 config_mark_lists_fragile(const config_format_t *fmt, void *options)
372 {
373  int i;
374  tor_assert(fmt);
375  tor_assert(options);
376 
377  for (i = 0; fmt->vars[i].name; ++i) {
378  const config_var_t *var = &fmt->vars[i];
380  if (var->type != CONFIG_TYPE_LINELIST &&
382  continue;
383 
384  list = *(config_line_t **)STRUCT_VAR_P(options, var->var_offset);
385  if (list)
386  list->fragile = 1;
387  }
388 }
389 
390 void
391 warn_deprecated_option(const char *what, const char *why)
392 {
393  const char *space = (why && strlen(why)) ? " " : "";
394  log_warn(LD_CONFIG, "The %s option is deprecated, and will most likely "
395  "be removed in a future version of Tor.%s%s (If you think this is "
396  "a mistake, please let us know!)",
397  what, space, why);
398 }
399 
409 static int
410 config_assign_line(const config_format_t *fmt, void *options,
411  config_line_t *c, unsigned flags,
412  bitarray_t *options_seen, char **msg)
413 {
414  const unsigned use_defaults = flags & CAL_USE_DEFAULTS;
415  const unsigned clear_first = flags & CAL_CLEAR_FIRST;
416  const unsigned warn_deprecations = flags & CAL_WARN_DEPRECATIONS;
417  const config_var_t *var;
418 
419  CONFIG_CHECK(fmt, options);
420 
421  var = config_find_option(fmt, c->key);
422  if (!var) {
423  if (fmt->extra) {
424  void *lvalue = STRUCT_VAR_P(options, fmt->extra->var_offset);
425  log_info(LD_CONFIG,
426  "Found unrecognized option '%s'; saving it.", c->key);
427  config_line_append((config_line_t**)lvalue, c->key, c->value);
428  return 0;
429  } else {
430  tor_asprintf(msg,
431  "Unknown option '%s'. Failing.", c->key);
432  return -1;
433  }
434  }
435 
436  /* Put keyword into canonical case. */
437  if (strcmp(var->name, c->key)) {
438  tor_free(c->key);
439  c->key = tor_strdup(var->name);
440  }
441 
442  const char *deprecation_msg;
443  if (warn_deprecations &&
444  (deprecation_msg = config_find_deprecation(fmt, var->name))) {
445  warn_deprecated_option(var->name, deprecation_msg);
446  }
447 
448  if (!strlen(c->value)) {
449  /* reset or clear it, then return */
450  if (!clear_first) {
451  if ((var->type == CONFIG_TYPE_LINELIST ||
452  var->type == CONFIG_TYPE_LINELIST_S) &&
453  c->command != CONFIG_LINE_CLEAR) {
454  /* We got an empty linelist from the torrc or command line.
455  As a special case, call this an error. Warn and ignore. */
456  log_warn(LD_CONFIG,
457  "Linelist option '%s' has no value. Skipping.", c->key);
458  } else { /* not already cleared */
459  config_reset(fmt, options, var, use_defaults);
460  }
461  }
462  return 0;
463  } else if (c->command == CONFIG_LINE_CLEAR && !clear_first) {
464  config_reset(fmt, options, var, use_defaults);
465  }
466 
467  if (options_seen && (var->type != CONFIG_TYPE_LINELIST &&
468  var->type != CONFIG_TYPE_LINELIST_S)) {
469  /* We're tracking which options we've seen, and this option is not
470  * supposed to occur more than once. */
471  int var_index = (int)(var - fmt->vars);
472  if (bitarray_is_set(options_seen, var_index)) {
473  log_warn(LD_CONFIG, "Option '%s' used more than once; all but the last "
474  "value will be ignored.", var->name);
475  }
476  bitarray_set(options_seen, var_index);
477  }
478 
479  if (config_assign_value(fmt, options, c, msg) < 0)
480  return -2;
481  return 0;
482 }
483 
486 static void
487 config_reset_line(const config_format_t *fmt, void *options,
488  const char *key, int use_defaults)
489 {
490  const config_var_t *var;
491 
492  CONFIG_CHECK(fmt, options);
493 
494  var = config_find_option(fmt, key);
495  if (!var)
496  return; /* give error on next pass. */
497 
498  config_reset(fmt, options, var, use_defaults);
499 }
500 
503 static int
504 config_value_needs_escape(const char *value)
505 {
506  if (*value == '\"')
507  return 1;
508  while (*value) {
509  switch (*value)
510  {
511  case '\r':
512  case '\n':
513  case '#':
514  /* Note: quotes and backspaces need special handling when we are using
515  * quotes, not otherwise, so they don't trigger escaping on their
516  * own. */
517  return 1;
518  default:
519  if (!TOR_ISPRINT(*value))
520  return 1;
521  }
522  ++value;
523  }
524  return 0;
525 }
526 
532 config_get_assigned_option(const config_format_t *fmt, const void *options,
533  const char *key, int escape_val)
534 {
535  const config_var_t *var;
536  const void *value;
537  config_line_t *result;
538  tor_assert(options && key);
539 
540  CONFIG_CHECK(fmt, options);
541 
542  var = config_find_option(fmt, key);
543  if (!var) {
544  log_warn(LD_CONFIG, "Unknown option '%s'. Failing.", key);
545  return NULL;
546  }
547  value = STRUCT_VAR_P(options, var->var_offset);
548 
549  result = tor_malloc_zero(sizeof(config_line_t));
550  result->key = tor_strdup(var->name);
551  switch (var->type)
552  {
553  case CONFIG_TYPE_STRING:
555  if (*(char**)value) {
556  result->value = tor_strdup(*(char**)value);
557  } else {
558  tor_free(result->key);
559  tor_free(result);
560  return NULL;
561  }
562  break;
563  case CONFIG_TYPE_ISOTIME:
564  if (*(time_t*)value) {
565  result->value = tor_malloc(ISO_TIME_LEN+1);
566  format_iso_time(result->value, *(time_t*)value);
567  } else {
568  tor_free(result->key);
569  tor_free(result);
570  }
571  escape_val = 0; /* Can't need escape. */
572  break;
573  case CONFIG_TYPE_PORT:
574  if (*(int*)value == CFG_AUTO_PORT) {
575  result->value = tor_strdup("auto");
576  escape_val = 0;
577  break;
578  }
579  /* fall through */
583  case CONFIG_TYPE_UINT:
584  case CONFIG_TYPE_INT:
585  /* This means every or_options_t uint or bool element
586  * needs to be an int. Not, say, a uint16_t or char. */
587  tor_asprintf(&result->value, "%d", *(int*)value);
588  escape_val = 0; /* Can't need escape. */
589  break;
590  case CONFIG_TYPE_UINT64: /* Fall through */
591  case CONFIG_TYPE_MEMUNIT:
592  tor_asprintf(&result->value, "%"PRIu64,
593  (*(uint64_t*)value));
594  escape_val = 0; /* Can't need escape. */
595  break;
596  case CONFIG_TYPE_DOUBLE:
597  tor_asprintf(&result->value, "%f", *(double*)value);
598  escape_val = 0; /* Can't need escape. */
599  break;
600 
602  if (*(int*)value == -1) {
603  result->value = tor_strdup("auto");
604  escape_val = 0;
605  break;
606  }
607  /* fall through */
608  case CONFIG_TYPE_BOOL:
609  result->value = tor_strdup(*(int*)value ? "1" : "0");
610  escape_val = 0; /* Can't need escape. */
611  break;
613  result->value = routerset_to_string(*(routerset_t**)value);
614  break;
615  case CONFIG_TYPE_CSV:
616  if (*(smartlist_t**)value)
617  result->value =
618  smartlist_join_strings(*(smartlist_t**)value, ",", 0, NULL);
619  else
620  result->value = tor_strdup("");
621  break;
624  "You asked me for the value of an obsolete config option '%s'.",
625  key);
626  tor_free(result->key);
627  tor_free(result);
628  return NULL;
630  tor_free(result->key);
631  tor_free(result);
632  result = config_lines_dup_and_filter(*(const config_line_t **)value,
633  key);
634  break;
637  tor_free(result->key);
638  tor_free(result);
639  result = config_lines_dup(*(const config_line_t**)value);
640  break;
641  default:
642  tor_free(result->key);
643  tor_free(result);
644  log_warn(LD_BUG,"Unknown type %d for known key '%s'",
645  var->type, key);
646  return NULL;
647  }
648 
649  if (escape_val) {
650  config_line_t *line;
651  for (line = result; line; line = line->next) {
652  if (line->value && config_value_needs_escape(line->value)) {
653  char *newval = esc_for_log(line->value);
654  tor_free(line->value);
655  line->value = newval;
656  }
657  }
658  }
659 
660  return result;
661 }
691 /*
692 There are three call cases for config_assign() currently.
693 
694 Case one: Torrc entry
695 options_init_from_torrc() calls config_assign(0, 0)
696  calls config_assign_line(0, 0).
697  if value is empty, calls config_reset(0) and returns.
698  calls config_assign_value(), appends.
699 
700 Case two: setconf
701 options_trial_assign() calls config_assign(0, 1)
702  calls config_reset_line(0)
703  calls config_reset(0)
704  calls option_clear().
705  calls config_assign_line(0, 1).
706  if value is empty, returns.
707  calls config_assign_value(), appends.
708 
709 Case three: resetconf
710 options_trial_assign() calls config_assign(1, 1)
711  calls config_reset_line(1)
712  calls config_reset(1)
713  calls option_clear().
714  calls config_assign_value(default)
715  calls config_assign_line(1, 1).
716  returns.
717 */
718 int
719 config_assign(const config_format_t *fmt, void *options, config_line_t *list,
720  unsigned config_assign_flags, char **msg)
721 {
722  config_line_t *p;
723  bitarray_t *options_seen;
724  const int n_options = config_count_options(fmt);
725  const unsigned clear_first = config_assign_flags & CAL_CLEAR_FIRST;
726  const unsigned use_defaults = config_assign_flags & CAL_USE_DEFAULTS;
727 
728  CONFIG_CHECK(fmt, options);
729 
730  /* pass 1: normalize keys */
731  for (p = list; p; p = p->next) {
732  const char *full = config_expand_abbrev(fmt, p->key, 0, 1);
733  if (strcmp(full,p->key)) {
734  tor_free(p->key);
735  p->key = tor_strdup(full);
736  }
737  }
738 
739  /* pass 2: if we're reading from a resetting source, clear all
740  * mentioned config options, and maybe set to their defaults. */
741  if (clear_first) {
742  for (p = list; p; p = p->next)
743  config_reset_line(fmt, options, p->key, use_defaults);
744  }
745 
746  options_seen = bitarray_init_zero(n_options);
747  /* pass 3: assign. */
748  while (list) {
749  int r;
750  if ((r=config_assign_line(fmt, options, list, config_assign_flags,
751  options_seen, msg))) {
752  bitarray_free(options_seen);
753  return r;
754  }
755  list = list->next;
756  }
757  bitarray_free(options_seen);
758 
762  config_mark_lists_fragile(fmt, options);
763 
764  return 0;
765 }
766 
769 static void
770 config_clear(const config_format_t *fmt, void *options,
771  const config_var_t *var)
772 {
773  void *lvalue = STRUCT_VAR_P(options, var->var_offset);
774  (void)fmt; /* unused */
775  switch (var->type) {
776  case CONFIG_TYPE_STRING:
778  tor_free(*(char**)lvalue);
779  break;
780  case CONFIG_TYPE_DOUBLE:
781  *(double*)lvalue = 0.0;
782  break;
783  case CONFIG_TYPE_ISOTIME:
784  *(time_t*)lvalue = 0;
785  break;
789  case CONFIG_TYPE_UINT:
790  case CONFIG_TYPE_INT:
791  case CONFIG_TYPE_PORT:
792  case CONFIG_TYPE_BOOL:
793  *(int*)lvalue = 0;
794  break;
796  *(int*)lvalue = -1;
797  break;
798  case CONFIG_TYPE_UINT64:
799  case CONFIG_TYPE_MEMUNIT:
800  *(uint64_t*)lvalue = 0;
801  break;
803  if (*(routerset_t**)lvalue) {
804  routerset_free(*(routerset_t**)lvalue);
805  *(routerset_t**)lvalue = NULL;
806  }
807  break;
808  case CONFIG_TYPE_CSV:
809  if (*(smartlist_t**)lvalue) {
810  SMARTLIST_FOREACH(*(smartlist_t **)lvalue, char *, cp, tor_free(cp));
811  smartlist_free(*(smartlist_t **)lvalue);
812  *(smartlist_t **)lvalue = NULL;
813  }
814  break;
817  config_free_lines(*(config_line_t **)lvalue);
818  *(config_line_t **)lvalue = NULL;
819  break;
821  /* handled by linelist_s. */
822  break;
824  break;
825  }
826 }
827 
831 static void
832 config_reset(const config_format_t *fmt, void *options,
833  const config_var_t *var, int use_defaults)
834 {
835  config_line_t *c;
836  char *msg = NULL;
837  CONFIG_CHECK(fmt, options);
838  config_clear(fmt, options, var); /* clear it first */
839  if (!use_defaults)
840  return; /* all done */
841  if (var->initvalue) {
842  c = tor_malloc_zero(sizeof(config_line_t));
843  c->key = tor_strdup(var->name);
844  c->value = tor_strdup(var->initvalue);
845  if (config_assign_value(fmt, options, c, &msg) < 0) {
846  log_warn(LD_BUG, "Failed to assign default: %s", msg);
847  tor_free(msg); /* if this happens it's a bug */
848  }
849  config_free_lines(c);
850  }
851 }
852 
854 void
855 config_free_(const config_format_t *fmt, void *options)
856 {
857  int i;
858 
859  if (!options)
860  return;
861 
862  tor_assert(fmt);
863 
864  for (i=0; fmt->vars[i].name; ++i)
865  config_clear(fmt, options, &(fmt->vars[i]));
866  if (fmt->extra) {
867  config_line_t **linep = STRUCT_VAR_P(options, fmt->extra->var_offset);
868  config_free_lines(*linep);
869  *linep = NULL;
870  }
871  tor_free(options);
872 }
873 
877 int
879  const void *o1, const void *o2,
880  const char *name)
881 {
882  config_line_t *c1, *c2;
883  int r = 1;
884  CONFIG_CHECK(fmt, o1);
885  CONFIG_CHECK(fmt, o2);
886 
887  c1 = config_get_assigned_option(fmt, o1, name, 0);
888  c2 = config_get_assigned_option(fmt, o2, name, 0);
889  r = config_lines_eq(c1, c2);
890  config_free_lines(c1);
891  config_free_lines(c2);
892  return r;
893 }
894 
896 void *
897 config_dup(const config_format_t *fmt, const void *old)
898 {
899  void *newopts;
900  int i;
901  config_line_t *line;
902 
903  newopts = config_new(fmt);
904  for (i=0; fmt->vars[i].name; ++i) {
905  if (fmt->vars[i].type == CONFIG_TYPE_LINELIST_S)
906  continue;
907  if (fmt->vars[i].type == CONFIG_TYPE_OBSOLETE)
908  continue;
909  line = config_get_assigned_option(fmt, old, fmt->vars[i].name, 0);
910  if (line) {
911  char *msg = NULL;
912  if (config_assign(fmt, newopts, line, 0, &msg) < 0) {
913  log_err(LD_BUG, "config_get_assigned_option() generated "
914  "something we couldn't config_assign(): %s", msg);
915  tor_free(msg);
916  tor_assert(0);
917  }
918  }
919  config_free_lines(line);
920  }
921  return newopts;
922 }
925 void
926 config_init(const config_format_t *fmt, void *options)
927 {
928  int i;
929  const config_var_t *var;
930  CONFIG_CHECK(fmt, options);
931 
932  for (i=0; fmt->vars[i].name; ++i) {
933  var = &fmt->vars[i];
934  if (!var->initvalue)
935  continue; /* defaults to NULL or 0 */
936  config_reset(fmt, options, var, 1);
937  }
938 }
939 
944 char *
945 config_dump(const config_format_t *fmt, const void *default_options,
946  const void *options, int minimal,
947  int comment_defaults)
948 {
949  smartlist_t *elements;
950  const void *defaults = default_options;
951  void *defaults_tmp = NULL;
952  config_line_t *line, *assigned;
953  char *result;
954  int i;
955  char *msg = NULL;
956 
957  if (defaults == NULL) {
958  defaults = defaults_tmp = config_new(fmt);
959  config_init(fmt, defaults_tmp);
960  }
961 
962  /* XXX use a 1 here so we don't add a new log line while dumping */
963  if (default_options == NULL) {
964  if (fmt->validate_fn(NULL, defaults_tmp, defaults_tmp, 1, &msg) < 0) {
965  log_err(LD_BUG, "Failed to validate default config: %s", msg);
966  tor_free(msg);
967  tor_assert(0);
968  }
969  }
970 
971  elements = smartlist_new();
972  for (i=0; fmt->vars[i].name; ++i) {
973  int comment_option = 0;
974  if (fmt->vars[i].type == CONFIG_TYPE_OBSOLETE ||
975  fmt->vars[i].type == CONFIG_TYPE_LINELIST_S)
976  continue;
977  /* Don't save 'hidden' control variables. */
978  if (!strcmpstart(fmt->vars[i].name, "__"))
979  continue;
980  if (minimal && config_is_same(fmt, options, defaults, fmt->vars[i].name))
981  continue;
982  else if (comment_defaults &&
983  config_is_same(fmt, options, defaults, fmt->vars[i].name))
984  comment_option = 1;
985 
986  line = assigned =
987  config_get_assigned_option(fmt, options, fmt->vars[i].name, 1);
988 
989  for (; line; line = line->next) {
990  if (!strcmpstart(line->key, "__")) {
991  /* This check detects "hidden" variables inside LINELIST_V structures.
992  */
993  continue;
994  }
995  smartlist_add_asprintf(elements, "%s%s %s\n",
996  comment_option ? "# " : "",
997  line->key, line->value);
998  }
999  config_free_lines(assigned);
1000  }
1001 
1002  if (fmt->extra) {
1003  line = *(config_line_t**)STRUCT_VAR_P(options, fmt->extra->var_offset);
1004  for (; line; line = line->next) {
1005  smartlist_add_asprintf(elements, "%s %s\n", line->key, line->value);
1006  }
1007  }
1008 
1009  result = smartlist_join_strings(elements, "", 0, NULL);
1010  SMARTLIST_FOREACH(elements, char *, cp, tor_free(cp));
1011  smartlist_free(elements);
1012  if (defaults_tmp) {
1013  fmt->free_fn(defaults_tmp);
1014  }
1015  return result;
1016 }
1017 
1021  const char *unit;
1022  uint64_t multiplier;
1023 };
1024 
1027 static struct unit_table_t memory_units[] = {
1028  { "", 1 },
1029  { "b", 1<< 0 },
1030  { "byte", 1<< 0 },
1031  { "bytes", 1<< 0 },
1032  { "kb", 1<<10 },
1033  { "kbyte", 1<<10 },
1034  { "kbytes", 1<<10 },
1035  { "kilobyte", 1<<10 },
1036  { "kilobytes", 1<<10 },
1037  { "kilobits", 1<<7 },
1038  { "kilobit", 1<<7 },
1039  { "kbits", 1<<7 },
1040  { "kbit", 1<<7 },
1041  { "m", 1<<20 },
1042  { "mb", 1<<20 },
1043  { "mbyte", 1<<20 },
1044  { "mbytes", 1<<20 },
1045  { "megabyte", 1<<20 },
1046  { "megabytes", 1<<20 },
1047  { "megabits", 1<<17 },
1048  { "megabit", 1<<17 },
1049  { "mbits", 1<<17 },
1050  { "mbit", 1<<17 },
1051  { "gb", 1<<30 },
1052  { "gbyte", 1<<30 },
1053  { "gbytes", 1<<30 },
1054  { "gigabyte", 1<<30 },
1055  { "gigabytes", 1<<30 },
1056  { "gigabits", 1<<27 },
1057  { "gigabit", 1<<27 },
1058  { "gbits", 1<<27 },
1059  { "gbit", 1<<27 },
1060  { "tb", UINT64_C(1)<<40 },
1061  { "tbyte", UINT64_C(1)<<40 },
1062  { "tbytes", UINT64_C(1)<<40 },
1063  { "terabyte", UINT64_C(1)<<40 },
1064  { "terabytes", UINT64_C(1)<<40 },
1065  { "terabits", UINT64_C(1)<<37 },
1066  { "terabit", UINT64_C(1)<<37 },
1067  { "tbits", UINT64_C(1)<<37 },
1068  { "tbit", UINT64_C(1)<<37 },
1069  { NULL, 0 },
1070 };
1071 
1074 static struct unit_table_t time_units[] = {
1075  { "", 1 },
1076  { "second", 1 },
1077  { "seconds", 1 },
1078  { "minute", 60 },
1079  { "minutes", 60 },
1080  { "hour", 60*60 },
1081  { "hours", 60*60 },
1082  { "day", 24*60*60 },
1083  { "days", 24*60*60 },
1084  { "week", 7*24*60*60 },
1085  { "weeks", 7*24*60*60 },
1086  { "month", 2629728, }, /* about 30.437 days */
1087  { "months", 2629728, },
1088  { NULL, 0 },
1089 };
1090 
1093 static struct unit_table_t time_msec_units[] = {
1094  { "", 1 },
1095  { "msec", 1 },
1096  { "millisecond", 1 },
1097  { "milliseconds", 1 },
1098  { "second", 1000 },
1099  { "seconds", 1000 },
1100  { "minute", 60*1000 },
1101  { "minutes", 60*1000 },
1102  { "hour", 60*60*1000 },
1103  { "hours", 60*60*1000 },
1104  { "day", 24*60*60*1000 },
1105  { "days", 24*60*60*1000 },
1106  { "week", 7*24*60*60*1000 },
1107  { "weeks", 7*24*60*60*1000 },
1108  { NULL, 0 },
1109 };
1110 
1117 static uint64_t
1118 config_parse_units(const char *val, struct unit_table_t *u, int *ok)
1119 {
1120  uint64_t v = 0;
1121  double d = 0;
1122  int use_float = 0;
1123  char *cp;
1124 
1125  tor_assert(ok);
1126 
1127  v = tor_parse_uint64(val, 10, 0, UINT64_MAX, ok, &cp);
1128  if (!*ok || (cp && *cp == '.')) {
1129  d = tor_parse_double(val, 0, (double)UINT64_MAX, ok, &cp);
1130  if (!*ok)
1131  goto done;
1132  use_float = 1;
1133  }
1134 
1135  if (!cp) {
1136  *ok = 1;
1137  v = use_float ? ((uint64_t)d) : v;
1138  goto done;
1139  }
1140 
1141  cp = (char*) eat_whitespace(cp);
1142 
1143  for ( ;u->unit;++u) {
1144  if (!strcasecmp(u->unit, cp)) {
1145  if (use_float)
1146  v = (uint64_t)(u->multiplier * d);
1147  else
1148  v *= u->multiplier;
1149  *ok = 1;
1150  goto done;
1151  }
1152  }
1153  log_warn(LD_CONFIG, "Unknown unit '%s'.", cp);
1154  *ok = 0;
1155  done:
1156 
1157  if (*ok)
1158  return v;
1159  else
1160  return 0;
1161 }
1162 
1167 static uint64_t
1168 config_parse_memunit(const char *s, int *ok)
1169 {
1170  uint64_t u = config_parse_units(s, memory_units, ok);
1171  return u;
1172 }
1173 
1178 static int
1179 config_parse_msec_interval(const char *s, int *ok)
1180 {
1181  uint64_t r;
1182  r = config_parse_units(s, time_msec_units, ok);
1183  if (r > INT_MAX) {
1184  log_warn(LD_CONFIG, "Msec interval '%s' is too long", s);
1185  *ok = 0;
1186  return -1;
1187  }
1188  return (int)r;
1189 }
1190 
1195 static int
1196 config_parse_interval(const char *s, int *ok)
1197 {
1198  uint64_t r;
1199  r = config_parse_units(s, time_units, ok);
1200  if (r > INT_MAX) {
1201  log_warn(LD_CONFIG, "Interval '%s' is too long", s);
1202  *ok = 0;
1203  return -1;
1204  }
1205  return (int)r;
1206 }
off_t var_offset
Definition: confparse.h:105
void config_init(const config_format_t *fmt, void *options)
Definition: confparse.c:926
Header for confline.c.
static void config_reset_line(const config_format_t *fmt, void *options, const char *key, int use_defaults)
Definition: confparse.c:487
static struct unit_table_t time_msec_units[]
Definition: confparse.c:1093
static uint64_t config_parse_memunit(const char *s, int *ok)
Definition: confparse.c:1168
static int config_parse_interval(const char *s, int *ok)
Definition: confparse.c:1196
unsigned int bitarray_t
Definition: bitarray.h:30
uint64_t tor_parse_uint64(const char *s, int base, uint64_t min, uint64_t max, int *ok, char **next)
Definition: parse_int.c:107
config_abbrev_t * abbrevs
Definition: confparse.h:169
off_t magic_offset
Definition: confparse.h:168
Implements a variable-sized (but non-resizeable) bit-array.
#define LOG_INFO
Definition: log.h:41
#define CONFIG_LINE_APPEND
Definition: confline.h:22
config_var_t * extra
Definition: confparse.h:178
const char * config_expand_abbrev(const config_format_t *fmt, const char *option, int command_line, int warn_obsolete)
Definition: confparse.c:57
int strcmpstart(const char *s1, const char *s2)
Definition: util_string.c:209
#define tor_free(p)
Definition: malloc.h:52
void ** list
int config_lines_eq(config_line_t *a, config_line_t *b)
Definition: confline.c:246
char * config_dump(const config_format_t *fmt, const void *default_options, const void *options, int minimal, int comment_defaults)
Definition: confparse.c:945
config_line_t * config_get_assigned_option(const config_format_t *fmt, const void *options, const char *key, int escape_val)
Definition: confparse.c:532
config_type_t type
Definition: confparse.h:103
static void bitarray_set(bitarray_t *b, int bit)
Definition: bitarray.h:68
const config_var_t * config_find_option(const config_format_t *fmt, const char *key)
Definition: confparse.c:136
char * routerset_to_string(const routerset_t *set)
Definition: routerset.c:410
tor_assert(buffer)
config_line_t * config_lines_dup_and_filter(const config_line_t *inp, const char *key)
Definition: confline.c:223
unsigned int command
Definition: confline.h:35
static int config_assign_line(const config_format_t *fmt, void *options, config_line_t *c, unsigned flags, bitarray_t *options_seen, char **msg)
Definition: confparse.c:410
static struct unit_table_t time_units[]
Definition: confparse.c:1074
static uint64_t config_parse_units(const char *val, struct unit_table_t *u, int *ok)
Definition: confparse.c:1118
int tor_asprintf(char **strp, const char *fmt,...)
Definition: printf.c:75
#define CFG_AUTO_PORT
Definition: or.h:990
#define STRUCT_VAR_P(st, off)
void smartlist_add_asprintf(struct smartlist_t *sl, const char *pattern,...)
Definition: smartlist.c:36
Master header file for Tor-specific functionality.
free_cfg_fn_t free_fn
Definition: confparse.h:175
const char * eat_whitespace(const char *s)
Definition: util_string.c:271
config_var_t * config_find_option_mutable(config_format_t *fmt, const char *key)
Definition: confparse.c:105
const char * name
Definition: confparse.h:102
static bitarray_t * bitarray_init_zero(unsigned int n_bits)
Definition: bitarray.h:33
void * config_dup(const config_format_t *fmt, const void *old)
Definition: confparse.c:897
static int config_assign_value(const config_format_t *fmt, void *options, config_line_t *c, char **msg)
Definition: confparse.c:161
void config_free_(const config_format_t *fmt, void *options)
Definition: confparse.c:855
const char * initvalue
Definition: confparse.h:106
config_var_t * vars
Definition: confparse.h:172
int routerset_parse(routerset_t *target, const char *s, const char *description)
Definition: routerset.c:110
static struct unit_table_t memory_units[]
Definition: confparse.c:1027
unsigned int fragile
Definition: confline.h:39
config_line_t * config_lines_dup(const config_line_t *inp)
Definition: confline.c:214
static void config_reset(const config_format_t *fmt, void *options, const config_var_t *var, int use_defaults)
Definition: confparse.c:832
const char * config_find_deprecation(const config_format_t *fmt, const char *key)
Definition: confparse.c:87
void format_iso_time(char *buf, time_t t)
Definition: time_fmt.c:291
char * smartlist_join_strings(smartlist_t *sl, const char *join, int terminate, size_t *len_out)
Definition: smartlist.c:279
#define SMARTLIST_FOREACH(sl, type, var, cmd)
static void config_clear(const config_format_t *fmt, void *options, const config_var_t *var)
Definition: confparse.c:770
double tor_parse_double(const char *s, double min, double max, int *ok, char **next)
Definition: parse_int.c:94
const char * unit
Definition: confparse.c:1021
int config_is_same(const config_format_t *fmt, const void *o1, const void *o2, const char *name)
Definition: confparse.c:878
#define log_fn(severity, domain, args,...)
Definition: log.h:255
int config_assign(const config_format_t *fmt, void *options, config_line_t *list, unsigned config_assign_flags, char **msg)
Definition: confparse.c:719
#define CONFIG_CHECK(fmt, cfg)
Definition: confparse.h:183
uint32_t magic
Definition: confparse.h:166
validate_fn_t validate_fn
Definition: confparse.h:174
void config_line_append(config_line_t **lst, const char *key, const char *val)
Definition: confline.c:32
routerset_t * routerset_new(void)
Definition: routerset.c:47
long tor_parse_long(const char *s, int base, long min, long max, int *ok, char **next)
Definition: parse_int.c:56
char * esc_for_log(const char *s)
Definition: escape.c:30
static int config_count_options(const config_format_t *fmt)
Definition: confparse.c:143
int parse_iso_time(const char *cp, time_t *t)
Definition: time_fmt.c:388
static int config_parse_msec_interval(const char *s, int *ok)
Definition: confparse.c:1179
void smartlist_clear(smartlist_t *sl)
static int config_value_needs_escape(const char *value)
Definition: confparse.c:504
static unsigned int bitarray_is_set(bitarray_t *b, int bit)
Definition: bitarray.h:81
void * config_new(const config_format_t *fmt)
Definition: confparse.c:39
#define LD_BUG
Definition: log.h:82
#define LD_CONFIG
Definition: log.h:64
static void config_mark_lists_fragile(const config_format_t *fmt, void *options)
Definition: confparse.c:371
uint64_t multiplier
Definition: confparse.c:1022
Header for confparse.c.
int smartlist_split_string(smartlist_t *sl, const char *str, const char *sep, int flags, int max)