tor  0.4.1.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 
90 int
91 config_get_lines_aux(const char *string, config_line_t **result, int extended,
92  int allow_include, int *has_include,
93  struct smartlist_t *opened_lst, int recursion_level,
94  config_line_t **last,
95  include_handler_fn handle_include)
96 {
97  config_line_t *list = NULL, **next, *list_last = NULL;
98  char *k, *v;
99  const char *parse_err;
100  int include_used = 0;
101 
102  if (recursion_level > MAX_INCLUDE_RECURSION_LEVEL) {
103  log_warn(LD_CONFIG, "Error while parsing configuration: more than %d "
104  "nested %%includes.", MAX_INCLUDE_RECURSION_LEVEL);
105  return -1;
106  }
107 
108  next = &list;
109  do {
110  k = v = NULL;
111  string = parse_config_line_from_str_verbose(string, &k, &v, &parse_err);
112  if (!string) {
113  log_warn(LD_CONFIG, "Error while parsing configuration: %s",
114  parse_err?parse_err:"<unknown>");
115  config_free_lines(list);
116  tor_free(k);
117  tor_free(v);
118  return -1;
119  }
120  if (k && v) {
121  unsigned command = CONFIG_LINE_NORMAL;
122  if (extended) {
123  if (k[0] == '+') {
124  char *k_new = tor_strdup(k+1);
125  tor_free(k);
126  k = k_new;
127  command = CONFIG_LINE_APPEND;
128  } else if (k[0] == '/') {
129  char *k_new = tor_strdup(k+1);
130  tor_free(k);
131  k = k_new;
132  tor_free(v);
133  v = tor_strdup("");
134  command = CONFIG_LINE_CLEAR;
135  }
136  }
137 
138  if (allow_include && !strcmp(k, "%include") && handle_include) {
139  tor_free(k);
140  include_used = 1;
141 
142  config_line_t *include_list;
143  if (handle_include(v, recursion_level, extended, &include_list,
144  &list_last, opened_lst) < 0) {
145  log_warn(LD_CONFIG, "Error reading included configuration "
146  "file or directory: \"%s\".", v);
147  config_free_lines(list);
148  tor_free(v);
149  return -1;
150  }
151  log_notice(LD_CONFIG, "Included configuration file or "
152  "directory at recursion level %d: \"%s\".",
153  recursion_level, v);
154  *next = include_list;
155  if (list_last)
156  next = &list_last->next;
157  tor_free(v);
158  } else {
159  /* This list can get long, so we keep a pointer to the end of it
160  * rather than using config_line_append over and over and getting
161  * n^2 performance. */
162  *next = tor_malloc_zero(sizeof(**next));
163  (*next)->key = k;
164  (*next)->value = v;
165  (*next)->next = NULL;
166  (*next)->command = command;
167  list_last = *next;
168  next = &((*next)->next);
169  }
170  } else {
171  tor_free(k);
172  tor_free(v);
173  }
174  } while (*string);
175 
176  if (last) {
177  *last = list_last;
178  }
179  if (has_include) {
180  *has_include = include_used;
181  }
182  *result = list;
183  return 0;
184 }
185 
187 int
188 config_get_lines(const char *string, config_line_t **result, int extended)
189 {
190  return config_get_lines_aux(string, result, extended, 0, NULL, NULL, 1,
191  NULL, NULL);
192 }
193 
197 void
199 {
200  config_line_t *tmp;
201 
202  while (front) {
203  tmp = front;
204  front = tmp->next;
205 
206  tor_free(tmp->key);
207  tor_free(tmp->value);
208  tor_free(tmp);
209  }
210 }
211 
215 {
216  return config_lines_dup_and_filter(inp, NULL);
217 }
218 
224  const char *key)
225 {
226  config_line_t *result = NULL;
227  config_line_t **next_out = &result;
228  while (inp) {
229  if (key && strcasecmpstart(inp->key, key)) {
230  inp = inp->next;
231  continue;
232  }
233  *next_out = tor_malloc_zero(sizeof(config_line_t));
234  (*next_out)->key = tor_strdup(inp->key);
235  (*next_out)->value = tor_strdup(inp->value);
236  inp = inp->next;
237  next_out = &((*next_out)->next);
238  }
239  (*next_out) = NULL;
240  return result;
241 }
242 
245 int
247 {
248  while (a && b) {
249  if (strcasecmp(a->key, b->key) || strcmp(a->value, b->value))
250  return 0;
251  a = a->next;
252  b = b->next;
253  }
254  if (a || b)
255  return 0;
256  return 1;
257 }
258 
260 int
261 config_count_key(const config_line_t *a, const char *key)
262 {
263  int n = 0;
264  while (a) {
265  if (!strcasecmp(a->key, key)) {
266  ++n;
267  }
268  a = a->next;
269  }
270  return n;
271 }
272 
282 const char *
283 parse_config_line_from_str_verbose(const char *line, char **key_out,
284  char **value_out,
285  const char **err_out)
286 {
287  /*
288  See torrc_format.txt for a description of the (silly) format this parses.
289  */
290  const char *key, *val, *cp;
291  int continuation = 0;
292 
293  tor_assert(key_out);
294  tor_assert(value_out);
295 
296  *key_out = *value_out = NULL;
297  key = val = NULL;
298  /* Skip until the first keyword. */
299  while (1) {
300  while (TOR_ISSPACE(*line))
301  ++line;
302  if (*line == '#') {
303  while (*line && *line != '\n')
304  ++line;
305  } else {
306  break;
307  }
308  }
309 
310  if (!*line) { /* End of string? */
311  *key_out = *value_out = NULL;
312  return line;
313  }
314 
315  /* Skip until the next space or \ followed by newline. */
316  key = line;
317  while (*line && !TOR_ISSPACE(*line) && *line != '#' &&
318  ! (line[0] == '\\' && line[1] == '\n'))
319  ++line;
320  *key_out = tor_strndup(key, line-key);
321 
322  /* Skip until the value. */
323  while (*line == ' ' || *line == '\t')
324  ++line;
325 
326  val = line;
327 
328  /* Find the end of the line. */
329  if (*line == '\"') { // XXX No continuation handling is done here
330  if (!(line = unescape_string(line, value_out, NULL))) {
331  if (err_out)
332  *err_out = "Invalid escape sequence in quoted string";
333  return NULL;
334  }
335  while (*line == ' ' || *line == '\t')
336  ++line;
337  if (*line == '\r' && *(++line) == '\n')
338  ++line;
339  if (*line && *line != '#' && *line != '\n') {
340  if (err_out)
341  *err_out = "Excess data after quoted string";
342  return NULL;
343  }
344  } else {
345  /* Look for the end of the line. */
346  while (*line && *line != '\n' && (*line != '#' || continuation)) {
347  if (*line == '\\' && line[1] == '\n') {
348  continuation = 1;
349  line += 2;
350  } else if (*line == '#') {
351  do {
352  ++line;
353  } while (*line && *line != '\n');
354  if (*line == '\n')
355  ++line;
356  } else {
357  ++line;
358  }
359  }
360 
361  if (*line == '\n') {
362  cp = line++;
363  } else {
364  cp = line;
365  }
366  /* Now back cp up to be the last nonspace character */
367  while (cp>val && TOR_ISSPACE(*(cp-1)))
368  --cp;
369 
370  tor_assert(cp >= val);
371 
372  /* Now copy out and decode the value. */
373  *value_out = tor_strndup(val, cp-val);
374  if (continuation) {
375  char *v_out, *v_in;
376  v_out = v_in = *value_out;
377  while (*v_in) {
378  if (*v_in == '#') {
379  do {
380  ++v_in;
381  } while (*v_in && *v_in != '\n');
382  if (*v_in == '\n')
383  ++v_in;
384  } else if (v_in[0] == '\\' && v_in[1] == '\n') {
385  v_in += 2;
386  } else {
387  *v_out++ = *v_in++;
388  }
389  }
390  *v_out = '\0';
391  }
392  }
393 
394  if (*line == '#') {
395  do {
396  ++line;
397  } while (*line && *line != '\n');
398  }
399  while (TOR_ISSPACE(*line)) ++line;
400 
401  return line;
402 }
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:283
Header for cstring.c.
#define CONFIG_LINE_APPEND
Definition: confline.h:22
#define tor_free(p)
Definition: malloc.h:52
Header for util_string.c.
int config_lines_eq(config_line_t *a, config_line_t *b)
Definition: confline.c:246
int config_count_key(const config_line_t *a, const char *key)
Definition: confline.c:261
Headers for util_malloc.c.
int config_get_lines(const char *string, config_line_t **result, int extended)
Definition: confline.c:188
tor_assert(buffer)
config_line_t * config_lines_dup_and_filter(const config_line_t *inp, const char *key)
Definition: confline.c:223
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:91
config_line_t * config_lines_dup(const config_line_t *inp)
Definition: confline.c:214
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:198
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:219
#define LD_CONFIG
Definition: log.h:65