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