chiark / gitweb /
dbus: install some properties on the job objects
[elogind.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 }