]> git.ipfire.org Git - people/ms/systemd.git/blob - conf-parser.c
port config parser to new utility functions
[people/ms/systemd.git] / conf-parser.c
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"
12 #include "strv.h"
13 #include "log.h"
14
15 #define COMMENTS "#;\n"
16 #define NEWLINES "\n\r"
17 #define LINE_MAX 4096
18
19 /* Run the user supplied parser for an assignment */
20 static 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
48 log_info("[%s:%u] Unknown lvalue '%s' in section '%s'. Ignoring.", filename, line, lvalue, strna(section));
49 return 0;
50 }
51
52 /* Parse a variable assignment line */
53 static int parse_line(const char *filename, unsigned line, char **section, const char* const * sections, const ConfigItem *t, char *l, void *userdata) {
54 char *e;
55
56 l = strstrip(l);
57
58 if (!*l)
59 return 0;
60
61 if (strchr(COMMENTS, *l))
62 return 0;
63
64 if (startswith(l, ".include ")) {
65 char *fn;
66 int r;
67
68 if (!(fn = file_in_same_dir(filename, strstrip(l+9))))
69 return -ENOMEM;
70
71 r = config_parse(fn, NULL, sections, t, userdata);
72 free(fn);
73
74 return r;
75 }
76
77 if (*l == '[') {
78 size_t k;
79 char *n;
80
81 k = strlen(l);
82 assert(k > 0);
83
84 if (l[k-1] != ']') {
85 log_error("[%s:%u] Invalid section header.", filename, line);
86 return -EBADMSG;
87 }
88
89 if (!(n = strndup(l+1, k-2)))
90 return -ENOMEM;
91
92 if (sections && !strv_contains((char**) sections, n)) {
93 free(n);
94 return -EBADMSG;
95 }
96
97 free(*section);
98 *section = n;
99
100 return 0;
101 }
102
103 if (!(e = strchr(l, '='))) {
104 log_error("[%s:%u] Missing '='.", filename, line);
105 return -EBADMSG;
106 }
107
108 *e = 0;
109 e++;
110
111 return next_assignment(filename, line, *section, t, strstrip(l), strstrip(e), userdata);
112 }
113
114 /* Go through the file and parse each line */
115 int config_parse(const char *filename, FILE *f, const char* const * sections, const ConfigItem *t, void *userdata) {
116 unsigned line = 0;
117 char *section = NULL;
118 int r;
119
120 assert(filename);
121 assert(t);
122
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 }
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;
139 log_error("Failed to read configuration file '%s': %s", filename, strerror(-r));
140 goto finish;
141 }
142
143 if ((r = parse_line(filename, ++line, &section, sections, t, l, userdata)) < 0)
144 goto finish;
145 }
146
147 r = 0;
148
149 finish:
150 free(section);
151
152 if (f)
153 fclose(f);
154
155 return r;
156 }
157
158 int 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) {
176 log_error("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue);
177 return r;
178 }
179
180 return 0;
181 }
182
183 int 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) {
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_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) {
227 log_error("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue);
228 return r;
229 }
230
231 *sz = (size_t) u;
232 return 0;
233 }
234
235 int 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) {
253 log_error("[%s:%u] Failed to parse boolean value: %s", filename, line, rvalue);
254 return k;
255 }
256
257 *b = !!k;
258 return 0;
259 }
260
261 int 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 }
289
290 int 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 }
320
321 int 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);
343 FOREACH_WORD_QUOTED(w, l, rvalue, state)
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];
351 FOREACH_WORD_QUOTED(w, l, rvalue, state)
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
361 fail:
362 for (; k > 0; k--)
363 free(n[k-1]);
364 free(n);
365
366 return -ENOMEM;
367 }