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