]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/conf-parser.c
dbus: add service D-Bus property "Sockets"
[thirdparty/systemd.git] / src / conf-parser.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
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
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"
31 #include "strv.h"
32 #include "log.h"
33
34 /* Run the user supplied parser for an assignment */
35 static int next_assignment(
36 const char *filename,
37 unsigned line,
38 const char *section,
39 const ConfigItem *t,
40 bool relaxed,
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
50 for (; t->parse || t->lvalue; t++) {
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
61 if (!t->parse)
62 return 0;
63
64 return t->parse(filename, line, section, lvalue, rvalue, t->data, userdata);
65 }
66
67 /* Warn about unknown non-extension fields. */
68 if (!relaxed && !startswith(lvalue, "X-"))
69 log_info("[%s:%u] Unknown lvalue '%s' in section '%s'. Ignoring.", filename, line, lvalue, strna(section));
70
71 return 0;
72 }
73
74 /* Parse a variable assignment line */
75 static int parse_line(const char *filename, unsigned line, char **section, const char* const * sections, const ConfigItem *t, bool relaxed, char *l, void *userdata) {
76 char *e;
77
78 l = strstrip(l);
79
80 if (!*l)
81 return 0;
82
83 if (strchr(COMMENTS, *l))
84 return 0;
85
86 if (startswith(l, ".include ")) {
87 char *fn;
88 int r;
89
90 if (!(fn = file_in_same_dir(filename, strstrip(l+9))))
91 return -ENOMEM;
92
93 r = config_parse(fn, NULL, sections, t, relaxed, userdata);
94 free(fn);
95
96 return r;
97 }
98
99 if (*l == '[') {
100 size_t k;
101 char *n;
102
103 k = strlen(l);
104 assert(k > 0);
105
106 if (l[k-1] != ']') {
107 log_error("[%s:%u] Invalid section header.", filename, line);
108 return -EBADMSG;
109 }
110
111 if (!(n = strndup(l+1, k-2)))
112 return -ENOMEM;
113
114 if (!relaxed && sections && !strv_contains((char**) sections, n))
115 log_info("[%s:%u] Unknown section '%s'. Ignoring.", filename, line, n);
116
117 free(*section);
118 *section = n;
119
120 return 0;
121 }
122
123 if (sections && (!*section || !strv_contains((char**) sections, *section)))
124 return 0;
125
126 if (!(e = strchr(l, '='))) {
127 log_error("[%s:%u] Missing '='.", filename, line);
128 return -EBADMSG;
129 }
130
131 *e = 0;
132 e++;
133
134 return next_assignment(filename, line, *section, t, relaxed, strstrip(l), strstrip(e), userdata);
135 }
136
137 /* Go through the file and parse each line */
138 int config_parse(const char *filename, FILE *f, const char* const * sections, const ConfigItem *t, bool relaxed, void *userdata) {
139 unsigned line = 0;
140 char *section = NULL;
141 int r;
142 bool ours = false;
143 char *continuation = NULL;
144
145 assert(filename);
146 assert(t);
147
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 }
154
155 ours = true;
156 }
157
158 while (!feof(f)) {
159 char l[LINE_MAX], *p, *c = NULL, *e;
160 bool escaped = false;
161
162 if (!fgets(l, sizeof(l), f)) {
163 if (feof(f))
164 break;
165
166 r = -errno;
167 log_error("Failed to read configuration file '%s': %s", filename, strerror(-r));
168 goto finish;
169 }
170
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)
209 goto finish;
210 }
211
212 r = 0;
213
214 finish:
215 free(section);
216 free(continuation);
217
218 if (f && ours)
219 fclose(f);
220
221 return r;
222 }
223
224 int config_parse_int(
225 const char *filename,
226 unsigned line,
227 const char *section,
228 const char *lvalue,
229 const char *rvalue,
230 void *data,
231 void *userdata) {
232
233 int *i = data;
234 int r;
235
236 assert(filename);
237 assert(lvalue);
238 assert(rvalue);
239 assert(data);
240
241 if ((r = safe_atoi(rvalue, i)) < 0) {
242 log_error("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue);
243 return r;
244 }
245
246 return 0;
247 }
248
249 int config_parse_uint64(
250 const char *filename,
251 unsigned line,
252 const char *section,
253 const char *lvalue,
254 const char *rvalue,
255 void *data,
256 void *userdata) {
257
258 uint64_t *u = data;
259 int r;
260
261 assert(filename);
262 assert(lvalue);
263 assert(rvalue);
264 assert(data);
265
266 if ((r = safe_atou64(rvalue, u)) < 0) {
267 log_error("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue);
268 return r;
269 }
270
271 return 0;
272 }
273
274 int config_parse_unsigned(
275 const char *filename,
276 unsigned line,
277 const char *section,
278 const char *lvalue,
279 const char *rvalue,
280 void *data,
281 void *userdata) {
282
283 unsigned *u = data;
284 int r;
285
286 assert(filename);
287 assert(lvalue);
288 assert(rvalue);
289 assert(data);
290
291 if ((r = safe_atou(rvalue, u)) < 0) {
292 log_error("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue);
293 return r;
294 }
295
296 return 0;
297 }
298
299 int config_parse_size(
300 const char *filename,
301 unsigned line,
302 const char *section,
303 const char *lvalue,
304 const char *rvalue,
305 void *data,
306 void *userdata) {
307
308 size_t *sz = data;
309 unsigned u;
310 int r;
311
312 assert(filename);
313 assert(lvalue);
314 assert(rvalue);
315 assert(data);
316
317 if ((r = safe_atou(rvalue, &u)) < 0) {
318 log_error("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue);
319 return r;
320 }
321
322 *sz = (size_t) u;
323 return 0;
324 }
325
326 int config_parse_bool(
327 const char *filename,
328 unsigned line,
329 const char *section,
330 const char *lvalue,
331 const char *rvalue,
332 void *data,
333 void *userdata) {
334
335 int k;
336 bool *b = data;
337
338 assert(filename);
339 assert(lvalue);
340 assert(rvalue);
341 assert(data);
342
343 if ((k = parse_boolean(rvalue)) < 0) {
344 log_error("[%s:%u] Failed to parse boolean value: %s", filename, line, rvalue);
345 return k;
346 }
347
348 *b = !!k;
349 return 0;
350 }
351
352 int config_parse_string(
353 const char *filename,
354 unsigned line,
355 const char *section,
356 const char *lvalue,
357 const char *rvalue,
358 void *data,
359 void *userdata) {
360
361 char **s = data;
362 char *n;
363
364 assert(filename);
365 assert(lvalue);
366 assert(rvalue);
367 assert(data);
368
369 if (*rvalue) {
370 if (!(n = strdup(rvalue)))
371 return -ENOMEM;
372 } else
373 n = NULL;
374
375 free(*s);
376 *s = n;
377
378 return 0;
379 }
380
381 int config_parse_path(
382 const char *filename,
383 unsigned line,
384 const char *section,
385 const char *lvalue,
386 const char *rvalue,
387 void *data,
388 void *userdata) {
389
390 char **s = data;
391 char *n;
392
393 assert(filename);
394 assert(lvalue);
395 assert(rvalue);
396 assert(data);
397
398 if (!path_is_absolute(rvalue)) {
399 log_error("[%s:%u] Not an absolute path: %s", filename, line, rvalue);
400 return -EINVAL;
401 }
402
403 if (!(n = strdup(rvalue)))
404 return -ENOMEM;
405
406 path_kill_slashes(n);
407
408 free(*s);
409 *s = n;
410
411 return 0;
412 }
413
414 int config_parse_strv(
415 const char *filename,
416 unsigned line,
417 const char *section,
418 const char *lvalue,
419 const char *rvalue,
420 void *data,
421 void *userdata) {
422
423 char*** sv = data;
424 char **n;
425 char *w;
426 unsigned k;
427 size_t l;
428 char *state;
429
430 assert(filename);
431 assert(lvalue);
432 assert(rvalue);
433 assert(data);
434
435 k = strv_length(*sv);
436 FOREACH_WORD_QUOTED(w, l, rvalue, state)
437 k++;
438
439 if (!(n = new(char*, k+1)))
440 return -ENOMEM;
441
442 if (*sv)
443 for (k = 0; (*sv)[k]; k++)
444 n[k] = (*sv)[k];
445 else
446 k = 0;
447
448 FOREACH_WORD_QUOTED(w, l, rvalue, state)
449 if (!(n[k++] = cunescape_length(w, l)))
450 goto fail;
451
452 n[k] = NULL;
453 free(*sv);
454 *sv = n;
455
456 return 0;
457
458 fail:
459 for (; k > 0; k--)
460 free(n[k-1]);
461 free(n);
462
463 return -ENOMEM;
464 }
465
466 int config_parse_path_strv(
467 const char *filename,
468 unsigned line,
469 const char *section,
470 const char *lvalue,
471 const char *rvalue,
472 void *data,
473 void *userdata) {
474
475 char*** sv = data;
476 char **n;
477 char *w;
478 unsigned k;
479 size_t l;
480 char *state;
481 int r;
482
483 assert(filename);
484 assert(lvalue);
485 assert(rvalue);
486 assert(data);
487
488 k = strv_length(*sv);
489 FOREACH_WORD_QUOTED(w, l, rvalue, state)
490 k++;
491
492 if (!(n = new(char*, k+1)))
493 return -ENOMEM;
494
495 k = 0;
496 if (*sv)
497 for (; (*sv)[k]; k++)
498 n[k] = (*sv)[k];
499
500 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
501 if (!(n[k] = cunescape_length(w, l))) {
502 r = -ENOMEM;
503 goto fail;
504 }
505
506 if (!path_is_absolute(n[k])) {
507 log_error("[%s:%u] Not an absolute path: %s", filename, line, rvalue);
508 r = -EINVAL;
509 goto fail;
510 }
511
512 path_kill_slashes(n[k]);
513
514 k++;
515 }
516
517 n[k] = NULL;
518 free(*sv);
519 *sv = n;
520
521 return 0;
522
523 fail:
524 free(n[k]);
525 for (; k > 0; k--)
526 free(n[k-1]);
527 free(n);
528
529 return r;
530 }