]> git.ipfire.org Git - people/ms/systemd.git/blob - conf-parser.c
device: allow easy identification of network interfaces without their full sysfs...
[people/ms/systemd.git] / conf-parser.c
1 /*-*- Mode: C; c-basic-offset: 8 -*-*/
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 #define COMMENTS "#;\n"
35 #define LINE_MAX 4096
36
37 /* Run the user supplied parser for an assignment */
38 static 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
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
70 return 0;
71 }
72
73 /* Parse a variable assignment line */
74 static int parse_line(const char *filename, unsigned line, char **section, const char* const * sections, const ConfigItem *t, char *l, void *userdata) {
75 char *e;
76
77 l = strstrip(l);
78
79 if (!*l)
80 return 0;
81
82 if (strchr(COMMENTS, *l))
83 return 0;
84
85 if (startswith(l, ".include ")) {
86 char *fn;
87 int r;
88
89 if (!(fn = file_in_same_dir(filename, strstrip(l+9))))
90 return -ENOMEM;
91
92 r = config_parse(fn, NULL, sections, t, userdata);
93 free(fn);
94
95 return r;
96 }
97
98 if (*l == '[') {
99 size_t k;
100 char *n;
101
102 k = strlen(l);
103 assert(k > 0);
104
105 if (l[k-1] != ']') {
106 log_error("[%s:%u] Invalid section header.", filename, line);
107 return -EBADMSG;
108 }
109
110 if (!(n = strndup(l+1, k-2)))
111 return -ENOMEM;
112
113 if (sections && !strv_contains((char**) sections, n)) {
114 log_error("[%s:%u] Unknown section '%s'.", filename, line, n);
115 free(n);
116 return -EBADMSG;
117 }
118
119 free(*section);
120 *section = n;
121
122 return 0;
123 }
124
125 if (!(e = strchr(l, '='))) {
126 log_error("[%s:%u] Missing '='.", filename, line);
127 return -EBADMSG;
128 }
129
130 *e = 0;
131 e++;
132
133 return next_assignment(filename, line, *section, t, strstrip(l), strstrip(e), userdata);
134 }
135
136 /* Go through the file and parse each line */
137 int config_parse(const char *filename, FILE *f, const char* const * sections, const ConfigItem *t, void *userdata) {
138 unsigned line = 0;
139 char *section = NULL;
140 int r;
141 bool ours = false;
142
143 assert(filename);
144 assert(t);
145
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 }
152
153 ours = true;
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;
164 log_error("Failed to read configuration file '%s': %s", filename, strerror(-r));
165 goto finish;
166 }
167
168 if ((r = parse_line(filename, ++line, &section, sections, t, l, userdata)) < 0)
169 goto finish;
170 }
171
172 r = 0;
173
174 finish:
175 free(section);
176
177 if (f && ours)
178 fclose(f);
179
180 return r;
181 }
182
183 int 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) {
201 log_error("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue);
202 return r;
203 }
204
205 return 0;
206 }
207
208 int 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) {
226 log_error("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue);
227 return r;
228 }
229
230 return 0;
231 }
232
233 int 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) {
252 log_error("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue);
253 return r;
254 }
255
256 *sz = (size_t) u;
257 return 0;
258 }
259
260 int 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) {
278 log_error("[%s:%u] Failed to parse boolean value: %s", filename, line, rvalue);
279 return k;
280 }
281
282 *b = !!k;
283 return 0;
284 }
285
286 int 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 }
314
315 int 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
332 if (!path_is_absolute(rvalue)) {
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 }
345
346 int 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);
368 FOREACH_WORD_QUOTED(w, l, rvalue, state)
369 k++;
370
371 if (!(n = new(char*, k+1)))
372 return -ENOMEM;
373
374 if (*sv)
375 for (k = 0; (*sv)[k]; k++)
376 n[k] = (*sv)[k];
377 else
378 k = 0;
379
380 FOREACH_WORD_QUOTED(w, l, rvalue, state)
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
390 fail:
391 for (; k > 0; k--)
392 free(n[k-1]);
393 free(n);
394
395 return -ENOMEM;
396 }
397
398 int 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
453 fail:
454 free(n[k]);
455 for (; k > 0; k--)
456 free(n[k-1]);
457 free(n);
458
459 return r;
460 }