chiark / gitweb /
service: fix parsing word size functions
[elogind.git] / src / 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
36 /* Run the user supplied parser for an assignment */
37 static int next_assignment(
38                 const char *filename,
39                 unsigned line,
40                 const char *section,
41                 const ConfigItem *t,
42                 bool relaxed,
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->lvalue; 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                 if (!t->parse)
64                         return 0;
65
66                 return t->parse(filename, line, section, lvalue, rvalue, t->data, userdata);
67         }
68
69         /* Warn about unknown non-extension fields. */
70         if (!relaxed && !startswith(lvalue, "X-"))
71                 log_info("[%s:%u] Unknown lvalue '%s' in section '%s'. Ignoring.", filename, line, lvalue, strna(section));
72
73         return 0;
74 }
75
76 /* Parse a variable assignment line */
77 static int parse_line(const char *filename, unsigned line, char **section, const char* const * sections, const ConfigItem *t, bool relaxed, char *l, void *userdata) {
78         char *e;
79
80         l = strstrip(l);
81
82         if (!*l)
83                 return 0;
84
85         if (strchr(COMMENTS, *l))
86                 return 0;
87
88         if (startswith(l, ".include ")) {
89                 char *fn;
90                 int r;
91
92                 if (!(fn = file_in_same_dir(filename, strstrip(l+9))))
93                         return -ENOMEM;
94
95                 r = config_parse(fn, NULL, sections, t, relaxed, userdata);
96                 free(fn);
97
98                 return r;
99         }
100
101         if (*l == '[') {
102                 size_t k;
103                 char *n;
104
105                 k = strlen(l);
106                 assert(k > 0);
107
108                 if (l[k-1] != ']') {
109                         log_error("[%s:%u] Invalid section header.", filename, line);
110                         return -EBADMSG;
111                 }
112
113                 if (!(n = strndup(l+1, k-2)))
114                         return -ENOMEM;
115
116                 if (!relaxed && sections && !strv_contains((char**) sections, n))
117                         log_info("[%s:%u] Unknown section '%s'. Ignoring.", filename, line, n);
118
119                 free(*section);
120                 *section = n;
121
122                 return 0;
123         }
124
125         if (sections && !strv_contains((char**) sections, *section))
126                 return 0;
127
128         if (!(e = strchr(l, '='))) {
129                 log_error("[%s:%u] Missing '='.", filename, line);
130                 return -EBADMSG;
131         }
132
133         *e = 0;
134         e++;
135
136         return next_assignment(filename, line, *section, t, relaxed, strstrip(l), strstrip(e), userdata);
137 }
138
139 /* Go through the file and parse each line */
140 int config_parse(const char *filename, FILE *f, const char* const * sections, const ConfigItem *t, bool relaxed, void *userdata) {
141         unsigned line = 0;
142         char *section = NULL;
143         int r;
144         bool ours = false;
145
146         assert(filename);
147         assert(t);
148
149         if (!f) {
150                 if (!(f = fopen(filename, "re"))) {
151                         r = -errno;
152                         log_error("Failed to open configuration file '%s': %s", filename, strerror(-r));
153                         goto finish;
154                 }
155
156                 ours = true;
157         }
158
159         while (!feof(f)) {
160                 char l[LINE_MAX];
161
162                 if (!fgets(l, sizeof(l), f)) {
163                         if (feof(f))
164                                 break;
165
166                         r = -errno;
167                         log_error("Failed to read configuration file '%s': %s", filename, strerror(-r));
168                         goto finish;
169                 }
170
171                 if ((r = parse_line(filename, ++line, &section, sections, t, relaxed, l, userdata)) < 0)
172                         goto finish;
173         }
174
175         r = 0;
176
177 finish:
178         free(section);
179
180         if (f && ours)
181                 fclose(f);
182
183         return r;
184 }
185
186 int config_parse_int(
187                 const char *filename,
188                 unsigned line,
189                 const char *section,
190                 const char *lvalue,
191                 const char *rvalue,
192                 void *data,
193                 void *userdata) {
194
195         int *i = data;
196         int r;
197
198         assert(filename);
199         assert(lvalue);
200         assert(rvalue);
201         assert(data);
202
203         if ((r = safe_atoi(rvalue, i)) < 0) {
204                 log_error("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue);
205                 return r;
206         }
207
208         return 0;
209 }
210
211 int config_parse_unsigned(
212                 const char *filename,
213                 unsigned line,
214                 const char *section,
215                 const char *lvalue,
216                 const char *rvalue,
217                 void *data,
218                 void *userdata) {
219
220         unsigned *u = data;
221         int r;
222
223         assert(filename);
224         assert(lvalue);
225         assert(rvalue);
226         assert(data);
227
228         if ((r = safe_atou(rvalue, u)) < 0) {
229                 log_error("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue);
230                 return r;
231         }
232
233         return 0;
234 }
235
236 int config_parse_size(
237                 const char *filename,
238                 unsigned line,
239                 const char *section,
240                 const char *lvalue,
241                 const char *rvalue,
242                 void *data,
243                 void *userdata) {
244
245         size_t *sz = data;
246         unsigned u;
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) {
255                 log_error("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue);
256                 return r;
257         }
258
259         *sz = (size_t) u;
260         return 0;
261 }
262
263 int config_parse_bool(
264                 const char *filename,
265                 unsigned line,
266                 const char *section,
267                 const char *lvalue,
268                 const char *rvalue,
269                 void *data,
270                 void *userdata) {
271
272         int k;
273         bool *b = data;
274
275         assert(filename);
276         assert(lvalue);
277         assert(rvalue);
278         assert(data);
279
280         if ((k = parse_boolean(rvalue)) < 0) {
281                 log_error("[%s:%u] Failed to parse boolean value: %s", filename, line, rvalue);
282                 return k;
283         }
284
285         *b = !!k;
286         return 0;
287 }
288
289 int config_parse_string(
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         char **s = data;
299         char *n;
300
301         assert(filename);
302         assert(lvalue);
303         assert(rvalue);
304         assert(data);
305
306         if (*rvalue) {
307                 if (!(n = strdup(rvalue)))
308                         return -ENOMEM;
309         } else
310                 n = NULL;
311
312         free(*s);
313         *s = n;
314
315         return 0;
316 }
317
318 int config_parse_path(
319                 const char *filename,
320                 unsigned line,
321                 const char *section,
322                 const char *lvalue,
323                 const char *rvalue,
324                 void *data,
325                 void *userdata) {
326
327         char **s = data;
328         char *n;
329
330         assert(filename);
331         assert(lvalue);
332         assert(rvalue);
333         assert(data);
334
335         if (!path_is_absolute(rvalue)) {
336                 log_error("[%s:%u] Not an absolute path: %s", filename, line, rvalue);
337                 return -EINVAL;
338         }
339
340         if (!(n = strdup(rvalue)))
341                 return -ENOMEM;
342
343         path_kill_slashes(n);
344
345         free(*s);
346         *s = n;
347
348         return 0;
349 }
350
351 int config_parse_strv(
352                 const char *filename,
353                 unsigned line,
354                 const char *section,
355                 const char *lvalue,
356                 const char *rvalue,
357                 void *data,
358                 void *userdata) {
359
360         char*** sv = data;
361         char **n;
362         char *w;
363         unsigned k;
364         size_t l;
365         char *state;
366
367         assert(filename);
368         assert(lvalue);
369         assert(rvalue);
370         assert(data);
371
372         k = strv_length(*sv);
373         FOREACH_WORD_QUOTED(w, l, rvalue, state)
374                 k++;
375
376         if (!(n = new(char*, k+1)))
377                 return -ENOMEM;
378
379         if (*sv)
380                 for (k = 0; (*sv)[k]; k++)
381                         n[k] = (*sv)[k];
382         else
383                 k = 0;
384
385         FOREACH_WORD_QUOTED(w, l, rvalue, state)
386                 if (!(n[k++] = strndup(w, l)))
387                         goto fail;
388
389         n[k] = NULL;
390         free(*sv);
391         *sv = n;
392
393         return 0;
394
395 fail:
396         for (; k > 0; k--)
397                 free(n[k-1]);
398         free(n);
399
400         return -ENOMEM;
401 }
402
403 int config_parse_path_strv(
404                 const char *filename,
405                 unsigned line,
406                 const char *section,
407                 const char *lvalue,
408                 const char *rvalue,
409                 void *data,
410                 void *userdata) {
411
412         char*** sv = data;
413         char **n;
414         char *w;
415         unsigned k;
416         size_t l;
417         char *state;
418         int r;
419
420         assert(filename);
421         assert(lvalue);
422         assert(rvalue);
423         assert(data);
424
425         k = strv_length(*sv);
426         FOREACH_WORD_QUOTED(w, l, rvalue, state)
427                 k++;
428
429         if (!(n = new(char*, k+1)))
430                 return -ENOMEM;
431
432         k = 0;
433         if (*sv)
434                 for (; (*sv)[k]; k++)
435                         n[k] = (*sv)[k];
436
437         FOREACH_WORD_QUOTED(w, l, rvalue, state) {
438                 if (!(n[k] = strndup(w, l))) {
439                         r = -ENOMEM;
440                         goto fail;
441                 }
442
443                 if (!path_is_absolute(n[k])) {
444                         log_error("[%s:%u] Not an absolute path: %s", filename, line, rvalue);
445                         r = -EINVAL;
446                         goto fail;
447                 }
448
449                 path_kill_slashes(n[k]);
450
451                 k++;
452         }
453
454         n[k] = NULL;
455         free(*sv);
456         *sv = n;
457
458         return 0;
459
460 fail:
461         free(n[k]);
462         for (; k > 0; k--)
463                 free(n[k-1]);
464         free(n);
465
466         return r;
467 }