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