]> git.ipfire.org Git - people/ms/systemd.git/blob - conf-parser.c
conf-parser: get rid of redundant NEWLINES definition
[people/ms/systemd.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 }