]>
Commit | Line | Data |
---|---|---|
d6c9574f | 1 | /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ |
ed5bcfbe | 2 | |
a7334b09 LP |
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 | |
5430f7f2 LP |
9 | under the terms of the GNU Lesser General Public License as published by |
10 | the Free Software Foundation; either version 2.1 of the License, or | |
a7334b09 LP |
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 | |
5430f7f2 | 16 | Lesser General Public License for more details. |
a7334b09 | 17 | |
5430f7f2 | 18 | You should have received a copy of the GNU Lesser General Public License |
a7334b09 LP |
19 | along with systemd; If not, see <http://www.gnu.org/licenses/>. |
20 | ***/ | |
21 | ||
ed5bcfbe LP |
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" | |
57d42a5f | 31 | #include "strv.h" |
16354eff | 32 | #include "log.h" |
7f110ff9 | 33 | #include "utf8.h" |
9eb977db | 34 | #include "path-util.h" |
96342de6 LN |
35 | #include "set.h" |
36 | #include "exit-status.h" | |
ed5bcfbe | 37 | |
f975e971 LP |
38 | int config_item_table_lookup( |
39 | void *table, | |
ed5bcfbe | 40 | const char *section, |
ed5bcfbe | 41 | const char *lvalue, |
f975e971 LP |
42 | ConfigParserCallback *func, |
43 | int *ltype, | |
44 | void **data, | |
ed5bcfbe LP |
45 | void *userdata) { |
46 | ||
f975e971 LP |
47 | ConfigTableItem *t; |
48 | ||
49 | assert(table); | |
ed5bcfbe | 50 | assert(lvalue); |
f975e971 LP |
51 | assert(func); |
52 | assert(ltype); | |
53 | assert(data); | |
ed5bcfbe | 54 | |
f975e971 | 55 | for (t = table; t->lvalue; t++) { |
ed5bcfbe | 56 | |
f975e971 | 57 | if (!streq(lvalue, t->lvalue)) |
ed5bcfbe LP |
58 | continue; |
59 | ||
f975e971 | 60 | if (!streq_ptr(section, t->section)) |
ed5bcfbe LP |
61 | continue; |
62 | ||
f975e971 LP |
63 | *func = t->parse; |
64 | *ltype = t->ltype; | |
65 | *data = t->data; | |
66 | return 1; | |
67 | } | |
ed5bcfbe | 68 | |
f975e971 LP |
69 | return 0; |
70 | } | |
10e87ee7 | 71 | |
f975e971 LP |
72 | int config_item_perf_lookup( |
73 | void *table, | |
74 | const char *section, | |
75 | const char *lvalue, | |
76 | ConfigParserCallback *func, | |
77 | int *ltype, | |
78 | void **data, | |
79 | void *userdata) { | |
80 | ||
81 | ConfigPerfItemLookup lookup = (ConfigPerfItemLookup) table; | |
82 | const ConfigPerfItem *p; | |
83 | ||
84 | assert(table); | |
85 | assert(lvalue); | |
86 | assert(func); | |
87 | assert(ltype); | |
88 | assert(data); | |
89 | ||
90 | if (!section) | |
91 | p = lookup(lvalue, strlen(lvalue)); | |
92 | else { | |
93 | char *key; | |
94 | ||
b7def684 | 95 | key = strjoin(section, ".", lvalue, NULL); |
44d91056 | 96 | if (!key) |
f975e971 LP |
97 | return -ENOMEM; |
98 | ||
99 | p = lookup(key, strlen(key)); | |
100 | free(key); | |
ed5bcfbe LP |
101 | } |
102 | ||
f975e971 LP |
103 | if (!p) |
104 | return 0; | |
105 | ||
106 | *func = p->parse; | |
107 | *ltype = p->ltype; | |
108 | *data = (uint8_t*) userdata + p->offset; | |
109 | return 1; | |
110 | } | |
111 | ||
112 | /* Run the user supplied parser for an assignment */ | |
113 | static int next_assignment( | |
114 | const char *filename, | |
115 | unsigned line, | |
116 | ConfigItemLookup lookup, | |
117 | void *table, | |
118 | const char *section, | |
119 | const char *lvalue, | |
120 | const char *rvalue, | |
121 | bool relaxed, | |
122 | void *userdata) { | |
123 | ||
124 | ConfigParserCallback func = NULL; | |
125 | int ltype = 0; | |
126 | void *data = NULL; | |
127 | int r; | |
128 | ||
129 | assert(filename); | |
130 | assert(line > 0); | |
131 | assert(lookup); | |
132 | assert(lvalue); | |
133 | assert(rvalue); | |
134 | ||
135 | r = lookup(table, section, lvalue, &func, <ype, &data, userdata); | |
136 | if (r < 0) | |
137 | return r; | |
138 | ||
d937fbbd LP |
139 | if (r > 0) { |
140 | if (func) | |
141 | return func(filename, line, section, lvalue, ltype, rvalue, data, userdata); | |
142 | ||
143 | return 0; | |
144 | } | |
f975e971 | 145 | |
46205bb6 | 146 | /* Warn about unknown non-extension fields. */ |
10e87ee7 | 147 | if (!relaxed && !startswith(lvalue, "X-")) |
f975e971 | 148 | log_info("[%s:%u] Unknown lvalue '%s' in section '%s'. Ignoring.", filename, line, lvalue, section); |
46205bb6 | 149 | |
f1857be0 | 150 | return 0; |
ed5bcfbe LP |
151 | } |
152 | ||
ed5bcfbe | 153 | /* Parse a variable assignment line */ |
f975e971 LP |
154 | static int parse_line( |
155 | const char *filename, | |
156 | unsigned line, | |
157 | const char *sections, | |
158 | ConfigItemLookup lookup, | |
159 | void *table, | |
160 | bool relaxed, | |
161 | char **section, | |
162 | char *l, | |
163 | void *userdata) { | |
164 | ||
b2aa81ef | 165 | char *e; |
ed5bcfbe | 166 | |
f975e971 LP |
167 | assert(filename); |
168 | assert(line > 0); | |
169 | assert(lookup); | |
170 | assert(l); | |
171 | ||
b2aa81ef | 172 | l = strstrip(l); |
ed5bcfbe | 173 | |
b2aa81ef | 174 | if (!*l) |
ed5bcfbe | 175 | return 0; |
1ea86b18 | 176 | |
b2aa81ef | 177 | if (strchr(COMMENTS, *l)) |
1ea86b18 | 178 | return 0; |
ed5bcfbe | 179 | |
b2aa81ef LP |
180 | if (startswith(l, ".include ")) { |
181 | char *fn; | |
ed5bcfbe LP |
182 | int r; |
183 | ||
f975e971 LP |
184 | fn = file_in_same_dir(filename, strstrip(l+9)); |
185 | if (!fn) | |
b2aa81ef | 186 | return -ENOMEM; |
ed5bcfbe | 187 | |
f975e971 | 188 | r = config_parse(fn, NULL, sections, lookup, table, relaxed, userdata); |
b2aa81ef LP |
189 | free(fn); |
190 | ||
ed5bcfbe LP |
191 | return r; |
192 | } | |
193 | ||
b2aa81ef | 194 | if (*l == '[') { |
ed5bcfbe LP |
195 | size_t k; |
196 | char *n; | |
197 | ||
b2aa81ef | 198 | k = strlen(l); |
ed5bcfbe LP |
199 | assert(k > 0); |
200 | ||
b2aa81ef | 201 | if (l[k-1] != ']') { |
16354eff | 202 | log_error("[%s:%u] Invalid section header.", filename, line); |
ed5bcfbe LP |
203 | return -EBADMSG; |
204 | } | |
205 | ||
f975e971 LP |
206 | n = strndup(l+1, k-2); |
207 | if (!n) | |
ed5bcfbe LP |
208 | return -ENOMEM; |
209 | ||
f975e971 | 210 | if (sections && !nulstr_contains(sections, n)) { |
42f4e3c4 | 211 | |
f975e971 LP |
212 | if (!relaxed) |
213 | log_info("[%s:%u] Unknown section '%s'. Ignoring.", filename, line, n); | |
214 | ||
215 | free(n); | |
216 | *section = NULL; | |
217 | } else { | |
218 | free(*section); | |
219 | *section = n; | |
220 | } | |
ed5bcfbe LP |
221 | |
222 | return 0; | |
223 | } | |
224 | ||
62f168a0 LP |
225 | if (sections && !*section) { |
226 | ||
227 | if (!relaxed) | |
228 | log_info("[%s:%u] Assignment outside of section. Ignoring.", filename, line); | |
229 | ||
10e87ee7 | 230 | return 0; |
62f168a0 | 231 | } |
10e87ee7 | 232 | |
f975e971 LP |
233 | e = strchr(l, '='); |
234 | if (!e) { | |
16354eff | 235 | log_error("[%s:%u] Missing '='.", filename, line); |
ed5bcfbe LP |
236 | return -EBADMSG; |
237 | } | |
238 | ||
239 | *e = 0; | |
240 | e++; | |
241 | ||
f975e971 LP |
242 | return next_assignment( |
243 | filename, | |
244 | line, | |
245 | lookup, | |
246 | table, | |
247 | *section, | |
248 | strstrip(l), | |
249 | strstrip(e), | |
250 | relaxed, | |
251 | userdata); | |
ed5bcfbe LP |
252 | } |
253 | ||
254 | /* Go through the file and parse each line */ | |
f975e971 LP |
255 | int config_parse( |
256 | const char *filename, | |
257 | FILE *f, | |
258 | const char *sections, | |
259 | ConfigItemLookup lookup, | |
260 | void *table, | |
261 | bool relaxed, | |
262 | void *userdata) { | |
263 | ||
ed5bcfbe LP |
264 | unsigned line = 0; |
265 | char *section = NULL; | |
ed5bcfbe | 266 | int r; |
63ad1ab4 | 267 | bool ours = false; |
3dab2943 | 268 | char *continuation = NULL; |
ed5bcfbe LP |
269 | |
270 | assert(filename); | |
f975e971 | 271 | assert(lookup); |
ed5bcfbe | 272 | |
87f0e418 | 273 | if (!f) { |
f975e971 LP |
274 | f = fopen(filename, "re"); |
275 | if (!f) { | |
87f0e418 LP |
276 | r = -errno; |
277 | log_error("Failed to open configuration file '%s': %s", filename, strerror(-r)); | |
278 | goto finish; | |
279 | } | |
63ad1ab4 LP |
280 | |
281 | ours = true; | |
ed5bcfbe LP |
282 | } |
283 | ||
284 | while (!feof(f)) { | |
3dab2943 LP |
285 | char l[LINE_MAX], *p, *c = NULL, *e; |
286 | bool escaped = false; | |
ed5bcfbe LP |
287 | |
288 | if (!fgets(l, sizeof(l), f)) { | |
289 | if (feof(f)) | |
290 | break; | |
291 | ||
292 | r = -errno; | |
16354eff | 293 | log_error("Failed to read configuration file '%s': %s", filename, strerror(-r)); |
ed5bcfbe LP |
294 | goto finish; |
295 | } | |
296 | ||
3dab2943 LP |
297 | truncate_nl(l); |
298 | ||
299 | if (continuation) { | |
f975e971 LP |
300 | c = strappend(continuation, l); |
301 | if (!c) { | |
3dab2943 LP |
302 | r = -ENOMEM; |
303 | goto finish; | |
304 | } | |
305 | ||
306 | free(continuation); | |
307 | continuation = NULL; | |
308 | p = c; | |
309 | } else | |
310 | p = l; | |
311 | ||
312 | for (e = p; *e; e++) { | |
313 | if (escaped) | |
314 | escaped = false; | |
315 | else if (*e == '\\') | |
316 | escaped = true; | |
317 | } | |
318 | ||
319 | if (escaped) { | |
320 | *(e-1) = ' '; | |
321 | ||
322 | if (c) | |
323 | continuation = c; | |
f975e971 LP |
324 | else { |
325 | continuation = strdup(l); | |
8ea913b2 | 326 | if (!continuation) { |
f975e971 LP |
327 | r = -ENOMEM; |
328 | goto finish; | |
329 | } | |
3dab2943 LP |
330 | } |
331 | ||
332 | continue; | |
333 | } | |
334 | ||
f975e971 LP |
335 | r = parse_line(filename, |
336 | ++line, | |
337 | sections, | |
338 | lookup, | |
339 | table, | |
340 | relaxed, | |
341 | §ion, | |
342 | p, | |
343 | userdata); | |
3dab2943 LP |
344 | free(c); |
345 | ||
346 | if (r < 0) | |
ed5bcfbe LP |
347 | goto finish; |
348 | } | |
349 | ||
350 | r = 0; | |
351 | ||
352 | finish: | |
353 | free(section); | |
3dab2943 | 354 | free(continuation); |
ed5bcfbe | 355 | |
63ad1ab4 | 356 | if (f && ours) |
ed5bcfbe LP |
357 | fclose(f); |
358 | ||
359 | return r; | |
360 | } | |
361 | ||
362 | int config_parse_int( | |
363 | const char *filename, | |
364 | unsigned line, | |
365 | const char *section, | |
366 | const char *lvalue, | |
2b583ce6 | 367 | int ltype, |
ed5bcfbe LP |
368 | const char *rvalue, |
369 | void *data, | |
370 | void *userdata) { | |
371 | ||
372 | int *i = data; | |
373 | int r; | |
374 | ||
375 | assert(filename); | |
376 | assert(lvalue); | |
377 | assert(rvalue); | |
378 | assert(data); | |
379 | ||
380 | if ((r = safe_atoi(rvalue, i)) < 0) { | |
f975e971 LP |
381 | log_error("[%s:%u] Failed to parse numeric value, ingoring: %s", filename, line, rvalue); |
382 | return 0; | |
ed5bcfbe LP |
383 | } |
384 | ||
385 | return 0; | |
386 | } | |
387 | ||
916abb21 LP |
388 | int config_parse_long( |
389 | const char *filename, | |
390 | unsigned line, | |
391 | const char *section, | |
392 | const char *lvalue, | |
393 | int ltype, | |
394 | const char *rvalue, | |
395 | void *data, | |
396 | void *userdata) { | |
397 | ||
398 | long *i = data; | |
399 | int r; | |
400 | ||
401 | assert(filename); | |
402 | assert(lvalue); | |
403 | assert(rvalue); | |
404 | assert(data); | |
405 | ||
406 | if ((r = safe_atoli(rvalue, i)) < 0) { | |
f975e971 LP |
407 | log_error("[%s:%u] Failed to parse numeric value, ignoring: %s", filename, line, rvalue); |
408 | return 0; | |
916abb21 LP |
409 | } |
410 | ||
411 | return 0; | |
412 | } | |
413 | ||
ec863ba6 LP |
414 | int config_parse_uint64( |
415 | const char *filename, | |
416 | unsigned line, | |
417 | const char *section, | |
418 | const char *lvalue, | |
2b583ce6 | 419 | int ltype, |
ec863ba6 LP |
420 | const char *rvalue, |
421 | void *data, | |
422 | void *userdata) { | |
423 | ||
424 | uint64_t *u = data; | |
425 | int r; | |
426 | ||
427 | assert(filename); | |
428 | assert(lvalue); | |
429 | assert(rvalue); | |
430 | assert(data); | |
431 | ||
432 | if ((r = safe_atou64(rvalue, u)) < 0) { | |
f975e971 LP |
433 | log_error("[%s:%u] Failed to parse numeric value, ignoring: %s", filename, line, rvalue); |
434 | return 0; | |
ec863ba6 LP |
435 | } |
436 | ||
437 | return 0; | |
438 | } | |
439 | ||
ed5bcfbe LP |
440 | int config_parse_unsigned( |
441 | const char *filename, | |
442 | unsigned line, | |
443 | const char *section, | |
444 | const char *lvalue, | |
2b583ce6 | 445 | int ltype, |
ed5bcfbe LP |
446 | const char *rvalue, |
447 | void *data, | |
448 | void *userdata) { | |
449 | ||
450 | unsigned *u = data; | |
451 | int r; | |
452 | ||
453 | assert(filename); | |
454 | assert(lvalue); | |
455 | assert(rvalue); | |
456 | assert(data); | |
457 | ||
458 | if ((r = safe_atou(rvalue, u)) < 0) { | |
16354eff | 459 | log_error("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue); |
ed5bcfbe LP |
460 | return r; |
461 | } | |
462 | ||
463 | return 0; | |
464 | } | |
465 | ||
9ba1a159 | 466 | int config_parse_bytes_size( |
ed5bcfbe LP |
467 | const char *filename, |
468 | unsigned line, | |
469 | const char *section, | |
470 | const char *lvalue, | |
2b583ce6 | 471 | int ltype, |
ed5bcfbe LP |
472 | const char *rvalue, |
473 | void *data, | |
474 | void *userdata) { | |
475 | ||
476 | size_t *sz = data; | |
9ba1a159 | 477 | off_t o; |
ed5bcfbe LP |
478 | |
479 | assert(filename); | |
480 | assert(lvalue); | |
481 | assert(rvalue); | |
482 | assert(data); | |
483 | ||
9ba1a159 LP |
484 | if (parse_bytes(rvalue, &o) < 0 || (off_t) (size_t) o != o) { |
485 | log_error("[%s:%u] Failed to parse byte value, ignoring: %s", filename, line, rvalue); | |
486 | return 0; | |
487 | } | |
488 | ||
489 | *sz = (size_t) o; | |
490 | return 0; | |
491 | } | |
492 | ||
493 | ||
494 | int config_parse_bytes_off( | |
495 | const char *filename, | |
496 | unsigned line, | |
497 | const char *section, | |
498 | const char *lvalue, | |
499 | int ltype, | |
500 | const char *rvalue, | |
501 | void *data, | |
502 | void *userdata) { | |
503 | ||
504 | off_t *bytes = data; | |
505 | ||
506 | assert(filename); | |
507 | assert(lvalue); | |
508 | assert(rvalue); | |
509 | assert(data); | |
510 | ||
511 | assert_cc(sizeof(off_t) == sizeof(uint64_t)); | |
512 | ||
513 | if (parse_bytes(rvalue, bytes) < 0) { | |
514 | log_error("[%s:%u] Failed to parse bytes value, ignoring: %s", filename, line, rvalue); | |
f975e971 | 515 | return 0; |
ed5bcfbe LP |
516 | } |
517 | ||
ed5bcfbe LP |
518 | return 0; |
519 | } | |
520 | ||
521 | int config_parse_bool( | |
522 | const char *filename, | |
523 | unsigned line, | |
524 | const char *section, | |
525 | const char *lvalue, | |
2b583ce6 | 526 | int ltype, |
ed5bcfbe LP |
527 | const char *rvalue, |
528 | void *data, | |
529 | void *userdata) { | |
530 | ||
531 | int k; | |
532 | bool *b = data; | |
533 | ||
534 | assert(filename); | |
535 | assert(lvalue); | |
536 | assert(rvalue); | |
537 | assert(data); | |
538 | ||
539 | if ((k = parse_boolean(rvalue)) < 0) { | |
f975e971 LP |
540 | log_error("[%s:%u] Failed to parse boolean value, ignoring: %s", filename, line, rvalue); |
541 | return 0; | |
ed5bcfbe LP |
542 | } |
543 | ||
544 | *b = !!k; | |
545 | return 0; | |
546 | } | |
547 | ||
8d53b453 LP |
548 | int config_parse_tristate( |
549 | const char *filename, | |
550 | unsigned line, | |
551 | const char *section, | |
552 | const char *lvalue, | |
553 | int ltype, | |
554 | const char *rvalue, | |
555 | void *data, | |
556 | void *userdata) { | |
557 | ||
558 | int k; | |
559 | int *b = data; | |
560 | ||
561 | assert(filename); | |
562 | assert(lvalue); | |
563 | assert(rvalue); | |
564 | assert(data); | |
565 | ||
566 | /* Tristates are like booleans, but can also take the 'default' value, i.e. "-1" */ | |
567 | ||
568 | k = parse_boolean(rvalue); | |
569 | if (k < 0) { | |
570 | log_error("[%s:%u] Failed to parse boolean value, ignoring: %s", filename, line, rvalue); | |
571 | return 0; | |
572 | } | |
573 | ||
574 | *b = !!k; | |
575 | return 0; | |
576 | } | |
577 | ||
ed5bcfbe LP |
578 | int config_parse_string( |
579 | const char *filename, | |
580 | unsigned line, | |
581 | const char *section, | |
582 | const char *lvalue, | |
2b583ce6 | 583 | int ltype, |
ed5bcfbe LP |
584 | const char *rvalue, |
585 | void *data, | |
586 | void *userdata) { | |
587 | ||
588 | char **s = data; | |
589 | char *n; | |
590 | ||
591 | assert(filename); | |
592 | assert(lvalue); | |
593 | assert(rvalue); | |
594 | assert(data); | |
595 | ||
7f110ff9 LP |
596 | n = cunescape(rvalue); |
597 | if (!n) | |
598 | return -ENOMEM; | |
599 | ||
600 | if (!utf8_is_valid(n)) { | |
601 | log_error("[%s:%u] String is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue); | |
602 | free(n); | |
603 | return 0; | |
604 | } | |
ed5bcfbe LP |
605 | |
606 | free(*s); | |
7f110ff9 LP |
607 | if (*n) |
608 | *s = n; | |
609 | else { | |
610 | free(n); | |
611 | *s = NULL; | |
612 | } | |
ed5bcfbe LP |
613 | |
614 | return 0; | |
615 | } | |
57d42a5f | 616 | |
034c6ed7 LP |
617 | int config_parse_path( |
618 | const char *filename, | |
619 | unsigned line, | |
620 | const char *section, | |
621 | const char *lvalue, | |
2b583ce6 | 622 | int ltype, |
034c6ed7 LP |
623 | const char *rvalue, |
624 | void *data, | |
625 | void *userdata) { | |
626 | ||
627 | char **s = data; | |
628 | char *n; | |
629 | ||
630 | assert(filename); | |
631 | assert(lvalue); | |
632 | assert(rvalue); | |
633 | assert(data); | |
634 | ||
7f110ff9 LP |
635 | if (!utf8_is_valid(rvalue)) { |
636 | log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue); | |
637 | return 0; | |
638 | } | |
639 | ||
15ae422b | 640 | if (!path_is_absolute(rvalue)) { |
f975e971 LP |
641 | log_error("[%s:%u] Not an absolute path, ignoring: %s", filename, line, rvalue); |
642 | return 0; | |
034c6ed7 LP |
643 | } |
644 | ||
7f110ff9 LP |
645 | n = strdup(rvalue); |
646 | if (!n) | |
034c6ed7 LP |
647 | return -ENOMEM; |
648 | ||
01f78473 LP |
649 | path_kill_slashes(n); |
650 | ||
034c6ed7 LP |
651 | free(*s); |
652 | *s = n; | |
653 | ||
654 | return 0; | |
655 | } | |
57d42a5f LP |
656 | |
657 | int config_parse_strv( | |
658 | const char *filename, | |
659 | unsigned line, | |
660 | const char *section, | |
661 | const char *lvalue, | |
2b583ce6 | 662 | int ltype, |
57d42a5f LP |
663 | const char *rvalue, |
664 | void *data, | |
665 | void *userdata) { | |
666 | ||
667 | char*** sv = data; | |
668 | char **n; | |
669 | char *w; | |
670 | unsigned k; | |
671 | size_t l; | |
672 | char *state; | |
7f110ff9 | 673 | int r; |
57d42a5f LP |
674 | |
675 | assert(filename); | |
676 | assert(lvalue); | |
677 | assert(rvalue); | |
678 | assert(data); | |
679 | ||
680 | k = strv_length(*sv); | |
034c6ed7 | 681 | FOREACH_WORD_QUOTED(w, l, rvalue, state) |
57d42a5f LP |
682 | k++; |
683 | ||
7f110ff9 LP |
684 | n = new(char*, k+1); |
685 | if (!n) | |
57d42a5f LP |
686 | return -ENOMEM; |
687 | ||
3251df7d LP |
688 | if (*sv) |
689 | for (k = 0; (*sv)[k]; k++) | |
690 | n[k] = (*sv)[k]; | |
7418040c LP |
691 | else |
692 | k = 0; | |
3251df7d | 693 | |
7f110ff9 LP |
694 | FOREACH_WORD_QUOTED(w, l, rvalue, state) { |
695 | n[k] = cunescape_length(w, l); | |
696 | if (!n[k]) { | |
697 | r = -ENOMEM; | |
57d42a5f | 698 | goto fail; |
7f110ff9 LP |
699 | } |
700 | ||
701 | if (!utf8_is_valid(n[k])) { | |
702 | log_error("[%s:%u] String is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue); | |
703 | free(n[k]); | |
704 | continue; | |
705 | } | |
706 | ||
707 | k++; | |
708 | } | |
57d42a5f LP |
709 | |
710 | n[k] = NULL; | |
711 | free(*sv); | |
712 | *sv = n; | |
713 | ||
714 | return 0; | |
715 | ||
716 | fail: | |
717 | for (; k > 0; k--) | |
718 | free(n[k-1]); | |
034c6ed7 | 719 | free(n); |
57d42a5f | 720 | |
7f110ff9 | 721 | return r; |
57d42a5f | 722 | } |
15ae422b LP |
723 | |
724 | int config_parse_path_strv( | |
725 | const char *filename, | |
726 | unsigned line, | |
727 | const char *section, | |
728 | const char *lvalue, | |
2b583ce6 | 729 | int ltype, |
15ae422b LP |
730 | const char *rvalue, |
731 | void *data, | |
732 | void *userdata) { | |
733 | ||
734 | char*** sv = data; | |
735 | char **n; | |
736 | char *w; | |
737 | unsigned k; | |
738 | size_t l; | |
739 | char *state; | |
740 | int r; | |
741 | ||
742 | assert(filename); | |
743 | assert(lvalue); | |
744 | assert(rvalue); | |
745 | assert(data); | |
746 | ||
747 | k = strv_length(*sv); | |
748 | FOREACH_WORD_QUOTED(w, l, rvalue, state) | |
749 | k++; | |
750 | ||
7f110ff9 LP |
751 | n = new(char*, k+1); |
752 | if (!n) | |
15ae422b LP |
753 | return -ENOMEM; |
754 | ||
755 | k = 0; | |
756 | if (*sv) | |
757 | for (; (*sv)[k]; k++) | |
758 | n[k] = (*sv)[k]; | |
759 | ||
760 | FOREACH_WORD_QUOTED(w, l, rvalue, state) { | |
7f110ff9 LP |
761 | n[k] = strndup(w, l); |
762 | if (!n[k]) { | |
15ae422b LP |
763 | r = -ENOMEM; |
764 | goto fail; | |
765 | } | |
766 | ||
7f110ff9 LP |
767 | if (!utf8_is_valid(n[k])) { |
768 | log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue); | |
769 | free(n[k]); | |
770 | continue; | |
771 | } | |
772 | ||
15ae422b | 773 | if (!path_is_absolute(n[k])) { |
f975e971 LP |
774 | log_error("[%s:%u] Not an absolute path, ignoring: %s", filename, line, rvalue); |
775 | free(n[k]); | |
776 | continue; | |
15ae422b LP |
777 | } |
778 | ||
01f78473 | 779 | path_kill_slashes(n[k]); |
15ae422b LP |
780 | k++; |
781 | } | |
782 | ||
783 | n[k] = NULL; | |
784 | free(*sv); | |
785 | *sv = n; | |
786 | ||
787 | return 0; | |
788 | ||
789 | fail: | |
15ae422b LP |
790 | for (; k > 0; k--) |
791 | free(n[k-1]); | |
792 | free(n); | |
793 | ||
794 | return r; | |
795 | } | |
f975e971 LP |
796 | |
797 | int config_parse_usec( | |
798 | const char *filename, | |
799 | unsigned line, | |
800 | const char *section, | |
801 | const char *lvalue, | |
802 | int ltype, | |
803 | const char *rvalue, | |
804 | void *data, | |
805 | void *userdata) { | |
806 | ||
807 | usec_t *usec = data; | |
808 | ||
809 | assert(filename); | |
810 | assert(lvalue); | |
811 | assert(rvalue); | |
812 | assert(data); | |
813 | ||
814 | if (parse_usec(rvalue, usec) < 0) { | |
815 | log_error("[%s:%u] Failed to parse time value, ignoring: %s", filename, line, rvalue); | |
d88a251b LP |
816 | return 0; |
817 | } | |
818 | ||
819 | return 0; | |
820 | } | |
821 | ||
822 | int config_parse_nsec( | |
823 | const char *filename, | |
824 | unsigned line, | |
825 | const char *section, | |
826 | const char *lvalue, | |
827 | int ltype, | |
828 | const char *rvalue, | |
829 | void *data, | |
830 | void *userdata) { | |
831 | ||
832 | nsec_t *nsec = data; | |
833 | ||
834 | assert(filename); | |
835 | assert(lvalue); | |
836 | assert(rvalue); | |
837 | assert(data); | |
838 | ||
839 | if (parse_nsec(rvalue, nsec) < 0) { | |
840 | log_error("[%s:%u] Failed to parse time value, ignoring: %s", filename, line, rvalue); | |
f975e971 LP |
841 | return 0; |
842 | } | |
843 | ||
844 | return 0; | |
845 | } | |
846 | ||
847 | int config_parse_mode( | |
848 | const char *filename, | |
849 | unsigned line, | |
850 | const char *section, | |
851 | const char *lvalue, | |
852 | int ltype, | |
853 | const char *rvalue, | |
854 | void *data, | |
855 | void *userdata) { | |
856 | ||
857 | mode_t *m = data; | |
858 | long l; | |
859 | char *x = NULL; | |
860 | ||
861 | assert(filename); | |
862 | assert(lvalue); | |
863 | assert(rvalue); | |
864 | assert(data); | |
865 | ||
866 | errno = 0; | |
867 | l = strtol(rvalue, &x, 8); | |
868 | if (!x || *x || errno) { | |
869 | log_error("[%s:%u] Failed to parse mode value, ignoring: %s", filename, line, rvalue); | |
870 | return 0; | |
871 | } | |
872 | ||
873 | if (l < 0000 || l > 07777) { | |
874 | log_error("[%s:%u] mode value out of range, ignoring: %s", filename, line, rvalue); | |
875 | return 0; | |
876 | } | |
877 | ||
878 | *m = (mode_t) l; | |
879 | return 0; | |
880 | } | |
213ba152 LP |
881 | |
882 | int config_parse_facility( | |
883 | const char *filename, | |
884 | unsigned line, | |
885 | const char *section, | |
886 | const char *lvalue, | |
887 | int ltype, | |
888 | const char *rvalue, | |
889 | void *data, | |
890 | void *userdata) { | |
891 | ||
892 | ||
893 | int *o = data, x; | |
894 | ||
895 | assert(filename); | |
896 | assert(lvalue); | |
897 | assert(rvalue); | |
898 | assert(data); | |
899 | ||
900 | x = log_facility_unshifted_from_string(rvalue); | |
901 | if (x < 0) { | |
902 | log_error("[%s:%u] Failed to parse log facility, ignoring: %s", filename, line, rvalue); | |
903 | return 0; | |
904 | } | |
905 | ||
906 | *o = (x << 3) | LOG_PRI(*o); | |
907 | ||
908 | return 0; | |
909 | } | |
910 | ||
911 | int config_parse_level( | |
912 | const char *filename, | |
913 | unsigned line, | |
914 | const char *section, | |
915 | const char *lvalue, | |
916 | int ltype, | |
917 | const char *rvalue, | |
918 | void *data, | |
919 | void *userdata) { | |
920 | ||
921 | ||
922 | int *o = data, x; | |
923 | ||
924 | assert(filename); | |
925 | assert(lvalue); | |
926 | assert(rvalue); | |
927 | assert(data); | |
928 | ||
929 | x = log_level_from_string(rvalue); | |
930 | if (x < 0) { | |
931 | log_error("[%s:%u] Failed to parse log level, ignoring: %s", filename, line, rvalue); | |
932 | return 0; | |
933 | } | |
934 | ||
935 | *o = (*o & LOG_FACMASK) | x; | |
936 | return 0; | |
937 | } | |
96342de6 LN |
938 | |
939 | int config_parse_set_status( | |
940 | const char *filename, | |
941 | unsigned line, | |
942 | const char *section, | |
943 | const char *lvalue, | |
944 | int ltype, | |
945 | const char *rvalue, | |
946 | void *data, | |
947 | void *userdata) { | |
948 | ||
949 | char *w; | |
950 | size_t l; | |
951 | char *state; | |
952 | int r; | |
953 | ExitStatusSet *status_set = data; | |
954 | ||
955 | assert(filename); | |
956 | assert(lvalue); | |
957 | assert(rvalue); | |
958 | assert(data); | |
959 | ||
960 | FOREACH_WORD(w, l, rvalue, state) { | |
961 | int val; | |
962 | char *temp = strndup(w, l); | |
963 | if (!temp) | |
964 | return log_oom(); | |
965 | ||
966 | r = safe_atoi(temp, &val); | |
967 | if (r < 0) { | |
968 | val = signal_from_string_try_harder(temp); | |
969 | free(temp); | |
970 | if (val > 0) { | |
971 | if (!status_set->signal) { | |
972 | status_set->signal = set_new(trivial_hash_func, trivial_compare_func); | |
973 | if (!status_set->signal) | |
974 | return log_oom(); | |
975 | } | |
976 | r = set_put(status_set->signal, INT_TO_PTR(val)); | |
977 | if (r < 0) { | |
978 | log_error("[%s:%u] Unable to store: %s", filename, line, w); | |
979 | return r; | |
980 | } | |
981 | } else { | |
982 | log_error("[%s:%u] Failed to parse value: %s", filename, line, w); | |
983 | return r; | |
984 | } | |
985 | } else { | |
986 | free(temp); | |
987 | if(val < 0 || val > 255) | |
988 | log_warning("[%s:%u] Value %d is outside range 0-255, ignoring", filename, line, val); | |
989 | else { | |
990 | if (!status_set->code) { | |
991 | status_set->code = set_new(trivial_hash_func, trivial_compare_func); | |
992 | if (!status_set->code) | |
993 | return log_oom(); | |
994 | } | |
995 | r = set_put(status_set->code, INT_TO_PTR(val)); | |
996 | if (r < 0) { | |
997 | log_error("[%s:%u] Unable to store: %s", filename, line, w); | |
998 | return r; | |
999 | } | |
1000 | } | |
1001 | } | |
1002 | ||
1003 | } | |
1004 | return 0; | |
1005 | } |