tor  0.4.2.0-alpha-dev
confline.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 
18 #include "lib/encoding/confline.h"
19 #include "lib/encoding/cstring.h"
20 #include "lib/log/log.h"
21 #include "lib/log/util_bug.h"
22 #include "lib/malloc/malloc.h"
25 #include "lib/string/util_string.h"
26 
27 #include <string.h>
28 
31 void
33  const char *key,
34  const char *val)
35 {
36  tor_assert(lst);
37 
38  config_line_t *newline;
39 
40  newline = tor_malloc_zero(sizeof(config_line_t));
41  newline->key = tor_strdup(key);
42  newline->value = tor_strdup(val);
43  newline->next = NULL;
44  while (*lst)
45  lst = &((*lst)->next);
46 
47  (*lst) = newline;
48 }
49 
52 void
54  const char *key,
55  const char *val)
56 {
57  tor_assert(lst);
58 
59  config_line_t *newline;
60 
61  newline = tor_malloc_zero(sizeof(config_line_t));
62  newline->key = tor_strdup(key);
63  newline->value = tor_strdup(val);
64  newline->next = *lst;
65  *lst = newline;
66 }
67 
73 const config_line_t *
75  const char *key)
76 {
77  const config_line_t *cl;
78  for (cl = lines; cl; cl = cl->next) {
79  if (!strcmp(cl->key, key))
80  return cl;
81  }
82  return NULL;
83 }
84 
86 const config_line_t *
88  const char *key)
89 {
90  const config_line_t *cl;
91  for (cl = lines; cl; cl = cl->next) {
92  if (!strcasecmp(cl->key, key))
93  return cl;
94  }
95  return NULL;
96 }
97 
103 int
104 config_get_lines_aux(const char *string, config_line_t **result, int extended,
105  int allow_include, int *has_include,
106  struct smartlist_t *opened_lst, int recursion_level,
107  config_line_t **last,
108  include_handler_fn handle_include)
109 {
110  config_line_t *list = NULL, **next, *list_last = NULL;
111  char *k, *v;
112  const char *parse_err;
113  int include_used = 0;
114 
115  if (recursion_level > MAX_INCLUDE_RECURSION_LEVEL) {
116  log_warn(LD_CONFIG, "Error while parsing configuration: more than %d "
117  "nested %%includes.", MAX_INCLUDE_RECURSION_LEVEL);
118  return -1;
119  }
120 
121  next = &list;
122  do {
123  k = v = NULL;
124  string = parse_config_line_from_str_verbose(string, &k, &v, &parse_err);
125  if (!string) {
126  log_warn(LD_CONFIG, "Error while parsing configuration: %s",
127  parse_err?parse_err:"<unknown>");
128  config_free_lines(list);
129  tor_free(k);
130  tor_free(v);
131  return -1;
132  }
133  if (k && v) {
134  unsigned command = CONFIG_LINE_NORMAL;
135  if (extended) {
136  if (k[0] == '+') {
137  char *k_new = tor_strdup(k+1);
138  tor_free(k);
139  k = k_new;
140  command = CONFIG_LINE_APPEND;
141  } else if (k[0] == '/') {
142  char *k_new = tor_strdup(k+1);
143  tor_free(k);
144  k = k_new;
145  tor_free(v);
146  v = tor_strdup("");
147  command = CONFIG_LINE_CLEAR;
148  }
149  }
150 
151  if (allow_include && !strcmp(k, "%include") && handle_include) {
152  tor_free(k);
153  include_used = 1;
154 
155  config_line_t *include_list;
156  if (handle_include(v, recursion_level, extended, &include_list,
157  &list_last, opened_lst) < 0) {
158  log_warn(LD_CONFIG, "Error reading included configuration "
159  "file or directory: \"%s\".", v);
160  config_free_lines(list);
161  tor_free(v);
162  return -1;
163  }
164  log_notice(LD_CONFIG, "Included configuration file or "
165  "directory at recursion level %d: \"%s\".",
166  recursion_level, v);
167  *next = include_list;
168  if (list_last)
169  next = &list_last->next;
170  tor_free(v);
171  } else {
172  /* This list can get long, so we keep a pointer to the end of it
173  * rather than using config_line_append over and over and getting
174  * n^2 performance. */
175  *next = tor_malloc_zero(sizeof(**next));
176  (*next)->key = k;
177  (*next)->value = v;
178  (*next)->next = NULL;
179  (*next)->command = command;
180  list_last = *next;
181  next = &((*next)->next);
182  }
183  } else {
184  tor_free(k);
185  tor_free(v);
186  }
187  } while (*string);
188 
189  if (last) {
190  *last = list_last;
191  }
192  if (has_include) {
193  *has_include = include_used;
194  }
195  *result = list;
196  return 0;
197 }
198 
200 int
201 config_get_lines(const char *string, config_line_t **result, int extended)
202 {
203  return config_get_lines_aux(string, result, extended, 0, NULL, NULL, 1,
204  NULL, NULL);
205 }
206 
210 void
212 {
213  config_line_t *tmp;
214 
215  while (front) {
216  tmp = front;
217  front = tmp->next;
218 
219  tor_free(tmp->key);
220  tor_free(tmp->value);
221  tor_free(tmp);
222  }
223 }
224 
228 {
229  return config_lines_dup_and_filter(inp, NULL);
230 }
231 
237  const char *key)
238 {
239  config_line_t *result = NULL;
240  config_line_t **next_out = &result;
241  while (inp) {
242  if (key && strcasecmpstart(inp->key, key)) {
243  inp = inp->next;
244  continue;
245  }
246  *next_out = tor_malloc_zero(sizeof(config_line_t));
247  (*next_out)->key = tor_strdup(inp->key);
248  (*next_out)->value = tor_strdup(inp->value);
249  inp = inp->next;
250  next_out = &((*next_out)->next);
251  }
252  (*next_out) = NULL;
253  return result;
254 }
255 
258 int
260 {
261  while (a && b) {
262  if (strcasecmp(a->key, b->key) || strcmp(a->value, b->value))
263  return 0;
264  a = a->next;
265  b = b->next;
266  }
267  if (a || b)
268  return 0;
269  return 1;
270 }
271 
273 int
274 config_count_key(const config_line_t *a, const char *key)
275 {
276  int n = 0;
277  while (a) {
278  if (!strcasecmp(a->key, key)) {
279  ++n;
280  }
281  a = a->next;
282  }
283  return n;
284 }
285 
295 const char *
296 parse_config_line_from_str_verbose(const char *line, char **key_out,
297  char **value_out,
298  const char **err_out)
299 {
300  /*
301  See torrc_format.txt for a description of the (silly) format this parses.
302  */
303  const char *key, *val, *cp;
304  int continuation = 0;
305 
306  tor_assert(key_out);
307  tor_assert(value_out);
308 
309  *key_out = *value_out = NULL;
310  key = val = NULL;
311  /* Skip until the first keyword. */
312  while (1) {
313  while (TOR_ISSPACE(*line))
314  ++line;
315  if (*line == '#') {
316  while (*line && *line != '\n')
317  ++line;
318  } else {
319  break;
320  }
321  }
322 
323  if (!*line) { /* End of string? */
324  *key_out = *value_out = NULL;
325  return line;
326  }
327 
328  /* Skip until the next space or \ followed by newline. */
329  key = line;
330  while (*line && !TOR_ISSPACE(*line) && *line != '#' &&
331  ! (line[0] == '\\' && line[1] == '\n'))
332  ++line;
333  *key_out = tor_strndup(key, line-key);
334 
335  /* Skip until the value. */
336  while (*line == ' ' || *line == '\t')
337  ++line;
338 
339  val = line;
340 
341  /* Find the end of the line. */
342  if (*line == '\"') { // XXX No continuation handling is done here
343  if (!(line = unescape_string(line, value_out, NULL))) {
344  if (err_out)
345  *err_out = "Invalid escape sequence in quoted string";
346  return NULL;
347  }
348  while (*line == ' ' || *line == '\t')
349  ++line;
350  if (*line == '\r' && *(++line) == '\n')
351  ++line;
352  if (*line && *line != '#' && *line != '\n') {
353  if (err_out)
354  *err_out = "Excess data after quoted string";
355  return NULL;
356  }
357  } else {
358  /* Look for the end of the line. */
359  while (*line && *line != '\n' && (*line != '#' || continuation)) {
360  if (*line == '\\' && line[1] == '\n') {
361  continuation = 1;
362  line += 2;
363  } else if (*line == '#') {
364  do {
365  ++line;
366  } while (*line && *line != '\n');
367  if (*line == '\n')
368  ++line;
369  } else {
370  ++line;
371  }
372  }
373 
374  if (*line == '\n') {
375  cp = line++;
376  } else {
377  cp = line;
378  }
379  /* Now back cp up to be the last nonspace character */
380  while (cp>val && TOR_ISSPACE(*(cp-1)))
381  --cp;
382 
383  tor_assert(cp >= val);
384 
385  /* Now copy out and decode the value. */
386  *value_out = tor_strndup(val, cp-val);
387  if (continuation) {
388  char *v_out, *v_in;
389  v_out = v_in = *value_out;
390  while (*v_in) {
391  if (*v_in == '#') {
392  do {
393  ++v_in;
394  } while (*v_in && *v_in != '\n');
395  if (*v_in == '\n')
396  ++v_in;
397  } else if (v_in[0] == '\\' && v_in[1] == '\n') {
398  v_in += 2;
399  } else {
400  *v_out++ = *v_in++;
401  }
402  }
403  *v_out = '\0';
404  }
405  }
406 
407  if (*line == '#') {
408  do {
409  ++line;
410  } while (*line && *line != '\n');
411  }
412  while (TOR_ISSPACE(*line)) ++line;
413 
414  return line;
415 }
Header for confline.c.
const char * parse_config_line_from_str_verbose(const char *line, char **key_out, char **value_out, const char **err_out)
Definition: confline.c:296
Header for cstring.c.
int config_lines_eq(const config_line_t *a, const config_line_t *b)
Definition: confline.c:259
#define CONFIG_LINE_APPEND
Definition: confline.h:22
#define tor_free(p)
Definition: malloc.h:52
Header for util_string.c.
const config_line_t * config_line_find_case(const config_line_t *lines, const char *key)
Definition: confline.c:87
int config_count_key(const config_line_t *a, const char *key)
Definition: confline.c:274
Headers for util_malloc.c.
int config_get_lines(const char *string, config_line_t **result, int extended)
Definition: confline.c:201
tor_assert(buffer)
config_line_t * config_lines_dup_and_filter(const config_line_t *inp, const char *key)
Definition: confline.c:236
int config_get_lines_aux(const char *string, config_line_t **result, int extended, int allow_include, int *has_include, struct smartlist_t *opened_lst, int recursion_level, config_line_t **last, include_handler_fn handle_include)
Definition: confline.c:104
config_line_t * config_lines_dup(const config_line_t *inp)
Definition: confline.c:227
void config_line_prepend(config_line_t **lst, const char *key, const char *val)
Definition: confline.c:53
Locale-independent character-type inspection (header)
const config_line_t * config_line_find(const config_line_t *lines, const char *key)
Definition: confline.c:74
void config_line_append(config_line_t **lst, const char *key, const char *val)
Definition: confline.c:32
Header for compat_string.c.
const char * unescape_string(const char *s, char **result, size_t *size_out)
Definition: cstring.c:30
void config_free_lines_(config_line_t *front)
Definition: confline.c:211
Headers for log.c.
#define CONFIG_LINE_NORMAL
Definition: confline.h:19
Macros to manage assertions, fatal and non-fatal.
int strcasecmpstart(const char *s1, const char *s2)
Definition: util_string.c:216
#define LD_CONFIG
Definition: log.h:66