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