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