]> git.ipfire.org Git - people/ms/systemd.git/blame - conf-parser.c
fix an assert when forking
[people/ms/systemd.git] / conf-parser.c
CommitLineData
ed5bcfbe
LP
1/*-*- Mode: C; c-basic-offset: 8 -*-*/
2
3#include <string.h>
4#include <stdio.h>
5#include <errno.h>
6#include <assert.h>
7#include <stdlib.h>
8
9#include "conf-parser.h"
10#include "util.h"
11#include "macro.h"
57d42a5f 12#include "strv.h"
16354eff 13#include "log.h"
ed5bcfbe 14
ed5bcfbe 15#define COMMENTS "#;\n"
1ea86b18 16#define NEWLINES "\n\r"
ed5bcfbe
LP
17#define LINE_MAX 4096
18
19/* Run the user supplied parser for an assignment */
20static int next_assignment(
21 const char *filename,
22 unsigned line,
23 const char *section,
24 const ConfigItem *t,
25 const char *lvalue,
26 const char *rvalue,
27 void *userdata) {
28
29 assert(filename);
30 assert(t);
31 assert(lvalue);
32 assert(rvalue);
33
34 for (; t->parse; t++) {
35
36 if (t->lvalue && !streq(lvalue, t->lvalue))
37 continue;
38
39 if (t->section && !section)
40 continue;
41
42 if (t->section && !streq(section, t->section))
43 continue;
44
45 return t->parse(filename, line, section, lvalue, rvalue, t->data, userdata);
46 }
47
f1857be0
LP
48 log_info("[%s:%u] Unknown lvalue '%s' in section '%s'. Ignoring.", filename, line, lvalue, strna(section));
49 return 0;
ed5bcfbe
LP
50}
51
52/* Returns non-zero when c is contained in s */
53static int in_string(char c, const char *s) {
54 assert(s);
55
56 for (; *s; s++)
57 if (*s == c)
58 return 1;
59
60 return 0;
61}
62
63/* Remove all whitepsapce from the beginning and the end of *s. *s may
64 * be modified. */
65static char *strip(char *s) {
66 char *b = s+strspn(s, WHITESPACE);
67 char *e, *l = NULL;
68
69 for (e = b; *e; e++)
70 if (!in_string(*e, WHITESPACE))
71 l = e;
72
73 if (l)
74 *(l+1) = 0;
75
76 return b;
77}
78
79/* Parse a variable assignment line */
42f4e3c4 80static int parse_line(const char *filename, unsigned line, char **section, const char* const * sections, const ConfigItem *t, char *l, void *userdata) {
1ea86b18 81 char *e, *b, *c;
ed5bcfbe
LP
82
83 b = l+strspn(l, WHITESPACE);
84
1ea86b18 85 if ((c = strpbrk(b, NEWLINES)))
ed5bcfbe
LP
86 *c = 0;
87
88 if (!*b)
89 return 0;
1ea86b18
LP
90
91 if (strchr(COMMENTS, *b))
92 return 0;
ed5bcfbe
LP
93
94 if (startswith(b, ".include ")) {
95 char *path = NULL, *fn;
96 int r;
97
98 fn = strip(b+9);
99 if (!is_path_absolute(fn)) {
100 const char *k;
101
102 if ((k = strrchr(filename, '/'))) {
103 char *dir;
104
105 if (!(dir = strndup(filename, k-filename)))
106 return -ENOMEM;
107
108 if (asprintf(&path, "%s/%s", dir, fn) < 0)
109 return -errno;
110
111 fn = path;
112 free(dir);
113 }
114 }
115
87f0e418 116 r = config_parse(fn, NULL, sections, t, userdata);
ed5bcfbe
LP
117 free(path);
118 return r;
119 }
120
121 if (*b == '[') {
122 size_t k;
123 char *n;
124
125 k = strlen(b);
126 assert(k > 0);
127
128 if (b[k-1] != ']') {
16354eff 129 log_error("[%s:%u] Invalid section header.", filename, line);
ed5bcfbe
LP
130 return -EBADMSG;
131 }
132
133 if (!(n = strndup(b+1, k-2)))
134 return -ENOMEM;
135
42f4e3c4
LP
136 if (sections) {
137 const char * const * i;
138 bool good = false;
139 STRV_FOREACH(i, sections)
140 if (streq(*i, n)) {
141 good = true;
142 break;
143 }
144
145 if (!good) {
146 free(n);
147 return -EBADMSG;
148 }
149 }
150
ed5bcfbe
LP
151 free(*section);
152 *section = n;
153
154 return 0;
155 }
156
157 if (!(e = strchr(b, '='))) {
16354eff 158 log_error("[%s:%u] Missing '='.", filename, line);
ed5bcfbe
LP
159 return -EBADMSG;
160 }
161
162 *e = 0;
163 e++;
164
165 return next_assignment(filename, line, *section, t, strip(b), strip(e), userdata);
166}
167
168/* Go through the file and parse each line */
87f0e418 169int config_parse(const char *filename, FILE *f, const char* const * sections, const ConfigItem *t, void *userdata) {
ed5bcfbe
LP
170 unsigned line = 0;
171 char *section = NULL;
ed5bcfbe
LP
172 int r;
173
174 assert(filename);
175 assert(t);
176
87f0e418
LP
177 if (!f) {
178 if (!(f = fopen(filename, "re"))) {
179 r = -errno;
180 log_error("Failed to open configuration file '%s': %s", filename, strerror(-r));
181 goto finish;
182 }
ed5bcfbe
LP
183 }
184
185 while (!feof(f)) {
186 char l[LINE_MAX];
187
188 if (!fgets(l, sizeof(l), f)) {
189 if (feof(f))
190 break;
191
192 r = -errno;
16354eff 193 log_error("Failed to read configuration file '%s': %s", filename, strerror(-r));
ed5bcfbe
LP
194 goto finish;
195 }
196
42f4e3c4 197 if ((r = parse_line(filename, ++line, &section, sections, t, l, userdata)) < 0)
ed5bcfbe
LP
198 goto finish;
199 }
200
201 r = 0;
202
203finish:
204 free(section);
205
206 if (f)
207 fclose(f);
208
209 return r;
210}
211
212int config_parse_int(
213 const char *filename,
214 unsigned line,
215 const char *section,
216 const char *lvalue,
217 const char *rvalue,
218 void *data,
219 void *userdata) {
220
221 int *i = data;
222 int r;
223
224 assert(filename);
225 assert(lvalue);
226 assert(rvalue);
227 assert(data);
228
229 if ((r = safe_atoi(rvalue, i)) < 0) {
16354eff 230 log_error("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue);
ed5bcfbe
LP
231 return r;
232 }
233
234 return 0;
235}
236
237int config_parse_unsigned(
238 const char *filename,
239 unsigned line,
240 const char *section,
241 const char *lvalue,
242 const char *rvalue,
243 void *data,
244 void *userdata) {
245
246 unsigned *u = data;
247 int r;
248
249 assert(filename);
250 assert(lvalue);
251 assert(rvalue);
252 assert(data);
253
254 if ((r = safe_atou(rvalue, u)) < 0) {
16354eff 255 log_error("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue);
ed5bcfbe
LP
256 return r;
257 }
258
259 return 0;
260}
261
262int config_parse_size(
263 const char *filename,
264 unsigned line,
265 const char *section,
266 const char *lvalue,
267 const char *rvalue,
268 void *data,
269 void *userdata) {
270
271 size_t *sz = data;
272 unsigned u;
273 int r;
274
275 assert(filename);
276 assert(lvalue);
277 assert(rvalue);
278 assert(data);
279
280 if ((r = safe_atou(rvalue, &u)) < 0) {
16354eff 281 log_error("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue);
ed5bcfbe
LP
282 return r;
283 }
284
285 *sz = (size_t) u;
286 return 0;
287}
288
289int config_parse_bool(
290 const char *filename,
291 unsigned line,
292 const char *section,
293 const char *lvalue,
294 const char *rvalue,
295 void *data,
296 void *userdata) {
297
298 int k;
299 bool *b = data;
300
301 assert(filename);
302 assert(lvalue);
303 assert(rvalue);
304 assert(data);
305
306 if ((k = parse_boolean(rvalue)) < 0) {
16354eff 307 log_error("[%s:%u] Failed to parse boolean value: %s", filename, line, rvalue);
ed5bcfbe
LP
308 return k;
309 }
310
311 *b = !!k;
312 return 0;
313}
314
315int config_parse_string(
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
332 if (*rvalue) {
333 if (!(n = strdup(rvalue)))
334 return -ENOMEM;
335 } else
336 n = NULL;
337
338 free(*s);
339 *s = n;
340
341 return 0;
342}
57d42a5f 343
034c6ed7
LP
344int config_parse_path(
345 const char *filename,
346 unsigned line,
347 const char *section,
348 const char *lvalue,
349 const char *rvalue,
350 void *data,
351 void *userdata) {
352
353 char **s = data;
354 char *n;
355
356 assert(filename);
357 assert(lvalue);
358 assert(rvalue);
359 assert(data);
360
361 if (*rvalue != '/') {
362 log_error("[%s:%u] Not an absolute path: %s", filename, line, rvalue);
363 return -EINVAL;
364 }
365
366 if (!(n = strdup(rvalue)))
367 return -ENOMEM;
368
369 free(*s);
370 *s = n;
371
372 return 0;
373}
57d42a5f
LP
374
375int config_parse_strv(
376 const char *filename,
377 unsigned line,
378 const char *section,
379 const char *lvalue,
380 const char *rvalue,
381 void *data,
382 void *userdata) {
383
384 char*** sv = data;
385 char **n;
386 char *w;
387 unsigned k;
388 size_t l;
389 char *state;
390
391 assert(filename);
392 assert(lvalue);
393 assert(rvalue);
394 assert(data);
395
396 k = strv_length(*sv);
034c6ed7 397 FOREACH_WORD_QUOTED(w, l, rvalue, state)
57d42a5f
LP
398 k++;
399
400 if (!(n = new(char*, k+1)))
401 return -ENOMEM;
402
403 for (k = 0; (*sv)[k]; k++)
404 n[k] = (*sv)[k];
034c6ed7 405 FOREACH_WORD_QUOTED(w, l, rvalue, state)
57d42a5f
LP
406 if (!(n[k++] = strndup(w, l)))
407 goto fail;
408
409 n[k] = NULL;
410 free(*sv);
411 *sv = n;
412
413 return 0;
414
415fail:
416 for (; k > 0; k--)
417 free(n[k-1]);
034c6ed7 418 free(n);
57d42a5f
LP
419
420 return -ENOMEM;
421}