]>
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> | |
ed5bcfbe LP |
25 | #include <stdlib.h> |
26 | ||
27 | #include "conf-parser.h" | |
e8461023 | 28 | #include "conf-files.h" |
ed5bcfbe LP |
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" |
e8e581bf ZJS |
35 | #include "sd-messages.h" |
36 | ||
f975e971 | 37 | int config_item_table_lookup( |
e9f3d2d5 | 38 | const void *table, |
ed5bcfbe | 39 | const char *section, |
ed5bcfbe | 40 | const char *lvalue, |
f975e971 LP |
41 | ConfigParserCallback *func, |
42 | int *ltype, | |
43 | void **data, | |
ed5bcfbe LP |
44 | void *userdata) { |
45 | ||
e9f3d2d5 | 46 | const ConfigTableItem *t; |
f975e971 LP |
47 | |
48 | assert(table); | |
ed5bcfbe | 49 | assert(lvalue); |
f975e971 LP |
50 | assert(func); |
51 | assert(ltype); | |
52 | assert(data); | |
ed5bcfbe | 53 | |
f975e971 | 54 | for (t = table; t->lvalue; t++) { |
ed5bcfbe | 55 | |
f975e971 | 56 | if (!streq(lvalue, t->lvalue)) |
ed5bcfbe LP |
57 | continue; |
58 | ||
f975e971 | 59 | if (!streq_ptr(section, t->section)) |
ed5bcfbe LP |
60 | continue; |
61 | ||
f975e971 LP |
62 | *func = t->parse; |
63 | *ltype = t->ltype; | |
64 | *data = t->data; | |
65 | return 1; | |
66 | } | |
ed5bcfbe | 67 | |
f975e971 LP |
68 | return 0; |
69 | } | |
10e87ee7 | 70 | |
f975e971 | 71 | int config_item_perf_lookup( |
e9f3d2d5 | 72 | const void *table, |
f975e971 LP |
73 | const char *section, |
74 | const char *lvalue, | |
75 | ConfigParserCallback *func, | |
76 | int *ltype, | |
77 | void **data, | |
78 | void *userdata) { | |
79 | ||
80 | ConfigPerfItemLookup lookup = (ConfigPerfItemLookup) table; | |
81 | const ConfigPerfItem *p; | |
82 | ||
83 | assert(table); | |
84 | assert(lvalue); | |
85 | assert(func); | |
86 | assert(ltype); | |
87 | assert(data); | |
88 | ||
89 | if (!section) | |
90 | p = lookup(lvalue, strlen(lvalue)); | |
91 | else { | |
92 | char *key; | |
93 | ||
b7def684 | 94 | key = strjoin(section, ".", lvalue, NULL); |
44d91056 | 95 | if (!key) |
f975e971 LP |
96 | return -ENOMEM; |
97 | ||
98 | p = lookup(key, strlen(key)); | |
99 | free(key); | |
ed5bcfbe LP |
100 | } |
101 | ||
f975e971 LP |
102 | if (!p) |
103 | return 0; | |
104 | ||
105 | *func = p->parse; | |
106 | *ltype = p->ltype; | |
107 | *data = (uint8_t*) userdata + p->offset; | |
108 | return 1; | |
109 | } | |
110 | ||
111 | /* Run the user supplied parser for an assignment */ | |
e8e581bf ZJS |
112 | static int next_assignment(const char *unit, |
113 | const char *filename, | |
114 | unsigned line, | |
115 | ConfigItemLookup lookup, | |
e9f3d2d5 | 116 | const void *table, |
e8e581bf | 117 | const char *section, |
71a61510 | 118 | unsigned section_line, |
e8e581bf ZJS |
119 | const char *lvalue, |
120 | const char *rvalue, | |
121 | bool relaxed, | |
122 | void *userdata) { | |
f975e971 LP |
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) | |
71a61510 TG |
141 | return func(unit, filename, line, section, section_line, |
142 | lvalue, ltype, rvalue, data, userdata); | |
d937fbbd LP |
143 | |
144 | return 0; | |
145 | } | |
f975e971 | 146 | |
46205bb6 | 147 | /* Warn about unknown non-extension fields. */ |
10e87ee7 | 148 | if (!relaxed && !startswith(lvalue, "X-")) |
e8e581bf ZJS |
149 | log_syntax(unit, LOG_WARNING, filename, line, EINVAL, |
150 | "Unknown lvalue '%s' in section '%s'", lvalue, section); | |
46205bb6 | 151 | |
f1857be0 | 152 | return 0; |
ed5bcfbe LP |
153 | } |
154 | ||
ed5bcfbe | 155 | /* Parse a variable assignment line */ |
e8e581bf ZJS |
156 | static int parse_line(const char* unit, |
157 | const char *filename, | |
158 | unsigned line, | |
159 | const char *sections, | |
160 | ConfigItemLookup lookup, | |
e9f3d2d5 | 161 | const void *table, |
e8e581bf | 162 | bool relaxed, |
db5c0122 | 163 | bool allow_include, |
e8e581bf | 164 | char **section, |
71a61510 | 165 | unsigned *section_line, |
342aea19 | 166 | bool *section_ignored, |
e8e581bf ZJS |
167 | char *l, |
168 | void *userdata) { | |
f975e971 | 169 | |
b2aa81ef | 170 | char *e; |
ed5bcfbe | 171 | |
f975e971 LP |
172 | assert(filename); |
173 | assert(line > 0); | |
174 | assert(lookup); | |
175 | assert(l); | |
176 | ||
b2aa81ef | 177 | l = strstrip(l); |
ed5bcfbe | 178 | |
b2aa81ef | 179 | if (!*l) |
ed5bcfbe | 180 | return 0; |
1ea86b18 | 181 | |
d3b6d0c2 | 182 | if (strchr(COMMENTS "\n", *l)) |
1ea86b18 | 183 | return 0; |
ed5bcfbe | 184 | |
b2aa81ef | 185 | if (startswith(l, ".include ")) { |
db5c0122 LP |
186 | _cleanup_free_ char *fn = NULL; |
187 | ||
b8e7a47b LP |
188 | /* .includes are a bad idea, we only support them here |
189 | * for historical reasons. They create cyclic include | |
190 | * problems and make it difficult to detect | |
191 | * configuration file changes with an easy | |
192 | * stat(). Better approaches, such as .d/ drop-in | |
193 | * snippets exist. | |
194 | * | |
195 | * Support for them should be eventually removed. */ | |
196 | ||
db5c0122 LP |
197 | if (!allow_include) { |
198 | log_syntax(unit, LOG_ERR, filename, line, EBADMSG, | |
199 | ".include not allowed here. Ignoring."); | |
200 | return 0; | |
201 | } | |
ed5bcfbe | 202 | |
f975e971 LP |
203 | fn = file_in_same_dir(filename, strstrip(l+9)); |
204 | if (!fn) | |
b2aa81ef | 205 | return -ENOMEM; |
ed5bcfbe | 206 | |
36f822c4 | 207 | return config_parse(unit, fn, NULL, sections, lookup, table, relaxed, false, false, userdata); |
ed5bcfbe LP |
208 | } |
209 | ||
b2aa81ef | 210 | if (*l == '[') { |
ed5bcfbe LP |
211 | size_t k; |
212 | char *n; | |
213 | ||
b2aa81ef | 214 | k = strlen(l); |
ed5bcfbe LP |
215 | assert(k > 0); |
216 | ||
b2aa81ef | 217 | if (l[k-1] != ']') { |
e8e581bf ZJS |
218 | log_syntax(unit, LOG_ERR, filename, line, EBADMSG, |
219 | "Invalid section header '%s'", l); | |
ed5bcfbe LP |
220 | return -EBADMSG; |
221 | } | |
222 | ||
f975e971 LP |
223 | n = strndup(l+1, k-2); |
224 | if (!n) | |
ed5bcfbe LP |
225 | return -ENOMEM; |
226 | ||
f975e971 | 227 | if (sections && !nulstr_contains(sections, n)) { |
42f4e3c4 | 228 | |
342aea19 | 229 | if (!relaxed && !startswith(n, "X-")) |
e8e581bf ZJS |
230 | log_syntax(unit, LOG_WARNING, filename, line, EINVAL, |
231 | "Unknown section '%s'. Ignoring.", n); | |
f975e971 LP |
232 | |
233 | free(n); | |
91ffff96 | 234 | free(*section); |
f975e971 | 235 | *section = NULL; |
71a61510 | 236 | *section_line = 0; |
342aea19 | 237 | *section_ignored = true; |
f975e971 LP |
238 | } else { |
239 | free(*section); | |
240 | *section = n; | |
71a61510 | 241 | *section_line = line; |
342aea19 | 242 | *section_ignored = false; |
f975e971 | 243 | } |
ed5bcfbe LP |
244 | |
245 | return 0; | |
246 | } | |
247 | ||
62f168a0 LP |
248 | if (sections && !*section) { |
249 | ||
342aea19 | 250 | if (!relaxed && !*section_ignored) |
e8e581bf ZJS |
251 | log_syntax(unit, LOG_WARNING, filename, line, EINVAL, |
252 | "Assignment outside of section. Ignoring."); | |
62f168a0 | 253 | |
10e87ee7 | 254 | return 0; |
62f168a0 | 255 | } |
10e87ee7 | 256 | |
f975e971 LP |
257 | e = strchr(l, '='); |
258 | if (!e) { | |
e8e581bf | 259 | log_syntax(unit, LOG_WARNING, filename, line, EINVAL, "Missing '='."); |
ed5bcfbe LP |
260 | return -EBADMSG; |
261 | } | |
262 | ||
263 | *e = 0; | |
264 | e++; | |
265 | ||
e8e581bf ZJS |
266 | return next_assignment(unit, |
267 | filename, | |
268 | line, | |
269 | lookup, | |
270 | table, | |
271 | *section, | |
71a61510 | 272 | *section_line, |
e8e581bf ZJS |
273 | strstrip(l), |
274 | strstrip(e), | |
275 | relaxed, | |
276 | userdata); | |
ed5bcfbe LP |
277 | } |
278 | ||
279 | /* Go through the file and parse each line */ | |
e8e581bf ZJS |
280 | int config_parse(const char *unit, |
281 | const char *filename, | |
282 | FILE *f, | |
283 | const char *sections, | |
284 | ConfigItemLookup lookup, | |
e9f3d2d5 | 285 | const void *table, |
e8e581bf | 286 | bool relaxed, |
db5c0122 | 287 | bool allow_include, |
36f822c4 | 288 | bool warn, |
e8e581bf | 289 | void *userdata) { |
f975e971 | 290 | |
7fd1b19b HH |
291 | _cleanup_free_ char *section = NULL, *continuation = NULL; |
292 | _cleanup_fclose_ FILE *ours = NULL; | |
71a61510 | 293 | unsigned line = 0, section_line = 0; |
342aea19 | 294 | bool section_ignored = false; |
ed5bcfbe LP |
295 | int r; |
296 | ||
297 | assert(filename); | |
f975e971 | 298 | assert(lookup); |
ed5bcfbe | 299 | |
87f0e418 | 300 | if (!f) { |
245802dd | 301 | f = ours = fopen(filename, "re"); |
f975e971 | 302 | if (!f) { |
36f822c4 ZJS |
303 | /* Only log on request, except for ENOENT, |
304 | * since we return 0 to the caller. */ | |
305 | if (warn || errno == ENOENT) | |
306 | log_full(errno == ENOENT ? LOG_DEBUG : LOG_ERR, | |
307 | "Failed to open configuration file '%s': %m", filename); | |
9f43a07f | 308 | return errno == ENOENT ? 0 : -errno; |
87f0e418 | 309 | } |
ed5bcfbe LP |
310 | } |
311 | ||
fdb9161c LP |
312 | fd_warn_permissions(filename, fileno(f)); |
313 | ||
ed5bcfbe | 314 | while (!feof(f)) { |
3dab2943 LP |
315 | char l[LINE_MAX], *p, *c = NULL, *e; |
316 | bool escaped = false; | |
ed5bcfbe LP |
317 | |
318 | if (!fgets(l, sizeof(l), f)) { | |
319 | if (feof(f)) | |
320 | break; | |
321 | ||
56f64d95 | 322 | log_error_errno(errno, "Failed to read configuration file '%s': %m", filename); |
245802dd | 323 | return -errno; |
ed5bcfbe LP |
324 | } |
325 | ||
3dab2943 LP |
326 | truncate_nl(l); |
327 | ||
328 | if (continuation) { | |
f975e971 | 329 | c = strappend(continuation, l); |
36f822c4 ZJS |
330 | if (!c) { |
331 | if (warn) | |
332 | log_oom(); | |
245802dd | 333 | return -ENOMEM; |
36f822c4 | 334 | } |
3dab2943 LP |
335 | |
336 | free(continuation); | |
337 | continuation = NULL; | |
338 | p = c; | |
339 | } else | |
340 | p = l; | |
341 | ||
342 | for (e = p; *e; e++) { | |
343 | if (escaped) | |
344 | escaped = false; | |
345 | else if (*e == '\\') | |
346 | escaped = true; | |
347 | } | |
348 | ||
349 | if (escaped) { | |
350 | *(e-1) = ' '; | |
351 | ||
352 | if (c) | |
353 | continuation = c; | |
f975e971 LP |
354 | else { |
355 | continuation = strdup(l); | |
36f822c4 ZJS |
356 | if (!continuation) { |
357 | if (warn) | |
358 | log_oom(); | |
245802dd | 359 | return -ENOMEM; |
36f822c4 | 360 | } |
3dab2943 LP |
361 | } |
362 | ||
363 | continue; | |
364 | } | |
365 | ||
e8e581bf ZJS |
366 | r = parse_line(unit, |
367 | filename, | |
368 | ++line, | |
369 | sections, | |
370 | lookup, | |
371 | table, | |
372 | relaxed, | |
db5c0122 | 373 | allow_include, |
e8e581bf | 374 | §ion, |
71a61510 | 375 | §ion_line, |
342aea19 | 376 | §ion_ignored, |
e8e581bf ZJS |
377 | p, |
378 | userdata); | |
3dab2943 LP |
379 | free(c); |
380 | ||
36f822c4 ZJS |
381 | if (r < 0) { |
382 | if (warn) | |
c33b3297 MS |
383 | log_warning_errno(r, "Failed to parse file '%s': %m", |
384 | filename); | |
245802dd | 385 | return r; |
36f822c4 | 386 | } |
ed5bcfbe LP |
387 | } |
388 | ||
245802dd | 389 | return 0; |
ed5bcfbe LP |
390 | } |
391 | ||
e8461023 JT |
392 | /* Parse each config file in the specified directories. */ |
393 | int config_parse_many(const char *conf_file, | |
394 | const char *conf_file_dirs, | |
395 | const char *sections, | |
396 | ConfigItemLookup lookup, | |
397 | const void *table, | |
398 | bool relaxed, | |
399 | void *userdata) { | |
400 | _cleanup_strv_free_ char **files = NULL; | |
401 | char **fn; | |
402 | int r; | |
403 | ||
404 | r = conf_files_list_nulstr(&files, ".conf", NULL, conf_file_dirs); | |
405 | if (r < 0) | |
406 | return r; | |
407 | ||
408 | if (conf_file) { | |
409 | r = config_parse(NULL, conf_file, NULL, sections, lookup, table, relaxed, false, true, userdata); | |
410 | if (r < 0) | |
411 | return r; | |
412 | } | |
413 | ||
414 | STRV_FOREACH(fn, files) { | |
415 | r = config_parse(NULL, *fn, NULL, sections, lookup, table, relaxed, false, true, userdata); | |
416 | if (r < 0) | |
417 | return r; | |
418 | } | |
419 | ||
420 | return 0; | |
421 | } | |
422 | ||
eb3491d9 | 423 | #define DEFINE_PARSER(type, vartype, conv_func) \ |
e8e581bf ZJS |
424 | int config_parse_##type(const char *unit, \ |
425 | const char *filename, \ | |
eb3491d9 ZJS |
426 | unsigned line, \ |
427 | const char *section, \ | |
71a61510 | 428 | unsigned section_line, \ |
eb3491d9 ZJS |
429 | const char *lvalue, \ |
430 | int ltype, \ | |
431 | const char *rvalue, \ | |
432 | void *data, \ | |
433 | void *userdata) { \ | |
434 | \ | |
435 | vartype *i = data; \ | |
436 | int r; \ | |
437 | \ | |
438 | assert(filename); \ | |
439 | assert(lvalue); \ | |
440 | assert(rvalue); \ | |
441 | assert(data); \ | |
442 | \ | |
443 | r = conv_func(rvalue, i); \ | |
444 | if (r < 0) \ | |
e8e581bf ZJS |
445 | log_syntax(unit, LOG_ERR, filename, line, -r, \ |
446 | "Failed to parse %s value, ignoring: %s", \ | |
98d75800 | 447 | #type, rvalue); \ |
eb3491d9 ZJS |
448 | \ |
449 | return 0; \ | |
ed5bcfbe LP |
450 | } |
451 | ||
eb3491d9 ZJS |
452 | DEFINE_PARSER(int, int, safe_atoi) |
453 | DEFINE_PARSER(long, long, safe_atoli) | |
454 | DEFINE_PARSER(uint64, uint64_t, safe_atou64) | |
455 | DEFINE_PARSER(unsigned, unsigned, safe_atou) | |
456 | DEFINE_PARSER(double, double, safe_atod) | |
457 | DEFINE_PARSER(nsec, nsec_t, parse_nsec) | |
458 | DEFINE_PARSER(sec, usec_t, parse_sec) | |
ed5bcfbe | 459 | |
5556b5fe | 460 | int config_parse_iec_size(const char* unit, |
e8e581bf ZJS |
461 | const char *filename, |
462 | unsigned line, | |
463 | const char *section, | |
71a61510 | 464 | unsigned section_line, |
e8e581bf ZJS |
465 | const char *lvalue, |
466 | int ltype, | |
467 | const char *rvalue, | |
468 | void *data, | |
469 | void *userdata) { | |
ed5bcfbe LP |
470 | |
471 | size_t *sz = data; | |
9ba1a159 | 472 | off_t o; |
e8e581bf | 473 | int r; |
ed5bcfbe LP |
474 | |
475 | assert(filename); | |
476 | assert(lvalue); | |
477 | assert(rvalue); | |
478 | assert(data); | |
479 | ||
5556b5fe | 480 | r = parse_size(rvalue, 1024, &o); |
e8e581bf | 481 | if (r < 0 || (off_t) (size_t) o != o) { |
5556b5fe | 482 | log_syntax(unit, LOG_ERR, filename, line, r < 0 ? -r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue); |
9ba1a159 LP |
483 | return 0; |
484 | } | |
485 | ||
486 | *sz = (size_t) o; | |
487 | return 0; | |
488 | } | |
489 | ||
5556b5fe LP |
490 | int config_parse_si_size(const char* unit, |
491 | const char *filename, | |
492 | unsigned line, | |
493 | const char *section, | |
494 | unsigned section_line, | |
495 | const char *lvalue, | |
496 | int ltype, | |
497 | const char *rvalue, | |
498 | void *data, | |
499 | void *userdata) { | |
500 | ||
501 | size_t *sz = data; | |
502 | off_t o; | |
503 | int r; | |
504 | ||
505 | assert(filename); | |
506 | assert(lvalue); | |
507 | assert(rvalue); | |
508 | assert(data); | |
509 | ||
510 | r = parse_size(rvalue, 1000, &o); | |
511 | if (r < 0 || (off_t) (size_t) o != o) { | |
512 | log_syntax(unit, LOG_ERR, filename, line, r < 0 ? -r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue); | |
513 | return 0; | |
514 | } | |
515 | ||
516 | *sz = (size_t) o; | |
517 | return 0; | |
518 | } | |
9ba1a159 | 519 | |
5556b5fe | 520 | int config_parse_iec_off(const char* unit, |
e8e581bf ZJS |
521 | const char *filename, |
522 | unsigned line, | |
523 | const char *section, | |
71a61510 | 524 | unsigned section_line, |
e8e581bf ZJS |
525 | const char *lvalue, |
526 | int ltype, | |
527 | const char *rvalue, | |
528 | void *data, | |
529 | void *userdata) { | |
9ba1a159 LP |
530 | |
531 | off_t *bytes = data; | |
e8e581bf | 532 | int r; |
9ba1a159 LP |
533 | |
534 | assert(filename); | |
535 | assert(lvalue); | |
536 | assert(rvalue); | |
537 | assert(data); | |
538 | ||
539 | assert_cc(sizeof(off_t) == sizeof(uint64_t)); | |
540 | ||
5556b5fe | 541 | r = parse_size(rvalue, 1024, bytes); |
e8e581bf | 542 | if (r < 0) |
5556b5fe | 543 | log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to parse size value, ignoring: %s", rvalue); |
ed5bcfbe | 544 | |
ed5bcfbe LP |
545 | return 0; |
546 | } | |
547 | ||
e8e581bf ZJS |
548 | int config_parse_bool(const char* unit, |
549 | const char *filename, | |
550 | unsigned line, | |
551 | const char *section, | |
71a61510 | 552 | unsigned section_line, |
e8e581bf ZJS |
553 | const char *lvalue, |
554 | int ltype, | |
555 | const char *rvalue, | |
556 | void *data, | |
557 | void *userdata) { | |
ed5bcfbe LP |
558 | |
559 | int k; | |
560 | bool *b = data; | |
561 | ||
562 | assert(filename); | |
563 | assert(lvalue); | |
564 | assert(rvalue); | |
565 | assert(data); | |
566 | ||
e8e581bf ZJS |
567 | k = parse_boolean(rvalue); |
568 | if (k < 0) { | |
569 | log_syntax(unit, LOG_ERR, filename, line, -k, | |
570 | "Failed to parse boolean value, ignoring: %s", rvalue); | |
f975e971 | 571 | return 0; |
ed5bcfbe LP |
572 | } |
573 | ||
574 | *b = !!k; | |
575 | return 0; | |
576 | } | |
577 | ||
8f2665a4 LP |
578 | int config_parse_string( |
579 | const char *unit, | |
580 | const char *filename, | |
581 | unsigned line, | |
582 | const char *section, | |
583 | unsigned section_line, | |
584 | const char *lvalue, | |
585 | int ltype, | |
586 | const char *rvalue, | |
587 | void *data, | |
588 | void *userdata) { | |
589 | ||
590 | char **s = data, *n; | |
ed5bcfbe LP |
591 | |
592 | assert(filename); | |
593 | assert(lvalue); | |
594 | assert(rvalue); | |
595 | assert(data); | |
596 | ||
8f2665a4 | 597 | if (!utf8_is_valid(rvalue)) { |
b5d74213 | 598 | log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue); |
7f110ff9 LP |
599 | return 0; |
600 | } | |
ed5bcfbe | 601 | |
8f2665a4 LP |
602 | if (isempty(rvalue)) |
603 | n = NULL; | |
7f110ff9 | 604 | else { |
8f2665a4 LP |
605 | n = strdup(rvalue); |
606 | if (!n) | |
607 | return log_oom(); | |
7f110ff9 | 608 | } |
ed5bcfbe | 609 | |
8f2665a4 LP |
610 | free(*s); |
611 | *s = n; | |
612 | ||
ed5bcfbe LP |
613 | return 0; |
614 | } | |
57d42a5f | 615 | |
8f2665a4 LP |
616 | int config_parse_path( |
617 | const char *unit, | |
618 | const char *filename, | |
619 | unsigned line, | |
620 | const char *section, | |
621 | unsigned section_line, | |
622 | const char *lvalue, | |
623 | int ltype, | |
624 | const char *rvalue, | |
625 | void *data, | |
626 | void *userdata) { | |
034c6ed7 | 627 | |
3b436292 | 628 | char **s = data, *n; |
034c6ed7 LP |
629 | |
630 | assert(filename); | |
631 | assert(lvalue); | |
632 | assert(rvalue); | |
633 | assert(data); | |
634 | ||
7f110ff9 | 635 | if (!utf8_is_valid(rvalue)) { |
b5d74213 | 636 | log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue); |
7f110ff9 LP |
637 | return 0; |
638 | } | |
639 | ||
3b436292 LP |
640 | if (!path_is_absolute(rvalue)) { |
641 | log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Not an absolute path, ignoring: %s", rvalue); | |
f975e971 | 642 | return 0; |
034c6ed7 LP |
643 | } |
644 | ||
7f110ff9 LP |
645 | n = strdup(rvalue); |
646 | if (!n) | |
74051b9b | 647 | return log_oom(); |
034c6ed7 | 648 | |
01f78473 LP |
649 | path_kill_slashes(n); |
650 | ||
034c6ed7 LP |
651 | free(*s); |
652 | *s = n; | |
653 | ||
654 | return 0; | |
655 | } | |
57d42a5f | 656 | |
e8e581bf ZJS |
657 | int config_parse_strv(const char *unit, |
658 | const char *filename, | |
659 | unsigned line, | |
660 | const char *section, | |
71a61510 | 661 | unsigned section_line, |
e8e581bf ZJS |
662 | const char *lvalue, |
663 | int ltype, | |
664 | const char *rvalue, | |
665 | void *data, | |
666 | void *userdata) { | |
57d42a5f | 667 | |
a2a5291b ZJS |
668 | char ***sv = data; |
669 | const char *word, *state; | |
57d42a5f | 670 | size_t l; |
7f110ff9 | 671 | int r; |
57d42a5f LP |
672 | |
673 | assert(filename); | |
674 | assert(lvalue); | |
675 | assert(rvalue); | |
676 | assert(data); | |
677 | ||
74051b9b | 678 | if (isempty(rvalue)) { |
4589f5bb LP |
679 | char **empty; |
680 | ||
681 | /* Empty assignment resets the list. As a special rule | |
682 | * we actually fill in a real empty array here rather | |
683 | * than NULL, since some code wants to know if | |
684 | * something was set at all... */ | |
685 | empty = strv_new(NULL, NULL); | |
686 | if (!empty) | |
687 | return log_oom(); | |
688 | ||
74051b9b | 689 | strv_free(*sv); |
4589f5bb | 690 | *sv = empty; |
853b8397 | 691 | return 0; |
74051b9b LP |
692 | } |
693 | ||
a2a5291b | 694 | FOREACH_WORD_QUOTED(word, l, rvalue, state) { |
6e18964d | 695 | char *n; |
7f110ff9 | 696 | |
a2a5291b | 697 | n = strndup(word, l); |
853b8397 LP |
698 | if (!n) |
699 | return log_oom(); | |
700 | ||
701 | if (!utf8_is_valid(n)) { | |
b5d74213 | 702 | log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue); |
9e602778 | 703 | free(n); |
7f110ff9 LP |
704 | continue; |
705 | } | |
706 | ||
6e18964d | 707 | r = strv_consume(sv, n); |
853b8397 LP |
708 | if (r < 0) |
709 | return log_oom(); | |
7f110ff9 | 710 | } |
b2fadec6 ZJS |
711 | if (!isempty(state)) |
712 | log_syntax(unit, LOG_ERR, filename, line, EINVAL, | |
713 | "Trailing garbage, ignoring."); | |
57d42a5f | 714 | |
57d42a5f | 715 | return 0; |
57d42a5f | 716 | } |
15ae422b | 717 | |
2ff7b0a5 LP |
718 | int config_parse_mode( |
719 | const char *unit, | |
720 | const char *filename, | |
721 | unsigned line, | |
722 | const char *section, | |
71a61510 | 723 | unsigned section_line, |
2ff7b0a5 LP |
724 | const char *lvalue, |
725 | int ltype, | |
726 | const char *rvalue, | |
727 | void *data, | |
728 | void *userdata) { | |
f975e971 LP |
729 | |
730 | mode_t *m = data; | |
f975e971 LP |
731 | |
732 | assert(filename); | |
733 | assert(lvalue); | |
734 | assert(rvalue); | |
735 | assert(data); | |
736 | ||
2ff7b0a5 LP |
737 | if (parse_mode(rvalue, m) < 0) { |
738 | log_syntax(unit, LOG_ERR, filename, line, errno, "Failed to parse mode value, ignoring: %s", rvalue); | |
f975e971 LP |
739 | return 0; |
740 | } | |
741 | ||
f975e971 LP |
742 | return 0; |
743 | } | |
213ba152 | 744 | |
ca37242e LP |
745 | int config_parse_log_facility( |
746 | const char *unit, | |
747 | const char *filename, | |
748 | unsigned line, | |
749 | const char *section, | |
750 | unsigned section_line, | |
751 | const char *lvalue, | |
752 | int ltype, | |
753 | const char *rvalue, | |
754 | void *data, | |
755 | void *userdata) { | |
213ba152 LP |
756 | |
757 | ||
758 | int *o = data, x; | |
759 | ||
760 | assert(filename); | |
761 | assert(lvalue); | |
762 | assert(rvalue); | |
763 | assert(data); | |
764 | ||
765 | x = log_facility_unshifted_from_string(rvalue); | |
766 | if (x < 0) { | |
769d324c | 767 | log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse log facility, ignoring: %s", rvalue); |
213ba152 LP |
768 | return 0; |
769 | } | |
770 | ||
771 | *o = (x << 3) | LOG_PRI(*o); | |
772 | ||
773 | return 0; | |
774 | } | |
775 | ||
ca37242e LP |
776 | int config_parse_log_level( |
777 | const char *unit, | |
778 | const char *filename, | |
779 | unsigned line, | |
780 | const char *section, | |
781 | unsigned section_line, | |
782 | const char *lvalue, | |
783 | int ltype, | |
784 | const char *rvalue, | |
785 | void *data, | |
786 | void *userdata) { | |
213ba152 LP |
787 | |
788 | ||
789 | int *o = data, x; | |
790 | ||
791 | assert(filename); | |
792 | assert(lvalue); | |
793 | assert(rvalue); | |
794 | assert(data); | |
795 | ||
796 | x = log_level_from_string(rvalue); | |
797 | if (x < 0) { | |
769d324c | 798 | log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse log level, ignoring: %s", rvalue); |
213ba152 LP |
799 | return 0; |
800 | } | |
801 | ||
802 | *o = (*o & LOG_FACMASK) | x; | |
803 | return 0; | |
804 | } |