]> git.ipfire.org Git - thirdparty/systemd.git/blame - conf-parser.c
execute: support basic filesystem namespacing
[thirdparty/systemd.git] / conf-parser.c
CommitLineData
ed5bcfbe
LP
1/*-*- Mode: C; c-basic-offset: 8 -*-*/
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#define COMMENTS "#;\n"
35#define LINE_MAX 4096
36
37/* Run the user supplied parser for an assignment */
38static int next_assignment(
39 const char *filename,
40 unsigned line,
41 const char *section,
42 const ConfigItem *t,
43 const char *lvalue,
44 const char *rvalue,
45 void *userdata) {
46
47 assert(filename);
48 assert(t);
49 assert(lvalue);
50 assert(rvalue);
51
52 for (; t->parse; t++) {
53
54 if (t->lvalue && !streq(lvalue, t->lvalue))
55 continue;
56
57 if (t->section && !section)
58 continue;
59
60 if (t->section && !streq(section, t->section))
61 continue;
62
63 return t->parse(filename, line, section, lvalue, rvalue, t->data, userdata);
64 }
65
46205bb6
LP
66 /* Warn about unknown non-extension fields. */
67 if (!startswith(lvalue, "X-"))
68 log_info("[%s:%u] Unknown lvalue '%s' in section '%s'. Ignoring.", filename, line, lvalue, strna(section));
69
f1857be0 70 return 0;
ed5bcfbe
LP
71}
72
ed5bcfbe 73/* Parse a variable assignment line */
42f4e3c4 74static int parse_line(const char *filename, unsigned line, char **section, const char* const * sections, const ConfigItem *t, char *l, void *userdata) {
b2aa81ef 75 char *e;
ed5bcfbe 76
b2aa81ef 77 l = strstrip(l);
ed5bcfbe 78
b2aa81ef 79 if (!*l)
ed5bcfbe 80 return 0;
1ea86b18 81
b2aa81ef 82 if (strchr(COMMENTS, *l))
1ea86b18 83 return 0;
ed5bcfbe 84
b2aa81ef
LP
85 if (startswith(l, ".include ")) {
86 char *fn;
ed5bcfbe
LP
87 int r;
88
b2aa81ef
LP
89 if (!(fn = file_in_same_dir(filename, strstrip(l+9))))
90 return -ENOMEM;
ed5bcfbe 91
87f0e418 92 r = config_parse(fn, NULL, sections, t, userdata);
b2aa81ef
LP
93 free(fn);
94
ed5bcfbe
LP
95 return r;
96 }
97
b2aa81ef 98 if (*l == '[') {
ed5bcfbe
LP
99 size_t k;
100 char *n;
101
b2aa81ef 102 k = strlen(l);
ed5bcfbe
LP
103 assert(k > 0);
104
b2aa81ef 105 if (l[k-1] != ']') {
16354eff 106 log_error("[%s:%u] Invalid section header.", filename, line);
ed5bcfbe
LP
107 return -EBADMSG;
108 }
109
b2aa81ef 110 if (!(n = strndup(l+1, k-2)))
ed5bcfbe
LP
111 return -ENOMEM;
112
b2aa81ef 113 if (sections && !strv_contains((char**) sections, n)) {
27563bb4 114 log_error("[%s:%u] Unknown section '%s'.", filename, line, n);
b2aa81ef
LP
115 free(n);
116 return -EBADMSG;
42f4e3c4
LP
117 }
118
ed5bcfbe
LP
119 free(*section);
120 *section = n;
121
122 return 0;
123 }
124
b2aa81ef 125 if (!(e = strchr(l, '='))) {
16354eff 126 log_error("[%s:%u] Missing '='.", filename, line);
ed5bcfbe
LP
127 return -EBADMSG;
128 }
129
130 *e = 0;
131 e++;
132
b2aa81ef 133 return next_assignment(filename, line, *section, t, strstrip(l), strstrip(e), userdata);
ed5bcfbe
LP
134}
135
136/* Go through the file and parse each line */
87f0e418 137int config_parse(const char *filename, FILE *f, const char* const * sections, const ConfigItem *t, void *userdata) {
ed5bcfbe
LP
138 unsigned line = 0;
139 char *section = NULL;
ed5bcfbe 140 int r;
63ad1ab4 141 bool ours = false;
ed5bcfbe
LP
142
143 assert(filename);
144 assert(t);
145
87f0e418
LP
146 if (!f) {
147 if (!(f = fopen(filename, "re"))) {
148 r = -errno;
149 log_error("Failed to open configuration file '%s': %s", filename, strerror(-r));
150 goto finish;
151 }
63ad1ab4
LP
152
153 ours = true;
ed5bcfbe
LP
154 }
155
156 while (!feof(f)) {
157 char l[LINE_MAX];
158
159 if (!fgets(l, sizeof(l), f)) {
160 if (feof(f))
161 break;
162
163 r = -errno;
16354eff 164 log_error("Failed to read configuration file '%s': %s", filename, strerror(-r));
ed5bcfbe
LP
165 goto finish;
166 }
167
42f4e3c4 168 if ((r = parse_line(filename, ++line, &section, sections, t, l, userdata)) < 0)
ed5bcfbe
LP
169 goto finish;
170 }
171
172 r = 0;
173
174finish:
175 free(section);
176
63ad1ab4 177 if (f && ours)
ed5bcfbe
LP
178 fclose(f);
179
180 return r;
181}
182
183int config_parse_int(
184 const char *filename,
185 unsigned line,
186 const char *section,
187 const char *lvalue,
188 const char *rvalue,
189 void *data,
190 void *userdata) {
191
192 int *i = data;
193 int r;
194
195 assert(filename);
196 assert(lvalue);
197 assert(rvalue);
198 assert(data);
199
200 if ((r = safe_atoi(rvalue, i)) < 0) {
16354eff 201 log_error("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue);
ed5bcfbe
LP
202 return r;
203 }
204
205 return 0;
206}
207
208int config_parse_unsigned(
209 const char *filename,
210 unsigned line,
211 const char *section,
212 const char *lvalue,
213 const char *rvalue,
214 void *data,
215 void *userdata) {
216
217 unsigned *u = data;
218 int r;
219
220 assert(filename);
221 assert(lvalue);
222 assert(rvalue);
223 assert(data);
224
225 if ((r = safe_atou(rvalue, u)) < 0) {
16354eff 226 log_error("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue);
ed5bcfbe
LP
227 return r;
228 }
229
230 return 0;
231}
232
233int config_parse_size(
234 const char *filename,
235 unsigned line,
236 const char *section,
237 const char *lvalue,
238 const char *rvalue,
239 void *data,
240 void *userdata) {
241
242 size_t *sz = data;
243 unsigned u;
244 int r;
245
246 assert(filename);
247 assert(lvalue);
248 assert(rvalue);
249 assert(data);
250
251 if ((r = safe_atou(rvalue, &u)) < 0) {
16354eff 252 log_error("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue);
ed5bcfbe
LP
253 return r;
254 }
255
256 *sz = (size_t) u;
257 return 0;
258}
259
260int config_parse_bool(
261 const char *filename,
262 unsigned line,
263 const char *section,
264 const char *lvalue,
265 const char *rvalue,
266 void *data,
267 void *userdata) {
268
269 int k;
270 bool *b = data;
271
272 assert(filename);
273 assert(lvalue);
274 assert(rvalue);
275 assert(data);
276
277 if ((k = parse_boolean(rvalue)) < 0) {
16354eff 278 log_error("[%s:%u] Failed to parse boolean value: %s", filename, line, rvalue);
ed5bcfbe
LP
279 return k;
280 }
281
282 *b = !!k;
283 return 0;
284}
285
286int config_parse_string(
287 const char *filename,
288 unsigned line,
289 const char *section,
290 const char *lvalue,
291 const char *rvalue,
292 void *data,
293 void *userdata) {
294
295 char **s = data;
296 char *n;
297
298 assert(filename);
299 assert(lvalue);
300 assert(rvalue);
301 assert(data);
302
303 if (*rvalue) {
304 if (!(n = strdup(rvalue)))
305 return -ENOMEM;
306 } else
307 n = NULL;
308
309 free(*s);
310 *s = n;
311
312 return 0;
313}
57d42a5f 314
034c6ed7
LP
315int config_parse_path(
316 const char *filename,
317 unsigned line,
318 const char *section,
319 const char *lvalue,
320 const char *rvalue,
321 void *data,
322 void *userdata) {
323
324 char **s = data;
325 char *n;
326
327 assert(filename);
328 assert(lvalue);
329 assert(rvalue);
330 assert(data);
331
15ae422b 332 if (!path_is_absolute(rvalue)) {
034c6ed7
LP
333 log_error("[%s:%u] Not an absolute path: %s", filename, line, rvalue);
334 return -EINVAL;
335 }
336
337 if (!(n = strdup(rvalue)))
338 return -ENOMEM;
339
340 free(*s);
341 *s = n;
342
343 return 0;
344}
57d42a5f
LP
345
346int config_parse_strv(
347 const char *filename,
348 unsigned line,
349 const char *section,
350 const char *lvalue,
351 const char *rvalue,
352 void *data,
353 void *userdata) {
354
355 char*** sv = data;
356 char **n;
357 char *w;
358 unsigned k;
359 size_t l;
360 char *state;
361
362 assert(filename);
363 assert(lvalue);
364 assert(rvalue);
365 assert(data);
366
367 k = strv_length(*sv);
034c6ed7 368 FOREACH_WORD_QUOTED(w, l, rvalue, state)
57d42a5f
LP
369 k++;
370
371 if (!(n = new(char*, k+1)))
372 return -ENOMEM;
373
3251df7d
LP
374 if (*sv)
375 for (k = 0; (*sv)[k]; k++)
376 n[k] = (*sv)[k];
7418040c
LP
377 else
378 k = 0;
3251df7d 379
034c6ed7 380 FOREACH_WORD_QUOTED(w, l, rvalue, state)
57d42a5f
LP
381 if (!(n[k++] = strndup(w, l)))
382 goto fail;
383
384 n[k] = NULL;
385 free(*sv);
386 *sv = n;
387
388 return 0;
389
390fail:
391 for (; k > 0; k--)
392 free(n[k-1]);
034c6ed7 393 free(n);
57d42a5f
LP
394
395 return -ENOMEM;
396}
15ae422b
LP
397
398int config_parse_path_strv(
399 const char *filename,
400 unsigned line,
401 const char *section,
402 const char *lvalue,
403 const char *rvalue,
404 void *data,
405 void *userdata) {
406
407 char*** sv = data;
408 char **n;
409 char *w;
410 unsigned k;
411 size_t l;
412 char *state;
413 int r;
414
415 assert(filename);
416 assert(lvalue);
417 assert(rvalue);
418 assert(data);
419
420 k = strv_length(*sv);
421 FOREACH_WORD_QUOTED(w, l, rvalue, state)
422 k++;
423
424 if (!(n = new(char*, k+1)))
425 return -ENOMEM;
426
427 k = 0;
428 if (*sv)
429 for (; (*sv)[k]; k++)
430 n[k] = (*sv)[k];
431
432 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
433 if (!(n[k] = strndup(w, l))) {
434 r = -ENOMEM;
435 goto fail;
436 }
437
438 if (!path_is_absolute(n[k])) {
439 log_error("[%s:%u] Not an absolute path: %s", filename, line, rvalue);
440 r = -EINVAL;
441 goto fail;
442 }
443
444 k++;
445 }
446
447 n[k] = NULL;
448 free(*sv);
449 *sv = n;
450
451 return 0;
452
453fail:
454 free(n[k]);
455 for (; k > 0; k--)
456 free(n[k-1]);
457 free(n);
458
459 return r;
460}