conffile.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  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 conffile.h
  8. *
  9. * \brief Read configuration files from disk, with full `%include` support.
  10. **/
  11. #include "lib/fs/conffile.h"
  12. #include "lib/container/smartlist.h"
  13. #include "lib/encoding/confline.h"
  14. #include "lib/fs/dir.h"
  15. #include "lib/fs/files.h"
  16. #include "lib/fs/path.h"
  17. #include "lib/log/log.h"
  18. #include "lib/malloc/malloc.h"
  19. #include "lib/string/printf.h"
  20. static smartlist_t *config_get_file_list(const char *path,
  21. smartlist_t *opened_files);
  22. static int config_get_included_config(const char *path, int recursion_level,
  23. int extended, config_line_t **config,
  24. config_line_t **config_last,
  25. smartlist_t *opened_lst);
  26. static int config_process_include(const char *path, int recursion_level,
  27. int extended, config_line_t **list,
  28. config_line_t **list_last,
  29. smartlist_t *opened_lst);
  30. /** Helper: parse the config string and strdup into key/value
  31. * strings. Set *result to the list, or NULL if parsing the string
  32. * failed. Set *has_include to 1 if <b>result</b> has values from
  33. * %included files. <b>opened_lst</b> will have a list of opened files if
  34. * provided. Return 0 on success, -1 on failure. Warn and ignore any
  35. * misformatted lines.
  36. *
  37. * If <b>extended</b> is set, then treat keys beginning with / and with + as
  38. * indicating "clear" and "append" respectively. */
  39. int
  40. config_get_lines_include(const char *string, config_line_t **result,
  41. int extended, int *has_include,
  42. smartlist_t *opened_lst)
  43. {
  44. return config_get_lines_aux(string, result, extended, 1, has_include,
  45. opened_lst, 1, NULL, config_process_include);
  46. }
  47. /** Adds a list of configuration files present on <b>path</b> to
  48. * <b>file_list</b>. <b>path</b> can be a file or a directory. If it is a file,
  49. * only that file will be added to <b>file_list</b>. If it is a directory,
  50. * all paths for files on that directory root (no recursion) except for files
  51. * whose name starts with a dot will be added to <b>file_list</b>.
  52. * <b>opened_files</b> will have a list of files opened by this function
  53. * if provided. Return 0 on success, -1 on failure. Ignores empty files.
  54. */
  55. static smartlist_t *
  56. config_get_file_list(const char *path, smartlist_t *opened_files)
  57. {
  58. smartlist_t *file_list = smartlist_new();
  59. if (opened_files) {
  60. smartlist_add_strdup(opened_files, path);
  61. }
  62. file_status_t file_type = file_status(path);
  63. if (file_type == FN_FILE) {
  64. smartlist_add_strdup(file_list, path);
  65. return file_list;
  66. } else if (file_type == FN_DIR) {
  67. smartlist_t *all_files = tor_listdir(path);
  68. if (!all_files) {
  69. smartlist_free(file_list);
  70. return NULL;
  71. }
  72. smartlist_sort_strings(all_files);
  73. SMARTLIST_FOREACH_BEGIN(all_files, char *, f) {
  74. if (f[0] == '.') {
  75. tor_free(f);
  76. continue;
  77. }
  78. char *fullname;
  79. tor_asprintf(&fullname, "%s"PATH_SEPARATOR"%s", path, f);
  80. tor_free(f);
  81. if (opened_files) {
  82. smartlist_add_strdup(opened_files, fullname);
  83. }
  84. if (file_status(fullname) != FN_FILE) {
  85. tor_free(fullname);
  86. continue;
  87. }
  88. smartlist_add(file_list, fullname);
  89. } SMARTLIST_FOREACH_END(f);
  90. smartlist_free(all_files);
  91. return file_list;
  92. } else if (file_type == FN_EMPTY) {
  93. return file_list;
  94. } else {
  95. smartlist_free(file_list);
  96. return NULL;
  97. }
  98. }
  99. /** Creates a list of config lines present on included <b>path</b>.
  100. * Set <b>config</b> to the list and <b>config_last</b> to the last element of
  101. * <b>config</b>. <b>opened_lst</b> will have a list of opened files if
  102. * provided. Return 0 on success, -1 on failure. */
  103. static int
  104. config_get_included_config(const char *path, int recursion_level, int extended,
  105. config_line_t **config, config_line_t **config_last,
  106. smartlist_t *opened_lst)
  107. {
  108. char *included_conf = read_file_to_str(path, 0, NULL);
  109. if (!included_conf) {
  110. return -1;
  111. }
  112. if (config_get_lines_aux(included_conf, config, extended, 1, NULL,
  113. opened_lst, recursion_level+1, config_last,
  114. config_process_include) < 0) {
  115. tor_free(included_conf);
  116. return -1;
  117. }
  118. tor_free(included_conf);
  119. return 0;
  120. }
  121. /** Process an %include <b>path</b> in a config file. Set <b>list</b> to the
  122. * list of configuration settings obtained and <b>list_last</b> to the last
  123. * element of the same list. <b>opened_lst</b> will have a list of opened
  124. * files if provided. Return 0 on success, -1 on failure. */
  125. static int
  126. config_process_include(const char *path, int recursion_level, int extended,
  127. config_line_t **list, config_line_t **list_last,
  128. smartlist_t *opened_lst)
  129. {
  130. config_line_t *ret_list = NULL;
  131. config_line_t **next = &ret_list;
  132. smartlist_t *config_files = config_get_file_list(path, opened_lst);
  133. if (!config_files) {
  134. return -1;
  135. }
  136. int rv = -1;
  137. SMARTLIST_FOREACH_BEGIN(config_files, const char *, config_file) {
  138. config_line_t *included_config = NULL;
  139. config_line_t *included_config_last = NULL;
  140. if (config_get_included_config(config_file, recursion_level, extended,
  141. &included_config, &included_config_last,
  142. opened_lst) < 0) {
  143. goto done;
  144. }
  145. *next = included_config;
  146. if (included_config_last) {
  147. next = &included_config_last->next;
  148. *list_last = included_config_last;
  149. }
  150. } SMARTLIST_FOREACH_END(config_file);
  151. *list = ret_list;
  152. rv = 0;
  153. done:
  154. SMARTLIST_FOREACH(config_files, char *, f, tor_free(f));
  155. smartlist_free(config_files);
  156. return rv;
  157. }