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