]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/conf-parser.c
socket: add POSIX mqueue support
[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, t->ltype, 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 int ltype,
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) {
243 log_error("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue);
244 return r;
245 }
246
247 return 0;
248 }
249
250 int config_parse_long(
251 const char *filename,
252 unsigned line,
253 const char *section,
254 const char *lvalue,
255 int ltype,
256 const char *rvalue,
257 void *data,
258 void *userdata) {
259
260 long *i = data;
261 int r;
262
263 assert(filename);
264 assert(lvalue);
265 assert(rvalue);
266 assert(data);
267
268 if ((r = safe_atoli(rvalue, i)) < 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
276 int config_parse_uint64(
277 const char *filename,
278 unsigned line,
279 const char *section,
280 const char *lvalue,
281 int ltype,
282 const char *rvalue,
283 void *data,
284 void *userdata) {
285
286 uint64_t *u = data;
287 int r;
288
289 assert(filename);
290 assert(lvalue);
291 assert(rvalue);
292 assert(data);
293
294 if ((r = safe_atou64(rvalue, u)) < 0) {
295 log_error("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue);
296 return r;
297 }
298
299 return 0;
300 }
301
302 int config_parse_unsigned(
303 const char *filename,
304 unsigned line,
305 const char *section,
306 const char *lvalue,
307 int ltype,
308 const char *rvalue,
309 void *data,
310 void *userdata) {
311
312 unsigned *u = data;
313 int r;
314
315 assert(filename);
316 assert(lvalue);
317 assert(rvalue);
318 assert(data);
319
320 if ((r = safe_atou(rvalue, u)) < 0) {
321 log_error("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue);
322 return r;
323 }
324
325 return 0;
326 }
327
328 int config_parse_size(
329 const char *filename,
330 unsigned line,
331 const char *section,
332 const char *lvalue,
333 int ltype,
334 const char *rvalue,
335 void *data,
336 void *userdata) {
337
338 size_t *sz = data;
339 unsigned u;
340 int r;
341
342 assert(filename);
343 assert(lvalue);
344 assert(rvalue);
345 assert(data);
346
347 if ((r = safe_atou(rvalue, &u)) < 0) {
348 log_error("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue);
349 return r;
350 }
351
352 *sz = (size_t) u;
353 return 0;
354 }
355
356 int config_parse_bool(
357 const char *filename,
358 unsigned line,
359 const char *section,
360 const char *lvalue,
361 int ltype,
362 const char *rvalue,
363 void *data,
364 void *userdata) {
365
366 int k;
367 bool *b = data;
368
369 assert(filename);
370 assert(lvalue);
371 assert(rvalue);
372 assert(data);
373
374 if ((k = parse_boolean(rvalue)) < 0) {
375 log_error("[%s:%u] Failed to parse boolean value: %s", filename, line, rvalue);
376 return k;
377 }
378
379 *b = !!k;
380 return 0;
381 }
382
383 int config_parse_string(
384 const char *filename,
385 unsigned line,
386 const char *section,
387 const char *lvalue,
388 int ltype,
389 const char *rvalue,
390 void *data,
391 void *userdata) {
392
393 char **s = data;
394 char *n;
395
396 assert(filename);
397 assert(lvalue);
398 assert(rvalue);
399 assert(data);
400
401 if (*rvalue) {
402 if (!(n = strdup(rvalue)))
403 return -ENOMEM;
404 } else
405 n = NULL;
406
407 free(*s);
408 *s = n;
409
410 return 0;
411 }
412
413 int config_parse_path(
414 const char *filename,
415 unsigned line,
416 const char *section,
417 const char *lvalue,
418 int ltype,
419 const char *rvalue,
420 void *data,
421 void *userdata) {
422
423 char **s = data;
424 char *n;
425
426 assert(filename);
427 assert(lvalue);
428 assert(rvalue);
429 assert(data);
430
431 if (!path_is_absolute(rvalue)) {
432 log_error("[%s:%u] Not an absolute path: %s", filename, line, rvalue);
433 return -EINVAL;
434 }
435
436 if (!(n = strdup(rvalue)))
437 return -ENOMEM;
438
439 path_kill_slashes(n);
440
441 free(*s);
442 *s = n;
443
444 return 0;
445 }
446
447 int config_parse_strv(
448 const char *filename,
449 unsigned line,
450 const char *section,
451 const char *lvalue,
452 int ltype,
453 const char *rvalue,
454 void *data,
455 void *userdata) {
456
457 char*** sv = data;
458 char **n;
459 char *w;
460 unsigned k;
461 size_t l;
462 char *state;
463
464 assert(filename);
465 assert(lvalue);
466 assert(rvalue);
467 assert(data);
468
469 k = strv_length(*sv);
470 FOREACH_WORD_QUOTED(w, l, rvalue, state)
471 k++;
472
473 if (!(n = new(char*, k+1)))
474 return -ENOMEM;
475
476 if (*sv)
477 for (k = 0; (*sv)[k]; k++)
478 n[k] = (*sv)[k];
479 else
480 k = 0;
481
482 FOREACH_WORD_QUOTED(w, l, rvalue, state)
483 if (!(n[k++] = cunescape_length(w, l)))
484 goto fail;
485
486 n[k] = NULL;
487 free(*sv);
488 *sv = n;
489
490 return 0;
491
492 fail:
493 for (; k > 0; k--)
494 free(n[k-1]);
495 free(n);
496
497 return -ENOMEM;
498 }
499
500 int config_parse_path_strv(
501 const char *filename,
502 unsigned line,
503 const char *section,
504 const char *lvalue,
505 int ltype,
506 const char *rvalue,
507 void *data,
508 void *userdata) {
509
510 char*** sv = data;
511 char **n;
512 char *w;
513 unsigned k;
514 size_t l;
515 char *state;
516 int r;
517
518 assert(filename);
519 assert(lvalue);
520 assert(rvalue);
521 assert(data);
522
523 k = strv_length(*sv);
524 FOREACH_WORD_QUOTED(w, l, rvalue, state)
525 k++;
526
527 if (!(n = new(char*, k+1)))
528 return -ENOMEM;
529
530 k = 0;
531 if (*sv)
532 for (; (*sv)[k]; k++)
533 n[k] = (*sv)[k];
534
535 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
536 if (!(n[k] = cunescape_length(w, l))) {
537 r = -ENOMEM;
538 goto fail;
539 }
540
541 if (!path_is_absolute(n[k])) {
542 log_error("[%s:%u] Not an absolute path: %s", filename, line, rvalue);
543 r = -EINVAL;
544 goto fail;
545 }
546
547 path_kill_slashes(n[k]);
548
549 k++;
550 }
551
552 n[k] = NULL;
553 free(*sv);
554 *sv = n;
555
556 return 0;
557
558 fail:
559 free(n[k]);
560 for (; k > 0; k--)
561 free(n[k-1]);
562 free(n);
563
564 return r;
565 }