]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/conf-parser.c
update TODO
[thirdparty/systemd.git] / src / conf-parser.c
CommitLineData
d6c9574f 1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
ed5bcfbe 2
a7334b09
LP
3/***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
ed5bcfbe
LP
22#include <string.h>
23#include <stdio.h>
24#include <errno.h>
25#include <assert.h>
26#include <stdlib.h>
27
28#include "conf-parser.h"
29#include "util.h"
30#include "macro.h"
57d42a5f 31#include "strv.h"
16354eff 32#include "log.h"
ed5bcfbe 33
ed5bcfbe
LP
34/* Run the user supplied parser for an assignment */
35static int next_assignment(
36 const char *filename,
37 unsigned line,
38 const char *section,
39 const ConfigItem *t,
10e87ee7 40 bool relaxed,
ed5bcfbe
LP
41 const char *lvalue,
42 const char *rvalue,
43 void *userdata) {
44
45 assert(filename);
46 assert(t);
47 assert(lvalue);
48 assert(rvalue);
49
827119a9 50 for (; t->parse || t->lvalue; t++) {
ed5bcfbe
LP
51
52 if (t->lvalue && !streq(lvalue, t->lvalue))
53 continue;
54
55 if (t->section && !section)
56 continue;
57
58 if (t->section && !streq(section, t->section))
59 continue;
60
10e87ee7
LP
61 if (!t->parse)
62 return 0;
63
2b583ce6 64 return t->parse(filename, line, section, lvalue, t->ltype, rvalue, t->data, userdata);
ed5bcfbe
LP
65 }
66
46205bb6 67 /* Warn about unknown non-extension fields. */
10e87ee7 68 if (!relaxed && !startswith(lvalue, "X-"))
46205bb6
LP
69 log_info("[%s:%u] Unknown lvalue '%s' in section '%s'. Ignoring.", filename, line, lvalue, strna(section));
70
f1857be0 71 return 0;
ed5bcfbe
LP
72}
73
ed5bcfbe 74/* Parse a variable assignment line */
10e87ee7 75static int parse_line(const char *filename, unsigned line, char **section, const char* const * sections, const ConfigItem *t, bool relaxed, char *l, void *userdata) {
b2aa81ef 76 char *e;
ed5bcfbe 77
b2aa81ef 78 l = strstrip(l);
ed5bcfbe 79
b2aa81ef 80 if (!*l)
ed5bcfbe 81 return 0;
1ea86b18 82
b2aa81ef 83 if (strchr(COMMENTS, *l))
1ea86b18 84 return 0;
ed5bcfbe 85
b2aa81ef
LP
86 if (startswith(l, ".include ")) {
87 char *fn;
ed5bcfbe
LP
88 int r;
89
b2aa81ef
LP
90 if (!(fn = file_in_same_dir(filename, strstrip(l+9))))
91 return -ENOMEM;
ed5bcfbe 92
10e87ee7 93 r = config_parse(fn, NULL, sections, t, relaxed, userdata);
b2aa81ef
LP
94 free(fn);
95
ed5bcfbe
LP
96 return r;
97 }
98
b2aa81ef 99 if (*l == '[') {
ed5bcfbe
LP
100 size_t k;
101 char *n;
102
b2aa81ef 103 k = strlen(l);
ed5bcfbe
LP
104 assert(k > 0);
105
b2aa81ef 106 if (l[k-1] != ']') {
16354eff 107 log_error("[%s:%u] Invalid section header.", filename, line);
ed5bcfbe
LP
108 return -EBADMSG;
109 }
110
b2aa81ef 111 if (!(n = strndup(l+1, k-2)))
ed5bcfbe
LP
112 return -ENOMEM;
113
10e87ee7
LP
114 if (!relaxed && sections && !strv_contains((char**) sections, n))
115 log_info("[%s:%u] Unknown section '%s'. Ignoring.", filename, line, n);
42f4e3c4 116
ed5bcfbe
LP
117 free(*section);
118 *section = n;
119
120 return 0;
121 }
122
449648c4 123 if (sections && (!*section || !strv_contains((char**) sections, *section)))
10e87ee7
LP
124 return 0;
125
b2aa81ef 126 if (!(e = strchr(l, '='))) {
16354eff 127 log_error("[%s:%u] Missing '='.", filename, line);
ed5bcfbe
LP
128 return -EBADMSG;
129 }
130
131 *e = 0;
132 e++;
133
10e87ee7 134 return next_assignment(filename, line, *section, t, relaxed, strstrip(l), strstrip(e), userdata);
ed5bcfbe
LP
135}
136
137/* Go through the file and parse each line */
10e87ee7 138int config_parse(const char *filename, FILE *f, const char* const * sections, const ConfigItem *t, bool relaxed, void *userdata) {
ed5bcfbe
LP
139 unsigned line = 0;
140 char *section = NULL;
ed5bcfbe 141 int r;
63ad1ab4 142 bool ours = false;
3dab2943 143 char *continuation = NULL;
ed5bcfbe
LP
144
145 assert(filename);
146 assert(t);
147
87f0e418
LP
148 if (!f) {
149 if (!(f = fopen(filename, "re"))) {
150 r = -errno;
151 log_error("Failed to open configuration file '%s': %s", filename, strerror(-r));
152 goto finish;
153 }
63ad1ab4
LP
154
155 ours = true;
ed5bcfbe
LP
156 }
157
158 while (!feof(f)) {
3dab2943
LP
159 char l[LINE_MAX], *p, *c = NULL, *e;
160 bool escaped = false;
ed5bcfbe
LP
161
162 if (!fgets(l, sizeof(l), f)) {
163 if (feof(f))
164 break;
165
166 r = -errno;
16354eff 167 log_error("Failed to read configuration file '%s': %s", filename, strerror(-r));
ed5bcfbe
LP
168 goto finish;
169 }
170
3dab2943
LP
171 truncate_nl(l);
172
173 if (continuation) {
174 if (!(c = strappend(continuation, l))) {
175 r = -ENOMEM;
176 goto finish;
177 }
178
179 free(continuation);
180 continuation = NULL;
181 p = c;
182 } else
183 p = l;
184
185 for (e = p; *e; e++) {
186 if (escaped)
187 escaped = false;
188 else if (*e == '\\')
189 escaped = true;
190 }
191
192 if (escaped) {
193 *(e-1) = ' ';
194
195 if (c)
196 continuation = c;
197 else if (!(continuation = strdup(l))) {
198 r = -ENOMEM;
199 goto finish;
200 }
201
202 continue;
203 }
204
205 r = parse_line(filename, ++line, &section, sections, t, relaxed, p, userdata);
206 free(c);
207
208 if (r < 0)
ed5bcfbe
LP
209 goto finish;
210 }
211
212 r = 0;
213
214finish:
215 free(section);
3dab2943 216 free(continuation);
ed5bcfbe 217
63ad1ab4 218 if (f && ours)
ed5bcfbe
LP
219 fclose(f);
220
221 return r;
222}
223
224int config_parse_int(
225 const char *filename,
226 unsigned line,
227 const char *section,
228 const char *lvalue,
2b583ce6 229 int ltype,
ed5bcfbe
LP
230 const char *rvalue,
231 void *data,
232 void *userdata) {
233
234 int *i = data;
235 int r;
236
237 assert(filename);
238 assert(lvalue);
239 assert(rvalue);
240 assert(data);
241
242 if ((r = safe_atoi(rvalue, i)) < 0) {
16354eff 243 log_error("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue);
ed5bcfbe
LP
244 return r;
245 }
246
247 return 0;
248}
249
ec863ba6
LP
250int config_parse_uint64(
251 const char *filename,
252 unsigned line,
253 const char *section,
254 const char *lvalue,
2b583ce6 255 int ltype,
ec863ba6
LP
256 const char *rvalue,
257 void *data,
258 void *userdata) {
259
260 uint64_t *u = data;
261 int r;
262
263 assert(filename);
264 assert(lvalue);
265 assert(rvalue);
266 assert(data);
267
268 if ((r = safe_atou64(rvalue, u)) < 0) {
269 log_error("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue);
270 return r;
271 }
272
273 return 0;
274}
275
ed5bcfbe
LP
276int config_parse_unsigned(
277 const char *filename,
278 unsigned line,
279 const char *section,
280 const char *lvalue,
2b583ce6 281 int ltype,
ed5bcfbe
LP
282 const char *rvalue,
283 void *data,
284 void *userdata) {
285
286 unsigned *u = data;
287 int r;
288
289 assert(filename);
290 assert(lvalue);
291 assert(rvalue);
292 assert(data);
293
294 if ((r = safe_atou(rvalue, u)) < 0) {
16354eff 295 log_error("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue);
ed5bcfbe
LP
296 return r;
297 }
298
299 return 0;
300}
301
302int config_parse_size(
303 const char *filename,
304 unsigned line,
305 const char *section,
306 const char *lvalue,
2b583ce6 307 int ltype,
ed5bcfbe
LP
308 const char *rvalue,
309 void *data,
310 void *userdata) {
311
312 size_t *sz = data;
313 unsigned u;
314 int r;
315
316 assert(filename);
317 assert(lvalue);
318 assert(rvalue);
319 assert(data);
320
321 if ((r = safe_atou(rvalue, &u)) < 0) {
16354eff 322 log_error("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue);
ed5bcfbe
LP
323 return r;
324 }
325
326 *sz = (size_t) u;
327 return 0;
328}
329
330int config_parse_bool(
331 const char *filename,
332 unsigned line,
333 const char *section,
334 const char *lvalue,
2b583ce6 335 int ltype,
ed5bcfbe
LP
336 const char *rvalue,
337 void *data,
338 void *userdata) {
339
340 int k;
341 bool *b = data;
342
343 assert(filename);
344 assert(lvalue);
345 assert(rvalue);
346 assert(data);
347
348 if ((k = parse_boolean(rvalue)) < 0) {
16354eff 349 log_error("[%s:%u] Failed to parse boolean value: %s", filename, line, rvalue);
ed5bcfbe
LP
350 return k;
351 }
352
353 *b = !!k;
354 return 0;
355}
356
357int config_parse_string(
358 const char *filename,
359 unsigned line,
360 const char *section,
361 const char *lvalue,
2b583ce6 362 int ltype,
ed5bcfbe
LP
363 const char *rvalue,
364 void *data,
365 void *userdata) {
366
367 char **s = data;
368 char *n;
369
370 assert(filename);
371 assert(lvalue);
372 assert(rvalue);
373 assert(data);
374
375 if (*rvalue) {
376 if (!(n = strdup(rvalue)))
377 return -ENOMEM;
378 } else
379 n = NULL;
380
381 free(*s);
382 *s = n;
383
384 return 0;
385}
57d42a5f 386
034c6ed7
LP
387int config_parse_path(
388 const char *filename,
389 unsigned line,
390 const char *section,
391 const char *lvalue,
2b583ce6 392 int ltype,
034c6ed7
LP
393 const char *rvalue,
394 void *data,
395 void *userdata) {
396
397 char **s = data;
398 char *n;
399
400 assert(filename);
401 assert(lvalue);
402 assert(rvalue);
403 assert(data);
404
15ae422b 405 if (!path_is_absolute(rvalue)) {
034c6ed7
LP
406 log_error("[%s:%u] Not an absolute path: %s", filename, line, rvalue);
407 return -EINVAL;
408 }
409
410 if (!(n = strdup(rvalue)))
411 return -ENOMEM;
412
01f78473
LP
413 path_kill_slashes(n);
414
034c6ed7
LP
415 free(*s);
416 *s = n;
417
418 return 0;
419}
57d42a5f
LP
420
421int config_parse_strv(
422 const char *filename,
423 unsigned line,
424 const char *section,
425 const char *lvalue,
2b583ce6 426 int ltype,
57d42a5f
LP
427 const char *rvalue,
428 void *data,
429 void *userdata) {
430
431 char*** sv = data;
432 char **n;
433 char *w;
434 unsigned k;
435 size_t l;
436 char *state;
437
438 assert(filename);
439 assert(lvalue);
440 assert(rvalue);
441 assert(data);
442
443 k = strv_length(*sv);
034c6ed7 444 FOREACH_WORD_QUOTED(w, l, rvalue, state)
57d42a5f
LP
445 k++;
446
447 if (!(n = new(char*, k+1)))
448 return -ENOMEM;
449
3251df7d
LP
450 if (*sv)
451 for (k = 0; (*sv)[k]; k++)
452 n[k] = (*sv)[k];
7418040c
LP
453 else
454 k = 0;
3251df7d 455
034c6ed7 456 FOREACH_WORD_QUOTED(w, l, rvalue, state)
f60f22df 457 if (!(n[k++] = cunescape_length(w, l)))
57d42a5f
LP
458 goto fail;
459
460 n[k] = NULL;
461 free(*sv);
462 *sv = n;
463
464 return 0;
465
466fail:
467 for (; k > 0; k--)
468 free(n[k-1]);
034c6ed7 469 free(n);
57d42a5f
LP
470
471 return -ENOMEM;
472}
15ae422b
LP
473
474int config_parse_path_strv(
475 const char *filename,
476 unsigned line,
477 const char *section,
478 const char *lvalue,
2b583ce6 479 int ltype,
15ae422b
LP
480 const char *rvalue,
481 void *data,
482 void *userdata) {
483
484 char*** sv = data;
485 char **n;
486 char *w;
487 unsigned k;
488 size_t l;
489 char *state;
490 int r;
491
492 assert(filename);
493 assert(lvalue);
494 assert(rvalue);
495 assert(data);
496
497 k = strv_length(*sv);
498 FOREACH_WORD_QUOTED(w, l, rvalue, state)
499 k++;
500
501 if (!(n = new(char*, k+1)))
502 return -ENOMEM;
503
504 k = 0;
505 if (*sv)
506 for (; (*sv)[k]; k++)
507 n[k] = (*sv)[k];
508
509 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
f60f22df 510 if (!(n[k] = cunescape_length(w, l))) {
15ae422b
LP
511 r = -ENOMEM;
512 goto fail;
513 }
514
515 if (!path_is_absolute(n[k])) {
516 log_error("[%s:%u] Not an absolute path: %s", filename, line, rvalue);
517 r = -EINVAL;
518 goto fail;
519 }
520
01f78473
LP
521 path_kill_slashes(n[k]);
522
15ae422b
LP
523 k++;
524 }
525
526 n[k] = NULL;
527 free(*sv);
528 *sv = n;
529
530 return 0;
531
532fail:
533 free(n[k]);
534 for (; k > 0; k--)
535 free(n[k-1]);
536 free(n);
537
538 return r;
539}