confparse.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721
  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. /**
  7. * \file confparse.c
  8. *
  9. * \brief Back-end for parsing and generating key-value files, used to
  10. * implement the torrc file format and the state file.
  11. *
  12. * This module is used by config.c to parse and encode torrc
  13. * configuration files, and by statefile.c to parse and encode the
  14. * $DATADIR/state file.
  15. *
  16. * To use this module, its callers provide an instance of
  17. * config_format_t to describe the mappings from a set of configuration
  18. * options to a number of fields in a C structure. With this mapping,
  19. * the functions here can convert back and forth between the C structure
  20. * specified, and a linked list of key-value pairs.
  21. */
  22. #define CONFPARSE_PRIVATE
  23. #include "core/or/or.h"
  24. #include "app/config/confparse.h"
  25. #include "feature/nodelist/routerset.h"
  26. #include "lib/confmgt/unitparse.h"
  27. #include "lib/container/bitarray.h"
  28. #include "lib/encoding/confline.h"
  29. #include "lib/confmgt/typedvar.h"
  30. static void config_reset(const config_format_t *fmt, void *options,
  31. const config_var_t *var, int use_defaults);
  32. /** Allocate an empty configuration object of a given format type. */
  33. void *
  34. config_new(const config_format_t *fmt)
  35. {
  36. void *opts = tor_malloc_zero(fmt->size);
  37. *(uint32_t*)STRUCT_VAR_P(opts, fmt->magic_offset) = fmt->magic;
  38. CONFIG_CHECK(fmt, opts);
  39. return opts;
  40. }
  41. /*
  42. * Functions to parse config options
  43. */
  44. /** If <b>option</b> is an official abbreviation for a longer option,
  45. * return the longer option. Otherwise return <b>option</b>.
  46. * If <b>command_line</b> is set, apply all abbreviations. Otherwise, only
  47. * apply abbreviations that work for the config file and the command line.
  48. * If <b>warn_obsolete</b> is set, warn about deprecated names. */
  49. const char *
  50. config_expand_abbrev(const config_format_t *fmt, const char *option,
  51. int command_line, int warn_obsolete)
  52. {
  53. int i;
  54. if (! fmt->abbrevs)
  55. return option;
  56. for (i=0; fmt->abbrevs[i].abbreviated; ++i) {
  57. /* Abbreviations are case insensitive. */
  58. if (!strcasecmp(option,fmt->abbrevs[i].abbreviated) &&
  59. (command_line || !fmt->abbrevs[i].commandline_only)) {
  60. if (warn_obsolete && fmt->abbrevs[i].warn) {
  61. log_warn(LD_CONFIG,
  62. "The configuration option '%s' is deprecated; "
  63. "use '%s' instead.",
  64. fmt->abbrevs[i].abbreviated,
  65. fmt->abbrevs[i].full);
  66. }
  67. /* Keep going through the list in case we want to rewrite it more.
  68. * (We could imagine recursing here, but I don't want to get the
  69. * user into an infinite loop if we craft our list wrong.) */
  70. option = fmt->abbrevs[i].full;
  71. }
  72. }
  73. return option;
  74. }
  75. /** If <b>key</b> is a deprecated configuration option, return the message
  76. * explaining why it is deprecated (which may be an empty string). Return NULL
  77. * if it is not deprecated. The <b>key</b> field must be fully expanded. */
  78. const char *
  79. config_find_deprecation(const config_format_t *fmt, const char *key)
  80. {
  81. if (BUG(fmt == NULL) || BUG(key == NULL))
  82. return NULL; // LCOV_EXCL_LINE
  83. if (fmt->deprecations == NULL)
  84. return NULL;
  85. const config_deprecation_t *d;
  86. for (d = fmt->deprecations; d->name; ++d) {
  87. if (!strcasecmp(d->name, key)) {
  88. return d->why_deprecated ? d->why_deprecated : "";
  89. }
  90. }
  91. return NULL;
  92. }
  93. /** As config_find_option, but return a non-const pointer. */
  94. config_var_t *
  95. config_find_option_mutable(config_format_t *fmt, const char *key)
  96. {
  97. int i;
  98. size_t keylen = strlen(key);
  99. if (!keylen)
  100. return NULL; /* if they say "--" on the command line, it's not an option */
  101. /* First, check for an exact (case-insensitive) match */
  102. for (i=0; fmt->vars[i].name; ++i) {
  103. if (!strcasecmp(key, fmt->vars[i].name)) {
  104. return &fmt->vars[i];
  105. }
  106. }
  107. /* If none, check for an abbreviated match */
  108. for (i=0; fmt->vars[i].name; ++i) {
  109. if (!strncasecmp(key, fmt->vars[i].name, keylen)) {
  110. log_warn(LD_CONFIG, "The abbreviation '%s' is deprecated. "
  111. "Please use '%s' instead",
  112. key, fmt->vars[i].name);
  113. return &fmt->vars[i];
  114. }
  115. }
  116. /* Okay, unrecognized option */
  117. return NULL;
  118. }
  119. /** If <b>key</b> is a configuration option, return the corresponding const
  120. * config_var_t. Otherwise, if <b>key</b> is a non-standard abbreviation,
  121. * warn, and return the corresponding const config_var_t. Otherwise return
  122. * NULL.
  123. */
  124. const config_var_t *
  125. config_find_option(const config_format_t *fmt, const char *key)
  126. {
  127. return config_find_option_mutable((config_format_t*)fmt, key);
  128. }
  129. /** Return the number of option entries in <b>fmt</b>. */
  130. static int
  131. config_count_options(const config_format_t *fmt)
  132. {
  133. int i;
  134. for (i=0; fmt->vars[i].name; ++i)
  135. ;
  136. return i;
  137. }
  138. /*
  139. * Functions to assign config options.
  140. */
  141. /** <b>c</b>-\>key is known to be a real key. Update <b>options</b>
  142. * with <b>c</b>-\>value and return 0, or return -1 if bad value.
  143. *
  144. * Called from config_assign_line() and option_reset().
  145. */
  146. static int
  147. config_assign_value(const config_format_t *fmt, void *options,
  148. config_line_t *c, char **msg)
  149. {
  150. const config_var_t *var;
  151. void *lvalue;
  152. CONFIG_CHECK(fmt, options);
  153. var = config_find_option(fmt, c->key);
  154. tor_assert(var);
  155. tor_assert(!strcmp(c->key, var->name));
  156. lvalue = STRUCT_VAR_P(options, var->var_offset);
  157. if (var->type == CONFIG_TYPE_ROUTERSET) {
  158. // XXXX make the backend extensible so that we don't have to
  159. // XXXX handle ROUTERSET specially.
  160. if (*(routerset_t**)lvalue) {
  161. routerset_free(*(routerset_t**)lvalue);
  162. }
  163. *(routerset_t**)lvalue = routerset_new();
  164. if (routerset_parse(*(routerset_t**)lvalue, c->value, c->key)<0) {
  165. tor_asprintf(msg, "Invalid exit list '%s' for option '%s'",
  166. c->value, c->key);
  167. return -1;
  168. }
  169. return 0;
  170. }
  171. return typed_var_kvassign(lvalue, c, msg, var->type);
  172. }
  173. /** Mark every linelist in <b>options</b> "fragile", so that fresh assignments
  174. * to it will replace old ones. */
  175. static void
  176. config_mark_lists_fragile(const config_format_t *fmt, void *options)
  177. {
  178. int i;
  179. tor_assert(fmt);
  180. tor_assert(options);
  181. for (i = 0; fmt->vars[i].name; ++i) {
  182. const config_var_t *var = &fmt->vars[i];
  183. config_line_t *list;
  184. if (var->type != CONFIG_TYPE_LINELIST &&
  185. var->type != CONFIG_TYPE_LINELIST_V)
  186. continue;
  187. list = *(config_line_t **)STRUCT_VAR_P(options, var->var_offset);
  188. if (list)
  189. list->fragile = 1;
  190. }
  191. }
  192. void
  193. warn_deprecated_option(const char *what, const char *why)
  194. {
  195. const char *space = (why && strlen(why)) ? " " : "";
  196. log_warn(LD_CONFIG, "The %s option is deprecated, and will most likely "
  197. "be removed in a future version of Tor.%s%s (If you think this is "
  198. "a mistake, please let us know!)",
  199. what, space, why);
  200. }
  201. /** If <b>c</b> is a syntactically valid configuration line, update
  202. * <b>options</b> with its value and return 0. Otherwise return -1 for bad
  203. * key, -2 for bad value.
  204. *
  205. * If <b>clear_first</b> is set, clear the value first. Then if
  206. * <b>use_defaults</b> is set, set the value to the default.
  207. *
  208. * Called from config_assign().
  209. */
  210. static int
  211. config_assign_line(const config_format_t *fmt, void *options,
  212. config_line_t *c, unsigned flags,
  213. bitarray_t *options_seen, char **msg)
  214. {
  215. const unsigned use_defaults = flags & CAL_USE_DEFAULTS;
  216. const unsigned clear_first = flags & CAL_CLEAR_FIRST;
  217. const unsigned warn_deprecations = flags & CAL_WARN_DEPRECATIONS;
  218. const config_var_t *var;
  219. CONFIG_CHECK(fmt, options);
  220. var = config_find_option(fmt, c->key);
  221. if (!var) {
  222. if (fmt->extra) {
  223. void *lvalue = STRUCT_VAR_P(options, fmt->extra->var_offset);
  224. log_info(LD_CONFIG,
  225. "Found unrecognized option '%s'; saving it.", c->key);
  226. config_line_append((config_line_t**)lvalue, c->key, c->value);
  227. return 0;
  228. } else {
  229. tor_asprintf(msg,
  230. "Unknown option '%s'. Failing.", c->key);
  231. return -1;
  232. }
  233. }
  234. /* Put keyword into canonical case. */
  235. if (strcmp(var->name, c->key)) {
  236. tor_free(c->key);
  237. c->key = tor_strdup(var->name);
  238. }
  239. const char *deprecation_msg;
  240. if (warn_deprecations &&
  241. (deprecation_msg = config_find_deprecation(fmt, var->name))) {
  242. warn_deprecated_option(var->name, deprecation_msg);
  243. }
  244. if (!strlen(c->value)) {
  245. /* reset or clear it, then return */
  246. if (!clear_first) {
  247. if ((var->type == CONFIG_TYPE_LINELIST ||
  248. var->type == CONFIG_TYPE_LINELIST_S) &&
  249. c->command != CONFIG_LINE_CLEAR) {
  250. /* We got an empty linelist from the torrc or command line.
  251. As a special case, call this an error. Warn and ignore. */
  252. log_warn(LD_CONFIG,
  253. "Linelist option '%s' has no value. Skipping.", c->key);
  254. } else { /* not already cleared */
  255. config_reset(fmt, options, var, use_defaults);
  256. }
  257. }
  258. return 0;
  259. } else if (c->command == CONFIG_LINE_CLEAR && !clear_first) {
  260. // XXXX This is unreachable, since a CLEAR line always has an
  261. // XXXX empty value.
  262. config_reset(fmt, options, var, use_defaults); // LCOV_EXCL_LINE
  263. }
  264. if (options_seen && (var->type != CONFIG_TYPE_LINELIST &&
  265. var->type != CONFIG_TYPE_LINELIST_S)) {
  266. /* We're tracking which options we've seen, and this option is not
  267. * supposed to occur more than once. */
  268. int var_index = (int)(var - fmt->vars);
  269. if (bitarray_is_set(options_seen, var_index)) {
  270. log_warn(LD_CONFIG, "Option '%s' used more than once; all but the last "
  271. "value will be ignored.", var->name);
  272. }
  273. bitarray_set(options_seen, var_index);
  274. }
  275. if (config_assign_value(fmt, options, c, msg) < 0)
  276. return -2;
  277. return 0;
  278. }
  279. /** Restore the option named <b>key</b> in options to its default value.
  280. * Called from config_assign(). */
  281. STATIC void
  282. config_reset_line(const config_format_t *fmt, void *options,
  283. const char *key, int use_defaults)
  284. {
  285. const config_var_t *var;
  286. CONFIG_CHECK(fmt, options);
  287. var = config_find_option(fmt, key);
  288. if (!var)
  289. return; /* give error on next pass. */
  290. config_reset(fmt, options, var, use_defaults);
  291. }
  292. /** Return true iff value needs to be quoted and escaped to be used in
  293. * a configuration file. */
  294. static int
  295. config_value_needs_escape(const char *value)
  296. {
  297. if (*value == '\"')
  298. return 1;
  299. while (*value) {
  300. switch (*value)
  301. {
  302. case '\r':
  303. case '\n':
  304. case '#':
  305. /* Note: quotes and backspaces need special handling when we are using
  306. * quotes, not otherwise, so they don't trigger escaping on their
  307. * own. */
  308. return 1;
  309. default:
  310. if (!TOR_ISPRINT(*value))
  311. return 1;
  312. }
  313. ++value;
  314. }
  315. return 0;
  316. }
  317. /** Return newly allocated line or lines corresponding to <b>key</b> in the
  318. * configuration <b>options</b>. If <b>escape_val</b> is true and a
  319. * value needs to be quoted before it's put in a config file, quote and
  320. * escape that value. Return NULL if no such key exists. */
  321. config_line_t *
  322. config_get_assigned_option(const config_format_t *fmt, const void *options,
  323. const char *key, int escape_val)
  324. {
  325. const config_var_t *var;
  326. const void *value;
  327. config_line_t *result;
  328. tor_assert(options && key);
  329. CONFIG_CHECK(fmt, options);
  330. var = config_find_option(fmt, key);
  331. if (!var) {
  332. log_warn(LD_CONFIG, "Unknown option '%s'. Failing.", key);
  333. return NULL;
  334. }
  335. value = STRUCT_VAR_P(options, var->var_offset);
  336. if (var->type == CONFIG_TYPE_ROUTERSET) {
  337. // XXXX make the backend extensible so that we don't have to
  338. // XXXX handle ROUTERSET specially.
  339. result = tor_malloc_zero(sizeof(config_line_t));
  340. result->key = tor_strdup(var->name);
  341. result->value = routerset_to_string(*(routerset_t**)value);
  342. } else {
  343. result = typed_var_kvencode(var->name, value, var->type);
  344. }
  345. if (escape_val) {
  346. config_line_t *line;
  347. for (line = result; line; line = line->next) {
  348. if (line->value && config_value_needs_escape(line->value)) {
  349. char *newval = esc_for_log(line->value);
  350. tor_free(line->value);
  351. line->value = newval;
  352. }
  353. }
  354. }
  355. return result;
  356. }
  357. /** Iterate through the linked list of requested options <b>list</b>.
  358. * For each item, convert as appropriate and assign to <b>options</b>.
  359. * If an item is unrecognized, set *msg and return -1 immediately,
  360. * else return 0 for success.
  361. *
  362. * If <b>clear_first</b>, interpret config options as replacing (not
  363. * extending) their previous values. If <b>clear_first</b> is set,
  364. * then <b>use_defaults</b> to decide if you set to defaults after
  365. * clearing, or make the value 0 or NULL.
  366. *
  367. * Here are the use cases:
  368. * 1. A non-empty AllowInvalid line in your torrc. Appends to current
  369. * if linelist, replaces current if csv.
  370. * 2. An empty AllowInvalid line in your torrc. Should clear it.
  371. * 3. "RESETCONF AllowInvalid" sets it to default.
  372. * 4. "SETCONF AllowInvalid" makes it NULL.
  373. * 5. "SETCONF AllowInvalid=foo" clears it and sets it to "foo".
  374. *
  375. * Use_defaults Clear_first
  376. * 0 0 "append"
  377. * 1 0 undefined, don't use
  378. * 0 1 "set to null first"
  379. * 1 1 "set to defaults first"
  380. * Return 0 on success, -1 on bad key, -2 on bad value.
  381. *
  382. * As an additional special case, if a LINELIST config option has
  383. * no value and clear_first is 0, then warn and ignore it.
  384. */
  385. /*
  386. There are three call cases for config_assign() currently.
  387. Case one: Torrc entry
  388. options_init_from_torrc() calls config_assign(0, 0)
  389. calls config_assign_line(0, 0).
  390. if value is empty, calls config_reset(0) and returns.
  391. calls config_assign_value(), appends.
  392. Case two: setconf
  393. options_trial_assign() calls config_assign(0, 1)
  394. calls config_reset_line(0)
  395. calls config_reset(0)
  396. calls option_clear().
  397. calls config_assign_line(0, 1).
  398. if value is empty, returns.
  399. calls config_assign_value(), appends.
  400. Case three: resetconf
  401. options_trial_assign() calls config_assign(1, 1)
  402. calls config_reset_line(1)
  403. calls config_reset(1)
  404. calls option_clear().
  405. calls config_assign_value(default)
  406. calls config_assign_line(1, 1).
  407. returns.
  408. */
  409. int
  410. config_assign(const config_format_t *fmt, void *options, config_line_t *list,
  411. unsigned config_assign_flags, char **msg)
  412. {
  413. config_line_t *p;
  414. bitarray_t *options_seen;
  415. const int n_options = config_count_options(fmt);
  416. const unsigned clear_first = config_assign_flags & CAL_CLEAR_FIRST;
  417. const unsigned use_defaults = config_assign_flags & CAL_USE_DEFAULTS;
  418. CONFIG_CHECK(fmt, options);
  419. /* pass 1: normalize keys */
  420. for (p = list; p; p = p->next) {
  421. const char *full = config_expand_abbrev(fmt, p->key, 0, 1);
  422. if (strcmp(full,p->key)) {
  423. tor_free(p->key);
  424. p->key = tor_strdup(full);
  425. }
  426. }
  427. /* pass 2: if we're reading from a resetting source, clear all
  428. * mentioned config options, and maybe set to their defaults. */
  429. if (clear_first) {
  430. for (p = list; p; p = p->next)
  431. config_reset_line(fmt, options, p->key, use_defaults);
  432. }
  433. options_seen = bitarray_init_zero(n_options);
  434. /* pass 3: assign. */
  435. while (list) {
  436. int r;
  437. if ((r=config_assign_line(fmt, options, list, config_assign_flags,
  438. options_seen, msg))) {
  439. bitarray_free(options_seen);
  440. return r;
  441. }
  442. list = list->next;
  443. }
  444. bitarray_free(options_seen);
  445. /** Now we're done assigning a group of options to the configuration.
  446. * Subsequent group assignments should _replace_ linelists, not extend
  447. * them. */
  448. config_mark_lists_fragile(fmt, options);
  449. return 0;
  450. }
  451. /** Reset config option <b>var</b> to 0, 0.0, NULL, or the equivalent.
  452. * Called from config_reset() and config_free(). */
  453. static void
  454. config_clear(const config_format_t *fmt, void *options,
  455. const config_var_t *var)
  456. {
  457. void *lvalue = STRUCT_VAR_P(options, var->var_offset);
  458. (void)fmt; /* unused */
  459. if (var->type == CONFIG_TYPE_ROUTERSET) {
  460. // XXXX make the backend extensible so that we don't have to
  461. // XXXX handle ROUTERSET specially.
  462. if (*(routerset_t**)lvalue) {
  463. routerset_free(*(routerset_t**)lvalue);
  464. *(routerset_t**)lvalue = NULL;
  465. }
  466. return;
  467. }
  468. typed_var_free(lvalue, var->type);
  469. }
  470. /** Clear the option indexed by <b>var</b> in <b>options</b>. Then if
  471. * <b>use_defaults</b>, set it to its default value.
  472. * Called by config_init() and option_reset_line() and option_assign_line(). */
  473. static void
  474. config_reset(const config_format_t *fmt, void *options,
  475. const config_var_t *var, int use_defaults)
  476. {
  477. config_line_t *c;
  478. char *msg = NULL;
  479. CONFIG_CHECK(fmt, options);
  480. config_clear(fmt, options, var); /* clear it first */
  481. if (!use_defaults)
  482. return; /* all done */
  483. if (var->initvalue) {
  484. c = tor_malloc_zero(sizeof(config_line_t));
  485. c->key = tor_strdup(var->name);
  486. c->value = tor_strdup(var->initvalue);
  487. if (config_assign_value(fmt, options, c, &msg) < 0) {
  488. // LCOV_EXCL_START
  489. log_warn(LD_BUG, "Failed to assign default: %s", msg);
  490. tor_free(msg); /* if this happens it's a bug */
  491. // LCOV_EXCL_STOP
  492. }
  493. config_free_lines(c);
  494. }
  495. }
  496. /** Release storage held by <b>options</b>. */
  497. void
  498. config_free_(const config_format_t *fmt, void *options)
  499. {
  500. int i;
  501. if (!options)
  502. return;
  503. tor_assert(fmt);
  504. for (i=0; fmt->vars[i].name; ++i)
  505. config_clear(fmt, options, &(fmt->vars[i]));
  506. if (fmt->extra) {
  507. config_line_t **linep = STRUCT_VAR_P(options, fmt->extra->var_offset);
  508. config_free_lines(*linep);
  509. *linep = NULL;
  510. }
  511. tor_free(options);
  512. }
  513. /** Return true iff the option <b>name</b> has the same value in <b>o1</b>
  514. * and <b>o2</b>. Must not be called for LINELIST_S or OBSOLETE options.
  515. */
  516. int
  517. config_is_same(const config_format_t *fmt,
  518. const void *o1, const void *o2,
  519. const char *name)
  520. {
  521. config_line_t *c1, *c2;
  522. int r = 1;
  523. CONFIG_CHECK(fmt, o1);
  524. CONFIG_CHECK(fmt, o2);
  525. c1 = config_get_assigned_option(fmt, o1, name, 0);
  526. c2 = config_get_assigned_option(fmt, o2, name, 0);
  527. r = config_lines_eq(c1, c2);
  528. config_free_lines(c1);
  529. config_free_lines(c2);
  530. return r;
  531. }
  532. /** Copy storage held by <b>old</b> into a new or_options_t and return it. */
  533. void *
  534. config_dup(const config_format_t *fmt, const void *old)
  535. {
  536. void *newopts;
  537. int i;
  538. config_line_t *line;
  539. newopts = config_new(fmt);
  540. for (i=0; fmt->vars[i].name; ++i) {
  541. if (fmt->vars[i].type == CONFIG_TYPE_LINELIST_S)
  542. continue;
  543. if (fmt->vars[i].type == CONFIG_TYPE_OBSOLETE)
  544. continue;
  545. line = config_get_assigned_option(fmt, old, fmt->vars[i].name, 0);
  546. if (line) {
  547. char *msg = NULL;
  548. if (config_assign(fmt, newopts, line, 0, &msg) < 0) {
  549. // LCOV_EXCL_START
  550. log_err(LD_BUG, "config_get_assigned_option() generated "
  551. "something we couldn't config_assign(): %s", msg);
  552. tor_free(msg);
  553. tor_assert(0);
  554. // LCOV_EXCL_STOP
  555. }
  556. }
  557. config_free_lines(line);
  558. }
  559. return newopts;
  560. }
  561. /** Set all vars in the configuration object <b>options</b> to their default
  562. * values. */
  563. void
  564. config_init(const config_format_t *fmt, void *options)
  565. {
  566. int i;
  567. const config_var_t *var;
  568. CONFIG_CHECK(fmt, options);
  569. for (i=0; fmt->vars[i].name; ++i) {
  570. var = &fmt->vars[i];
  571. if (!var->initvalue)
  572. continue; /* defaults to NULL or 0 */
  573. config_reset(fmt, options, var, 1);
  574. }
  575. }
  576. /** Allocate and return a new string holding the written-out values of the vars
  577. * in 'options'. If 'minimal', do not write out any default-valued vars.
  578. * Else, if comment_defaults, write default values as comments.
  579. */
  580. char *
  581. config_dump(const config_format_t *fmt, const void *default_options,
  582. const void *options, int minimal,
  583. int comment_defaults)
  584. {
  585. smartlist_t *elements;
  586. const void *defaults = default_options;
  587. void *defaults_tmp = NULL;
  588. config_line_t *line, *assigned;
  589. char *result;
  590. int i;
  591. char *msg = NULL;
  592. if (defaults == NULL) {
  593. defaults = defaults_tmp = config_new(fmt);
  594. config_init(fmt, defaults_tmp);
  595. }
  596. /* XXX use a 1 here so we don't add a new log line while dumping */
  597. if (default_options == NULL) {
  598. if (fmt->validate_fn(NULL, defaults_tmp, defaults_tmp, 1, &msg) < 0) {
  599. // LCOV_EXCL_START
  600. log_err(LD_BUG, "Failed to validate default config: %s", msg);
  601. tor_free(msg);
  602. tor_assert(0);
  603. // LCOV_EXCL_STOP
  604. }
  605. }
  606. elements = smartlist_new();
  607. for (i=0; fmt->vars[i].name; ++i) {
  608. int comment_option = 0;
  609. if (fmt->vars[i].type == CONFIG_TYPE_OBSOLETE ||
  610. fmt->vars[i].type == CONFIG_TYPE_LINELIST_S)
  611. continue;
  612. /* Don't save 'hidden' control variables. */
  613. if (!strcmpstart(fmt->vars[i].name, "__"))
  614. continue;
  615. if (minimal && config_is_same(fmt, options, defaults, fmt->vars[i].name))
  616. continue;
  617. else if (comment_defaults &&
  618. config_is_same(fmt, options, defaults, fmt->vars[i].name))
  619. comment_option = 1;
  620. line = assigned =
  621. config_get_assigned_option(fmt, options, fmt->vars[i].name, 1);
  622. for (; line; line = line->next) {
  623. if (!strcmpstart(line->key, "__")) {
  624. /* This check detects "hidden" variables inside LINELIST_V structures.
  625. */
  626. continue;
  627. }
  628. smartlist_add_asprintf(elements, "%s%s %s\n",
  629. comment_option ? "# " : "",
  630. line->key, line->value);
  631. }
  632. config_free_lines(assigned);
  633. }
  634. if (fmt->extra) {
  635. line = *(config_line_t**)STRUCT_VAR_P(options, fmt->extra->var_offset);
  636. for (; line; line = line->next) {
  637. smartlist_add_asprintf(elements, "%s %s\n", line->key, line->value);
  638. }
  639. }
  640. result = smartlist_join_strings(elements, "", 0, NULL);
  641. SMARTLIST_FOREACH(elements, char *, cp, tor_free(cp));
  642. smartlist_free(elements);
  643. if (defaults_tmp) {
  644. fmt->free_fn(defaults_tmp);
  645. }
  646. return result;
  647. }