]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/conf-parser.c
time-util: Introduce parse_sec_def_infinity
[thirdparty/systemd.git] / src / shared / conf-parser.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
a7334b09 2
ed5bcfbe 3#include <errno.h>
a8fbdf54
TA
4#include <limits.h>
5#include <stdint.h>
07630cea 6#include <stdio.h>
ed5bcfbe 7#include <stdlib.h>
07630cea 8#include <string.h>
a8fbdf54 9#include <sys/types.h>
07630cea 10
b5efdb8a 11#include "alloc-util.h"
e8461023 12#include "conf-files.h"
6bedfcbb 13#include "conf-parser.h"
e6dde451 14#include "def.h"
a8fbdf54 15#include "extract-word.h"
6bedfcbb 16#include "fd-util.h"
e6dde451 17#include "fileio.h"
f4f15635 18#include "fs-util.h"
16354eff 19#include "log.h"
07630cea 20#include "macro.h"
ef118d00 21#include "missing.h"
6bedfcbb 22#include "parse-util.h"
9eb977db 23#include "path-util.h"
7b3e062c 24#include "process-util.h"
ef118d00 25#include "rlimit-util.h"
f757855e 26#include "signal-util.h"
d31645ad 27#include "socket-util.h"
07630cea
LP
28#include "string-util.h"
29#include "strv.h"
7b3e062c 30#include "syslog-util.h"
a8fbdf54 31#include "time-util.h"
07630cea 32#include "utf8.h"
e8e581bf 33
f975e971 34int config_item_table_lookup(
e9f3d2d5 35 const void *table,
ed5bcfbe 36 const char *section,
ed5bcfbe 37 const char *lvalue,
f975e971
LP
38 ConfigParserCallback *func,
39 int *ltype,
40 void **data,
ed5bcfbe
LP
41 void *userdata) {
42
e9f3d2d5 43 const ConfigTableItem *t;
f975e971
LP
44
45 assert(table);
ed5bcfbe 46 assert(lvalue);
f975e971
LP
47 assert(func);
48 assert(ltype);
49 assert(data);
ed5bcfbe 50
f975e971 51 for (t = table; t->lvalue; t++) {
ed5bcfbe 52
f975e971 53 if (!streq(lvalue, t->lvalue))
ed5bcfbe
LP
54 continue;
55
f975e971 56 if (!streq_ptr(section, t->section))
ed5bcfbe
LP
57 continue;
58
f975e971
LP
59 *func = t->parse;
60 *ltype = t->ltype;
61 *data = t->data;
62 return 1;
63 }
ed5bcfbe 64
f975e971
LP
65 return 0;
66}
10e87ee7 67
f975e971 68int config_item_perf_lookup(
e9f3d2d5 69 const void *table,
f975e971
LP
70 const char *section,
71 const char *lvalue,
72 ConfigParserCallback *func,
73 int *ltype,
74 void **data,
75 void *userdata) {
76
77 ConfigPerfItemLookup lookup = (ConfigPerfItemLookup) table;
78 const ConfigPerfItem *p;
79
80 assert(table);
81 assert(lvalue);
82 assert(func);
83 assert(ltype);
84 assert(data);
85
4472fa6d
LP
86 if (section) {
87 const char *key;
f975e971 88
4472fa6d 89 key = strjoina(section, ".", lvalue);
f975e971 90 p = lookup(key, strlen(key));
4472fa6d
LP
91 } else
92 p = lookup(lvalue, strlen(lvalue));
f975e971
LP
93 if (!p)
94 return 0;
95
96 *func = p->parse;
97 *ltype = p->ltype;
98 *data = (uint8_t*) userdata + p->offset;
99 return 1;
100}
101
102/* Run the user supplied parser for an assignment */
bcde742e
LP
103static int next_assignment(
104 const char *unit,
105 const char *filename,
106 unsigned line,
107 ConfigItemLookup lookup,
108 const void *table,
109 const char *section,
110 unsigned section_line,
111 const char *lvalue,
112 const char *rvalue,
113 ConfigParseFlags flags,
114 void *userdata) {
f975e971
LP
115
116 ConfigParserCallback func = NULL;
117 int ltype = 0;
118 void *data = NULL;
119 int r;
120
121 assert(filename);
122 assert(line > 0);
123 assert(lookup);
124 assert(lvalue);
125 assert(rvalue);
126
127 r = lookup(table, section, lvalue, &func, &ltype, &data, userdata);
128 if (r < 0)
129 return r;
d937fbbd
LP
130 if (r > 0) {
131 if (func)
71a61510
TG
132 return func(unit, filename, line, section, section_line,
133 lvalue, ltype, rvalue, data, userdata);
d937fbbd
LP
134
135 return 0;
136 }
f975e971 137
46205bb6 138 /* Warn about unknown non-extension fields. */
bcde742e 139 if (!(flags & CONFIG_PARSE_RELAXED) && !startswith(lvalue, "X-"))
71b21730 140 log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown lvalue '%s' in section '%s', ignoring", lvalue, section);
46205bb6 141
f1857be0 142 return 0;
ed5bcfbe
LP
143}
144
8a37ce65 145/* Parse a single logical line */
bcde742e
LP
146static int parse_line(
147 const char* unit,
148 const char *filename,
149 unsigned line,
150 const char *sections,
151 ConfigItemLookup lookup,
152 const void *table,
153 ConfigParseFlags flags,
154 char **section,
155 unsigned *section_line,
156 bool *section_ignored,
157 char *l,
158 void *userdata) {
f975e971 159
bdc8e623 160 char *e, *include;
ed5bcfbe 161
f975e971
LP
162 assert(filename);
163 assert(line > 0);
164 assert(lookup);
165 assert(l);
166
b2aa81ef 167 l = strstrip(l);
b2aa81ef 168 if (!*l)
ed5bcfbe 169 return 0;
1ea86b18 170
9adbfeb3 171 if (*l == '\n')
1ea86b18 172 return 0;
ed5bcfbe 173
bdc8e623
LP
174 include = first_word(l, ".include");
175 if (include) {
db5c0122
LP
176 _cleanup_free_ char *fn = NULL;
177
b8e7a47b
LP
178 /* .includes are a bad idea, we only support them here
179 * for historical reasons. They create cyclic include
180 * problems and make it difficult to detect
181 * configuration file changes with an easy
182 * stat(). Better approaches, such as .d/ drop-in
183 * snippets exist.
184 *
185 * Support for them should be eventually removed. */
186
bcde742e 187 if (!(flags & CONFIG_PARSE_ALLOW_INCLUDE)) {
12ca818f 188 log_syntax(unit, LOG_ERR, filename, line, 0, ".include not allowed here. Ignoring.");
db5c0122
LP
189 return 0;
190 }
ed5bcfbe 191
41b283d0
LP
192 log_syntax(unit, LOG_WARNING, filename, line, 0,
193 ".include directives are deprecated, and support for them will be removed in a future version of systemd. "
194 "Please use drop-in files instead.");
195
bdc8e623 196 fn = file_in_same_dir(filename, strstrip(include));
f975e971 197 if (!fn)
b2aa81ef 198 return -ENOMEM;
ed5bcfbe 199
bcde742e 200 return config_parse(unit, fn, NULL, sections, lookup, table, flags, userdata);
ed5bcfbe
LP
201 }
202
78d17fa0
YW
203 if (!utf8_is_valid(l))
204 return log_syntax_invalid_utf8(unit, LOG_WARNING, filename, line, l);
205
b2aa81ef 206 if (*l == '[') {
ed5bcfbe
LP
207 size_t k;
208 char *n;
209
b2aa81ef 210 k = strlen(l);
ed5bcfbe
LP
211 assert(k > 0);
212
b2aa81ef 213 if (l[k-1] != ']') {
12ca818f 214 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid section header '%s'", l);
ed5bcfbe
LP
215 return -EBADMSG;
216 }
217
f975e971
LP
218 n = strndup(l+1, k-2);
219 if (!n)
ed5bcfbe
LP
220 return -ENOMEM;
221
f975e971 222 if (sections && !nulstr_contains(sections, n)) {
42f4e3c4 223
bcde742e 224 if (!(flags & CONFIG_PARSE_RELAXED) && !startswith(n, "X-"))
12ca818f 225 log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown section '%s'. Ignoring.", n);
f975e971
LP
226
227 free(n);
a1e58e8e 228 *section = mfree(*section);
71a61510 229 *section_line = 0;
342aea19 230 *section_ignored = true;
f975e971 231 } else {
97b9c506 232 free_and_replace(*section, n);
71a61510 233 *section_line = line;
342aea19 234 *section_ignored = false;
f975e971 235 }
ed5bcfbe
LP
236
237 return 0;
238 }
239
62f168a0
LP
240 if (sections && !*section) {
241
bcde742e 242 if (!(flags & CONFIG_PARSE_RELAXED) && !*section_ignored)
12ca818f 243 log_syntax(unit, LOG_WARNING, filename, line, 0, "Assignment outside of section. Ignoring.");
62f168a0 244
10e87ee7 245 return 0;
62f168a0 246 }
10e87ee7 247
f975e971
LP
248 e = strchr(l, '=');
249 if (!e) {
12ca818f
LP
250 log_syntax(unit, LOG_WARNING, filename, line, 0, "Missing '='.");
251 return -EINVAL;
ed5bcfbe
LP
252 }
253
254 *e = 0;
255 e++;
256
e8e581bf
ZJS
257 return next_assignment(unit,
258 filename,
259 line,
260 lookup,
261 table,
262 *section,
71a61510 263 *section_line,
e8e581bf
ZJS
264 strstrip(l),
265 strstrip(e),
bcde742e 266 flags,
e8e581bf 267 userdata);
ed5bcfbe
LP
268}
269
270/* Go through the file and parse each line */
e8e581bf
ZJS
271int config_parse(const char *unit,
272 const char *filename,
273 FILE *f,
274 const char *sections,
275 ConfigItemLookup lookup,
e9f3d2d5 276 const void *table,
bcde742e 277 ConfigParseFlags flags,
e8e581bf 278 void *userdata) {
f975e971 279
7fd1b19b
HH
280 _cleanup_free_ char *section = NULL, *continuation = NULL;
281 _cleanup_fclose_ FILE *ours = NULL;
71a61510 282 unsigned line = 0, section_line = 0;
bcde742e 283 bool section_ignored = false;
ed5bcfbe
LP
284 int r;
285
286 assert(filename);
f975e971 287 assert(lookup);
ed5bcfbe 288
87f0e418 289 if (!f) {
245802dd 290 f = ours = fopen(filename, "re");
f975e971 291 if (!f) {
36f822c4
ZJS
292 /* Only log on request, except for ENOENT,
293 * since we return 0 to the caller. */
bcde742e 294 if ((flags & CONFIG_PARSE_WARN) || errno == ENOENT)
b8b846d7
LP
295 log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_ERR, errno,
296 "Failed to open configuration file '%s': %m", filename);
9f43a07f 297 return errno == ENOENT ? 0 : -errno;
87f0e418 298 }
ed5bcfbe
LP
299 }
300
fdb9161c
LP
301 fd_warn_permissions(filename, fileno(f));
302
9dd7ea9a 303 for (;;) {
e6dde451 304 _cleanup_free_ char *buf = NULL;
3dab2943 305 bool escaped = false;
92b5e605 306 char *l, *p, *e;
ed5bcfbe 307
e6dde451
LP
308 r = read_line(f, LONG_LINE_MAX, &buf);
309 if (r == 0)
310 break;
311 if (r == -ENOBUFS) {
bcde742e 312 if (flags & CONFIG_PARSE_WARN)
e6dde451
LP
313 log_error_errno(r, "%s:%u: Line too long", filename, line);
314
315 return r;
316 }
317 if (r < 0) {
bcde742e 318 if (CONFIG_PARSE_WARN)
e6dde451 319 log_error_errno(r, "%s:%u: Error while reading configuration file: %m", filename, line);
ed5bcfbe 320
e6dde451 321 return r;
ed5bcfbe
LP
322 }
323
b41dd0d2 324 if (strchr(COMMENTS, *skip_leading_chars(buf, WHITESPACE)))
9adbfeb3
YW
325 continue;
326
9dd7ea9a 327 l = buf;
bcde742e 328 if (!(flags & CONFIG_PARSE_REFUSE_BOM)) {
e6dde451 329 char *q;
9dd7ea9a 330
e6dde451
LP
331 q = startswith(buf, UTF8_BYTE_ORDER_MARK);
332 if (q) {
333 l = q;
bcde742e 334 flags |= CONFIG_PARSE_REFUSE_BOM;
e6dde451
LP
335 }
336 }
3dab2943
LP
337
338 if (continuation) {
e6dde451 339 if (strlen(continuation) + strlen(l) > LONG_LINE_MAX) {
bcde742e 340 if (flags & CONFIG_PARSE_WARN)
e6dde451
LP
341 log_error("%s:%u: Continuation line too long", filename, line);
342 return -ENOBUFS;
343 }
344
92b5e605 345 if (!strextend(&continuation, l, NULL)) {
bcde742e 346 if (flags & CONFIG_PARSE_WARN)
36f822c4 347 log_oom();
245802dd 348 return -ENOMEM;
36f822c4 349 }
3dab2943 350
92b5e605 351 p = continuation;
3dab2943
LP
352 } else
353 p = l;
354
355 for (e = p; *e; e++) {
356 if (escaped)
357 escaped = false;
358 else if (*e == '\\')
359 escaped = true;
360 }
361
362 if (escaped) {
363 *(e-1) = ' ';
364
92b5e605 365 if (!continuation) {
f975e971 366 continuation = strdup(l);
36f822c4 367 if (!continuation) {
bcde742e 368 if (flags & CONFIG_PARSE_WARN)
36f822c4 369 log_oom();
245802dd 370 return -ENOMEM;
36f822c4 371 }
3dab2943
LP
372 }
373
374 continue;
375 }
376
e8e581bf
ZJS
377 r = parse_line(unit,
378 filename,
379 ++line,
380 sections,
381 lookup,
382 table,
bcde742e 383 flags,
e8e581bf 384 &section,
71a61510 385 &section_line,
342aea19 386 &section_ignored,
e8e581bf
ZJS
387 p,
388 userdata);
36f822c4 389 if (r < 0) {
bcde742e 390 if (flags & CONFIG_PARSE_WARN)
e6dde451 391 log_warning_errno(r, "%s:%u: Failed to parse file: %m", filename, line);
245802dd 392 return r;
36f822c4 393 }
92b5e605
LP
394
395 continuation = mfree(continuation);
ed5bcfbe
LP
396 }
397
4f29e0db
FB
398 if (continuation) {
399 r = parse_line(unit,
400 filename,
401 ++line,
402 sections,
403 lookup,
404 table,
405 flags,
406 &section,
407 &section_line,
408 &section_ignored,
409 continuation,
410 userdata);
411 if (r < 0) {
412 if (flags & CONFIG_PARSE_WARN)
413 log_warning_errno(r, "%s:%u: Failed to parse file: %m", filename, line);
414 return r;
4f29e0db
FB
415 }
416 }
417
245802dd 418 return 0;
ed5bcfbe
LP
419}
420
23bb31aa 421static int config_parse_many_files(
43688c49 422 const char *conf_file,
23bb31aa 423 char **files,
43688c49
ZJS
424 const char *sections,
425 ConfigItemLookup lookup,
426 const void *table,
bcde742e 427 ConfigParseFlags flags,
43688c49
ZJS
428 void *userdata) {
429
e8461023
JT
430 char **fn;
431 int r;
432
e8461023 433 if (conf_file) {
bcde742e 434 r = config_parse(NULL, conf_file, NULL, sections, lookup, table, flags, userdata);
e8461023
JT
435 if (r < 0)
436 return r;
437 }
438
439 STRV_FOREACH(fn, files) {
bcde742e 440 r = config_parse(NULL, *fn, NULL, sections, lookup, table, flags, userdata);
e8461023
JT
441 if (r < 0)
442 return r;
443 }
444
445 return 0;
446}
447
23bb31aa
ZJS
448/* Parse each config file in the directories specified as nulstr. */
449int config_parse_many_nulstr(
450 const char *conf_file,
451 const char *conf_file_dirs,
452 const char *sections,
453 ConfigItemLookup lookup,
454 const void *table,
bcde742e 455 ConfigParseFlags flags,
23bb31aa
ZJS
456 void *userdata) {
457
458 _cleanup_strv_free_ char **files = NULL;
459 int r;
460
b5084605 461 r = conf_files_list_nulstr(&files, ".conf", NULL, 0, conf_file_dirs);
23bb31aa
ZJS
462 if (r < 0)
463 return r;
464
bcde742e 465 return config_parse_many_files(conf_file, files, sections, lookup, table, flags, userdata);
23bb31aa
ZJS
466}
467
468/* Parse each config file in the directories specified as strv. */
469int config_parse_many(
470 const char *conf_file,
471 const char* const* conf_file_dirs,
472 const char *dropin_dirname,
473 const char *sections,
474 ConfigItemLookup lookup,
475 const void *table,
bcde742e 476 ConfigParseFlags flags,
23bb31aa
ZJS
477 void *userdata) {
478
479 _cleanup_strv_free_ char **dropin_dirs = NULL;
480 _cleanup_strv_free_ char **files = NULL;
481 const char *suffix;
482 int r;
483
484 suffix = strjoina("/", dropin_dirname);
485 r = strv_extend_strv_concat(&dropin_dirs, (char**) conf_file_dirs, suffix);
486 if (r < 0)
487 return r;
488
b5084605 489 r = conf_files_list_strv(&files, ".conf", NULL, 0, (const char* const*) dropin_dirs);
23bb31aa
ZJS
490 if (r < 0)
491 return r;
492
bcde742e 493 return config_parse_many_files(conf_file, files, sections, lookup, table, flags, userdata);
23bb31aa
ZJS
494}
495
eb3491d9 496#define DEFINE_PARSER(type, vartype, conv_func) \
2d1729ca 497 DEFINE_CONFIG_PARSE_PTR(config_parse_##type, conv_func, vartype, "Failed to parse " #type " value")
94d75d64
LP
498
499DEFINE_PARSER(int, int, safe_atoi);
500DEFINE_PARSER(long, long, safe_atoli);
134e24e1 501DEFINE_PARSER(uint8, uint8_t, safe_atou8);
c7440e74 502DEFINE_PARSER(uint16, uint16_t, safe_atou16);
94d75d64
LP
503DEFINE_PARSER(uint32, uint32_t, safe_atou32);
504DEFINE_PARSER(uint64, uint64_t, safe_atou64);
505DEFINE_PARSER(unsigned, unsigned, safe_atou);
506DEFINE_PARSER(double, double, safe_atod);
507DEFINE_PARSER(nsec, nsec_t, parse_nsec);
508DEFINE_PARSER(sec, usec_t, parse_sec);
7b61ce3c 509DEFINE_PARSER(sec_def_infinity, usec_t, parse_sec_def_infinity);
94d75d64 510DEFINE_PARSER(mode, mode_t, parse_mode);
ed5bcfbe 511
5556b5fe 512int config_parse_iec_size(const char* unit,
e8e581bf
ZJS
513 const char *filename,
514 unsigned line,
515 const char *section,
71a61510 516 unsigned section_line,
e8e581bf
ZJS
517 const char *lvalue,
518 int ltype,
519 const char *rvalue,
520 void *data,
521 void *userdata) {
ed5bcfbe
LP
522
523 size_t *sz = data;
59f448cf 524 uint64_t v;
e8e581bf 525 int r;
ed5bcfbe
LP
526
527 assert(filename);
528 assert(lvalue);
529 assert(rvalue);
530 assert(data);
531
59f448cf 532 r = parse_size(rvalue, 1024, &v);
1e5f4e8b
YW
533 if (r >= 0 && (uint64_t) (size_t) v != v)
534 r = -ERANGE;
535 if (r < 0) {
536 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value '%s', ignoring: %m", rvalue);
9ba1a159
LP
537 return 0;
538 }
539
59f448cf 540 *sz = (size_t) v;
9ba1a159
LP
541 return 0;
542}
543
78f3c4bc
LP
544int config_parse_si_size(
545 const char* unit,
546 const char *filename,
547 unsigned line,
548 const char *section,
549 unsigned section_line,
550 const char *lvalue,
551 int ltype,
552 const char *rvalue,
553 void *data,
554 void *userdata) {
5556b5fe
LP
555
556 size_t *sz = data;
59f448cf 557 uint64_t v;
5556b5fe
LP
558 int r;
559
560 assert(filename);
561 assert(lvalue);
562 assert(rvalue);
563 assert(data);
564
59f448cf 565 r = parse_size(rvalue, 1000, &v);
1e5f4e8b
YW
566 if (r >= 0 && (uint64_t) (size_t) v != v)
567 r = -ERANGE;
568 if (r < 0) {
569 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value '%s', ignoring: %m", rvalue);
5556b5fe
LP
570 return 0;
571 }
572
59f448cf 573 *sz = (size_t) v;
5556b5fe
LP
574 return 0;
575}
9ba1a159 576
78f3c4bc
LP
577int config_parse_iec_uint64(
578 const char* unit,
579 const char *filename,
580 unsigned line,
581 const char *section,
582 unsigned section_line,
583 const char *lvalue,
584 int ltype,
585 const char *rvalue,
586 void *data,
587 void *userdata) {
9ba1a159 588
59f448cf 589 uint64_t *bytes = data;
e8e581bf 590 int r;
9ba1a159
LP
591
592 assert(filename);
593 assert(lvalue);
594 assert(rvalue);
595 assert(data);
596
5556b5fe 597 r = parse_size(rvalue, 1024, bytes);
e8e581bf 598 if (r < 0)
59f448cf 599 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue);
ed5bcfbe 600
ed5bcfbe
LP
601 return 0;
602}
603
e8e581bf
ZJS
604int config_parse_bool(const char* unit,
605 const char *filename,
606 unsigned line,
607 const char *section,
71a61510 608 unsigned section_line,
e8e581bf
ZJS
609 const char *lvalue,
610 int ltype,
611 const char *rvalue,
612 void *data,
613 void *userdata) {
ed5bcfbe
LP
614
615 int k;
616 bool *b = data;
2c75fb73 617 bool fatal = ltype;
ed5bcfbe
LP
618
619 assert(filename);
620 assert(lvalue);
621 assert(rvalue);
622 assert(data);
623
e8e581bf
ZJS
624 k = parse_boolean(rvalue);
625 if (k < 0) {
2c75fb73
ZJS
626 log_syntax(unit, LOG_ERR, filename, line, k,
627 "Failed to parse boolean value%s: %s",
628 fatal ? "" : ", ignoring", rvalue);
629 return fatal ? -ENOEXEC : 0;
ed5bcfbe
LP
630 }
631
5d904a6a 632 *b = k;
ed5bcfbe
LP
633 return 0;
634}
635
f757855e
LP
636int config_parse_tristate(
637 const char* unit,
638 const char *filename,
639 unsigned line,
640 const char *section,
641 unsigned section_line,
642 const char *lvalue,
643 int ltype,
644 const char *rvalue,
645 void *data,
646 void *userdata) {
647
648 int k, *t = data;
649
650 assert(filename);
651 assert(lvalue);
652 assert(rvalue);
653 assert(data);
654
655 /* A tristate is pretty much a boolean, except that it can
656 * also take the special value -1, indicating "uninitialized",
657 * much like NULL is for a pointer type. */
658
659 k = parse_boolean(rvalue);
660 if (k < 0) {
661 log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse boolean value, ignoring: %s", rvalue);
662 return 0;
663 }
664
665 *t = !!k;
666 return 0;
667}
668
8f2665a4
LP
669int config_parse_string(
670 const char *unit,
671 const char *filename,
672 unsigned line,
673 const char *section,
674 unsigned section_line,
675 const char *lvalue,
676 int ltype,
677 const char *rvalue,
678 void *data,
679 void *userdata) {
680
5a4ff988 681 char **s = data;
ed5bcfbe
LP
682
683 assert(filename);
684 assert(lvalue);
685 assert(rvalue);
686 assert(data);
687
5a4ff988
LP
688 if (free_and_strdup(s, empty_to_null(rvalue)) < 0)
689 return log_oom();
8f2665a4 690
ed5bcfbe
LP
691 return 0;
692}
57d42a5f 693
8f2665a4
LP
694int config_parse_path(
695 const char *unit,
696 const char *filename,
697 unsigned line,
698 const char *section,
699 unsigned section_line,
700 const char *lvalue,
701 int ltype,
702 const char *rvalue,
703 void *data,
704 void *userdata) {
034c6ed7 705
c0d72c43 706 _cleanup_free_ char *n = NULL;
2c75fb73 707 bool fatal = ltype;
c0d72c43 708 char **s = data;
cd4f53c5 709 int r;
034c6ed7
LP
710
711 assert(filename);
712 assert(lvalue);
713 assert(rvalue);
714 assert(data);
715
8e7b5bd0 716 if (isempty(rvalue))
0fe50629 717 goto finalize;
0fe50629 718
7f110ff9
LP
719 n = strdup(rvalue);
720 if (!n)
74051b9b 721 return log_oom();
034c6ed7 722
cd4f53c5
YW
723 r = path_simplify_and_warn(n, PATH_CHECK_ABSOLUTE | (fatal ? PATH_CHECK_FATAL : 0), unit, filename, line, lvalue);
724 if (r < 0)
725 return fatal ? -ENOEXEC : 0;
01f78473 726
0fe50629 727finalize:
8e7b5bd0 728 return free_and_replace(*s, n);
034c6ed7 729}
57d42a5f 730
8249bb72
LP
731int config_parse_strv(
732 const char *unit,
733 const char *filename,
734 unsigned line,
735 const char *section,
736 unsigned section_line,
737 const char *lvalue,
738 int ltype,
739 const char *rvalue,
740 void *data,
741 void *userdata) {
57d42a5f 742
a2a5291b 743 char ***sv = data;
00d0fd06 744 int r;
57d42a5f
LP
745
746 assert(filename);
747 assert(lvalue);
748 assert(rvalue);
749 assert(data);
750
74051b9b 751 if (isempty(rvalue)) {
8249bb72 752 *sv = strv_free(*sv);
853b8397 753 return 0;
74051b9b
LP
754 }
755
34f253f0
DR
756 for (;;) {
757 char *word = NULL;
00d0fd06 758
9a82ab95 759 r = extract_first_word(&rvalue, &word, NULL, EXTRACT_QUOTES|EXTRACT_RETAIN_ESCAPE);
34f253f0
DR
760 if (r == 0)
761 break;
762 if (r == -ENOMEM)
853b8397 763 return log_oom();
34f253f0
DR
764 if (r < 0) {
765 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
766 break;
767 }
853b8397 768
34f253f0 769 r = strv_consume(sv, word);
853b8397
LP
770 if (r < 0)
771 return log_oom();
7f110ff9 772 }
57d42a5f 773
57d42a5f 774 return 0;
57d42a5f 775}
15ae422b 776
1e35c5ab
RP
777int config_parse_warn_compat(
778 const char *unit,
779 const char *filename,
780 unsigned line,
781 const char *section,
782 unsigned section_line,
783 const char *lvalue,
784 int ltype,
785 const char *rvalue,
786 void *data,
787 void *userdata) {
7ef7e15b 788
1e35c5ab
RP
789 Disabled reason = ltype;
790
791 switch(reason) {
7ef7e15b 792
1e35c5ab
RP
793 case DISABLED_CONFIGURATION:
794 log_syntax(unit, LOG_DEBUG, filename, line, 0,
795 "Support for option %s= has been disabled at compile time and it is ignored", lvalue);
796 break;
7ef7e15b 797
1e35c5ab
RP
798 case DISABLED_LEGACY:
799 log_syntax(unit, LOG_INFO, filename, line, 0,
800 "Support for option %s= has been removed and it is ignored", lvalue);
801 break;
7ef7e15b 802
1e35c5ab
RP
803 case DISABLED_EXPERIMENTAL:
804 log_syntax(unit, LOG_INFO, filename, line, 0,
805 "Support for option %s= has not yet been enabled and it is ignored", lvalue);
806 break;
7ef7e15b 807 }
1e35c5ab
RP
808
809 return 0;
810}
811
ca37242e
LP
812int config_parse_log_facility(
813 const char *unit,
814 const char *filename,
815 unsigned line,
816 const char *section,
817 unsigned section_line,
818 const char *lvalue,
819 int ltype,
820 const char *rvalue,
821 void *data,
822 void *userdata) {
213ba152 823
213ba152
LP
824 int *o = data, x;
825
826 assert(filename);
827 assert(lvalue);
828 assert(rvalue);
829 assert(data);
830
831 x = log_facility_unshifted_from_string(rvalue);
832 if (x < 0) {
12ca818f 833 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse log facility, ignoring: %s", rvalue);
213ba152
LP
834 return 0;
835 }
836
837 *o = (x << 3) | LOG_PRI(*o);
838
839 return 0;
840}
841
ca37242e
LP
842int config_parse_log_level(
843 const char *unit,
844 const char *filename,
845 unsigned line,
846 const char *section,
847 unsigned section_line,
848 const char *lvalue,
849 int ltype,
850 const char *rvalue,
851 void *data,
852 void *userdata) {
213ba152 853
213ba152
LP
854 int *o = data, x;
855
856 assert(filename);
857 assert(lvalue);
858 assert(rvalue);
859 assert(data);
860
861 x = log_level_from_string(rvalue);
862 if (x < 0) {
12ca818f 863 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse log level, ignoring: %s", rvalue);
213ba152
LP
864 return 0;
865 }
866
d3070fbd
LP
867 if (*o < 0) /* if it wasn't initialized so far, assume zero facility */
868 *o = x;
869 else
870 *o = (*o & LOG_FACMASK) | x;
871
213ba152
LP
872 return 0;
873}
f757855e
LP
874
875int config_parse_signal(
876 const char *unit,
877 const char *filename,
878 unsigned line,
879 const char *section,
880 unsigned section_line,
881 const char *lvalue,
882 int ltype,
883 const char *rvalue,
884 void *data,
885 void *userdata) {
886
887 int *sig = data, r;
888
889 assert(filename);
890 assert(lvalue);
891 assert(rvalue);
892 assert(sig);
893
29a3db75 894 r = signal_from_string(rvalue);
f757855e 895 if (r <= 0) {
12ca818f 896 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse signal name, ignoring: %s", rvalue);
f757855e
LP
897 return 0;
898 }
899
900 *sig = r;
901 return 0;
902}
903
904int config_parse_personality(
905 const char *unit,
906 const char *filename,
907 unsigned line,
908 const char *section,
909 unsigned section_line,
910 const char *lvalue,
911 int ltype,
912 const char *rvalue,
913 void *data,
914 void *userdata) {
915
916 unsigned long *personality = data, p;
917
918 assert(filename);
919 assert(lvalue);
920 assert(rvalue);
921 assert(personality);
922
40fdd636
LP
923 if (isempty(rvalue))
924 p = PERSONALITY_INVALID;
925 else {
926 p = personality_from_string(rvalue);
927 if (p == PERSONALITY_INVALID) {
928 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse personality, ignoring: %s", rvalue);
929 return 0;
930 }
f757855e
LP
931 }
932
933 *personality = p;
934 return 0;
935}
d31645ad
LP
936
937int config_parse_ifname(
938 const char *unit,
939 const char *filename,
940 unsigned line,
941 const char *section,
942 unsigned section_line,
943 const char *lvalue,
944 int ltype,
945 const char *rvalue,
946 void *data,
947 void *userdata) {
948
949 char **s = data;
950 int r;
951
952 assert(filename);
953 assert(lvalue);
954 assert(rvalue);
955 assert(data);
956
957 if (isempty(rvalue)) {
958 *s = mfree(*s);
959 return 0;
960 }
961
962 if (!ifname_valid(rvalue)) {
963 log_syntax(unit, LOG_ERR, filename, line, 0, "Interface name is not valid or too long, ignoring assignment: %s", rvalue);
964 return 0;
965 }
966
967 r = free_and_strdup(s, rvalue);
968 if (r < 0)
969 return log_oom();
970
971 return 0;
972}
177d0b20
SS
973
974int config_parse_ip_port(
975 const char *unit,
976 const char *filename,
977 unsigned line,
978 const char *section,
979 unsigned section_line,
980 const char *lvalue,
981 int ltype,
982 const char *rvalue,
983 void *data,
984 void *userdata) {
985
986 uint16_t *s = data;
987 uint16_t port;
988 int r;
989
990 assert(filename);
991 assert(lvalue);
992 assert(rvalue);
993 assert(data);
994
995 if (isempty(rvalue)) {
996 *s = 0;
997 return 0;
998 }
999
1000 r = parse_ip_port(rvalue, &port);
1001 if (r < 0) {
1002 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse port '%s'.", rvalue);
1003 return 0;
1004 }
1005
1006 *s = port;
1007
1008 return 0;
1009}
9ecdba8c 1010
79138a38
LP
1011int config_parse_mtu(
1012 const char *unit,
1013 const char *filename,
1014 unsigned line,
1015 const char *section,
1016 unsigned section_line,
1017 const char *lvalue,
1018 int ltype,
1019 const char *rvalue,
1020 void *data,
1021 void *userdata) {
1022
1023 uint32_t *mtu = data;
1024 int r;
1025
1026 assert(rvalue);
1027 assert(mtu);
1028
1029 r = parse_mtu(ltype, rvalue, mtu);
1030 if (r == -ERANGE) {
1031 log_syntax(unit, LOG_ERR, filename, line, r,
1032 "Maximum transfer unit (MTU) value out of range. Permitted range is %" PRIu32 "…%" PRIu32 ", ignoring: %s",
1033 (uint32_t) (ltype == AF_INET6 ? IPV6_MIN_MTU : IPV4_MIN_MTU), (uint32_t) UINT32_MAX,
1034 rvalue);
1035 return 0;
1036 }
1037 if (r < 0) {
1038 log_syntax(unit, LOG_ERR, filename, line, r,
1039 "Failed to parse MTU value '%s', ignoring: %m", rvalue);
1040 return 0;
1041 }
1042
1043 return 0;
1044}
4f424df7
LP
1045
1046int config_parse_rlimit(
1047 const char *unit,
1048 const char *filename,
1049 unsigned line,
1050 const char *section,
1051 unsigned section_line,
1052 const char *lvalue,
1053 int ltype,
1054 const char *rvalue,
1055 void *data,
1056 void *userdata) {
1057
1058 struct rlimit **rl = data, d = {};
1059 int r;
1060
1061 assert(rvalue);
1062 assert(rl);
1063
1064 r = rlimit_parse(ltype, rvalue, &d);
1065 if (r == -EILSEQ) {
1066 log_syntax(unit, LOG_WARNING, filename, line, r, "Soft resource limit chosen higher than hard limit, ignoring: %s", rvalue);
1067 return 0;
1068 }
1069 if (r < 0) {
1070 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue);
1071 return 0;
1072 }
1073
1074 if (rl[ltype])
1075 *rl[ltype] = d;
1076 else {
1077 rl[ltype] = newdup(struct rlimit, &d, 1);
1078 if (!rl[ltype])
1079 return log_oom();
1080 }
1081
1082 return 0;
1083}
c07b23ca
MKB
1084
1085int config_parse_permille(const char* unit,
1086 const char *filename,
1087 unsigned line,
1088 const char *section,
1089 unsigned section_line,
1090 const char *lvalue,
1091 int ltype,
1092 const char *rvalue,
1093 void *data,
1094 void *userdata) {
1095
1096 unsigned *permille = data;
1097 int r;
1098
1099 assert(filename);
1100 assert(lvalue);
1101 assert(rvalue);
1102 assert(permille);
1103
1104 r = parse_permille(rvalue);
1105 if (r < 0) {
1106 log_syntax(unit, LOG_ERR, filename, line, r,
1107 "Failed to parse permille value, ignoring: %s", rvalue);
1108 return 0;
1109 }
1110
1111 *permille = (unsigned) r;
1112
1113 return 0;
1114}