]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/conf-parser.c
man/systemd-sysext: list ephemeral/ephemeral-import in the list of options
[thirdparty/systemd.git] / src / shared / conf-parser.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
a7334b09 2
47a71f98 3#include <linux/ipv6.h>
07630cea 4#include <stdio.h>
07630cea 5
1cf40697
DDM
6#include "sd-id128.h"
7
b5efdb8a 8#include "alloc-util.h"
0e10c3d8 9#include "calendarspec.h"
1cf40697 10#include "chase.h"
e8461023 11#include "conf-files.h"
6bedfcbb 12#include "conf-parser.h"
28db6fbf 13#include "constants.h"
fa787a13 14#include "dns-domain.h"
3f87eaa5 15#include "escape.h"
0ec2a7a1 16#include "ether-addr-util.h"
a8fbdf54 17#include "extract-word.h"
6bedfcbb 18#include "fd-util.h"
e6dde451 19#include "fileio.h"
f4f15635 20#include "fs-util.h"
9ac2f3c4 21#include "hash-funcs.h"
fa787a13 22#include "hostname-util.h"
aea3f594 23#include "id128-util.h"
8cde9f6c 24#include "in-addr-prefix-util.h"
f7a1e57e 25#include "ip-protocol-list.h"
16354eff 26#include "log.h"
f5947a5e 27#include "missing_network.h"
d8b4d14d 28#include "nulstr-util.h"
c3eaba2d 29#include "parse-helpers.h"
6bedfcbb 30#include "parse-util.h"
9eb977db 31#include "path-util.h"
ed5033fd 32#include "percent-util.h"
7b3e062c 33#include "process-util.h"
ef118d00 34#include "rlimit-util.h"
0ec2a7a1 35#include "set.h"
f757855e 36#include "signal-util.h"
69a283c5 37#include "siphash24.h"
d31645ad 38#include "socket-util.h"
bdb2d3c6 39#include "stat-util.h"
07630cea
LP
40#include "string-util.h"
41#include "strv.h"
7b3e062c 42#include "syslog-util.h"
a8fbdf54 43#include "time-util.h"
07630cea 44#include "utf8.h"
e8e581bf 45
9ac2f3c4
MY
46DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(config_file_hash_ops_fclose,
47 char, path_hash_func, path_compare,
48 FILE, safe_fclose);
49
f975e971 50int config_item_table_lookup(
e9f3d2d5 51 const void *table,
ed5bcfbe 52 const char *section,
ed5bcfbe 53 const char *lvalue,
0b954099
LP
54 ConfigParserCallback *ret_func,
55 int *ret_ltype,
56 void **ret_data,
ed5bcfbe
LP
57 void *userdata) {
58
f975e971 59 assert(table);
ed5bcfbe 60 assert(lvalue);
0b954099
LP
61 assert(ret_func);
62 assert(ret_ltype);
63 assert(ret_data);
ed5bcfbe 64
62c9beaa 65 for (const ConfigTableItem *t = table; t->lvalue; t++) {
ed5bcfbe 66
f975e971 67 if (!streq(lvalue, t->lvalue))
ed5bcfbe
LP
68 continue;
69
f975e971 70 if (!streq_ptr(section, t->section))
ed5bcfbe
LP
71 continue;
72
0b954099
LP
73 *ret_func = t->parse;
74 *ret_ltype = t->ltype;
75 *ret_data = t->data;
f975e971
LP
76 return 1;
77 }
ed5bcfbe 78
0b954099
LP
79 *ret_func = NULL;
80 *ret_ltype = 0;
81 *ret_data = NULL;
f975e971
LP
82 return 0;
83}
10e87ee7 84
f975e971 85int config_item_perf_lookup(
e9f3d2d5 86 const void *table,
f975e971
LP
87 const char *section,
88 const char *lvalue,
0b954099
LP
89 ConfigParserCallback *ret_func,
90 int *ret_ltype,
91 void **ret_data,
f975e971
LP
92 void *userdata) {
93
94 ConfigPerfItemLookup lookup = (ConfigPerfItemLookup) table;
95 const ConfigPerfItem *p;
96
97 assert(table);
98 assert(lvalue);
0b954099
LP
99 assert(ret_func);
100 assert(ret_ltype);
101 assert(ret_data);
f975e971 102
4472fa6d
LP
103 if (section) {
104 const char *key;
f975e971 105
4472fa6d 106 key = strjoina(section, ".", lvalue);
f975e971 107 p = lookup(key, strlen(key));
4472fa6d
LP
108 } else
109 p = lookup(lvalue, strlen(lvalue));
0b954099
LP
110 if (!p) {
111 *ret_func = NULL;
112 *ret_ltype = 0;
113 *ret_data = NULL;
f975e971 114 return 0;
0b954099 115 }
f975e971 116
0b954099
LP
117 *ret_func = p->parse;
118 *ret_ltype = p->ltype;
119 *ret_data = (uint8_t*) userdata + p->offset;
f975e971
LP
120 return 1;
121}
122
123/* Run the user supplied parser for an assignment */
bcde742e
LP
124static int next_assignment(
125 const char *unit,
126 const char *filename,
127 unsigned line,
128 ConfigItemLookup lookup,
129 const void *table,
130 const char *section,
131 unsigned section_line,
132 const char *lvalue,
133 const char *rvalue,
134 ConfigParseFlags flags,
135 void *userdata) {
f975e971
LP
136
137 ConfigParserCallback func = NULL;
138 int ltype = 0;
139 void *data = NULL;
140 int r;
141
142 assert(filename);
143 assert(line > 0);
144 assert(lookup);
145 assert(lvalue);
146 assert(rvalue);
147
148 r = lookup(table, section, lvalue, &func, &ltype, &data, userdata);
149 if (r < 0)
150 return r;
d937fbbd 151 if (r > 0) {
0b954099
LP
152 if (!func)
153 return 0;
d937fbbd 154
0b954099
LP
155 return func(unit, filename, line, section, section_line,
156 lvalue, ltype, rvalue, data, userdata);
d937fbbd 157 }
f975e971 158
46205bb6 159 /* Warn about unknown non-extension fields. */
bcde742e 160 if (!(flags & CONFIG_PARSE_RELAXED) && !startswith(lvalue, "X-"))
28f30f40 161 log_syntax(unit, LOG_WARNING, filename, line, 0,
600a7405
ZJS
162 "Unknown key '%s'%s%s%s, ignoring.",
163 lvalue,
164 section ? " in section [" : "",
165 strempty(section),
166 section ? "]" : "");
46205bb6 167
f1857be0 168 return 0;
ed5bcfbe
LP
169}
170
8a37ce65 171/* Parse a single logical line */
bcde742e 172static int parse_line(
152f3493 173 const char *unit,
bcde742e
LP
174 const char *filename,
175 unsigned line,
176 const char *sections,
177 ConfigItemLookup lookup,
178 const void *table,
179 ConfigParseFlags flags,
180 char **section,
181 unsigned *section_line,
182 bool *section_ignored,
73a4ac8a 183 char *l, /* is modified */
bcde742e 184 void *userdata) {
f975e971 185
7ade8982 186 char *e;
ed5bcfbe 187
f975e971
LP
188 assert(filename);
189 assert(line > 0);
190 assert(lookup);
191 assert(l);
192
b2aa81ef 193 l = strstrip(l);
73a4ac8a 194 if (isempty(l))
ed5bcfbe 195 return 0;
1ea86b18 196
73a4ac8a 197 if (l[0] == '\n')
1ea86b18 198 return 0;
ed5bcfbe 199
78d17fa0
YW
200 if (!utf8_is_valid(l))
201 return log_syntax_invalid_utf8(unit, LOG_WARNING, filename, line, l);
202
deec0b6d
LP
203 if (l[0] == '[') {
204 _cleanup_free_ char *n = NULL;
ed5bcfbe 205 size_t k;
ed5bcfbe 206
b2aa81ef 207 k = strlen(l);
ed5bcfbe
LP
208 assert(k > 0);
209
3de39a1a
YW
210 if (l[k-1] != ']')
211 return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EBADMSG), "Invalid section header '%s'", l);
ed5bcfbe 212
f975e971
LP
213 n = strndup(l+1, k-2);
214 if (!n)
7a602af0 215 return log_oom();
ed5bcfbe 216
cec7f09d
LP
217 if (!string_is_safe(n))
218 return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EBADMSG), "Bad characters in section header '%s'", l);
219
f975e971 220 if (sections && !nulstr_contains(sections, n)) {
73a4ac8a 221 bool ignore;
42f4e3c4 222
73a4ac8a 223 ignore = (flags & CONFIG_PARSE_RELAXED) || startswith(n, "X-");
ddeb3f5d
ZJS
224
225 if (!ignore)
226 NULSTR_FOREACH(t, sections)
73a4ac8a 227 if (streq_ptr(n, startswith(t, "-"))) { /* Ignore sections prefixed with "-" in valid section list */
ddeb3f5d
ZJS
228 ignore = true;
229 break;
230 }
231
232 if (!ignore)
12ca818f 233 log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown section '%s'. Ignoring.", n);
f975e971 234
a1e58e8e 235 *section = mfree(*section);
71a61510 236 *section_line = 0;
342aea19 237 *section_ignored = true;
f975e971 238 } else {
97b9c506 239 free_and_replace(*section, n);
71a61510 240 *section_line = line;
342aea19 241 *section_ignored = false;
f975e971 242 }
ed5bcfbe
LP
243
244 return 0;
245 }
246
62f168a0 247 if (sections && !*section) {
bcde742e 248 if (!(flags & CONFIG_PARSE_RELAXED) && !*section_ignored)
12ca818f 249 log_syntax(unit, LOG_WARNING, filename, line, 0, "Assignment outside of section. Ignoring.");
62f168a0 250
10e87ee7 251 return 0;
62f168a0 252 }
10e87ee7 253
f975e971 254 e = strchr(l, '=');
2d4fffb0
ZJS
255 if (!e)
256 return log_syntax(unit, LOG_WARNING, filename, line, 0,
257 "Missing '=', ignoring line.");
8be8ed8c
ZJS
258 if (e == l)
259 return log_syntax(unit, LOG_WARNING, filename, line, 0,
260 "Missing key name before '=', ignoring line.");
ed5bcfbe
LP
261
262 *e = 0;
263 e++;
264
e8e581bf
ZJS
265 return next_assignment(unit,
266 filename,
267 line,
268 lookup,
269 table,
270 *section,
71a61510 271 *section_line,
e8e581bf
ZJS
272 strstrip(l),
273 strstrip(e),
bcde742e 274 flags,
e8e581bf 275 userdata);
ed5bcfbe
LP
276}
277
278/* Go through the file and parse each line */
c2f781bc
YW
279int config_parse(
280 const char *unit,
281 const char *filename,
282 FILE *f,
283 const char *sections,
284 ConfigItemLookup lookup,
285 const void *table,
286 ConfigParseFlags flags,
287 void *userdata,
8524db50 288 struct stat *ret_stat) {
f975e971 289
7fd1b19b
HH
290 _cleanup_free_ char *section = NULL, *continuation = NULL;
291 _cleanup_fclose_ FILE *ours = NULL;
71a61510 292 unsigned line = 0, section_line = 0;
f9761a89 293 bool section_ignored = false, bom_seen = false;
8524db50 294 struct stat st;
14f594b9 295 int r, fd;
ed5bcfbe
LP
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. */
bcde742e 305 if ((flags & CONFIG_PARSE_WARN) || errno == ENOENT)
b8b846d7
LP
306 log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_ERR, errno,
307 "Failed to open configuration file '%s': %m", filename);
8524db50
YW
308
309 if (errno == ENOENT) {
310 if (ret_stat)
311 *ret_stat = (struct stat) {};
312
313 return 0;
314 }
315
316 return -errno;
87f0e418 317 }
ed5bcfbe
LP
318 }
319
14f594b9 320 fd = fileno(f);
4f9ff96a 321 if (fd >= 0) { /* stream might not have an fd, let's be careful hence */
4f9ff96a
LP
322
323 if (fstat(fd, &st) < 0)
324 return log_full_errno(FLAGS_SET(flags, CONFIG_PARSE_WARN) ? LOG_ERR : LOG_DEBUG, errno,
325 "Failed to fstat(%s): %m", filename);
326
327 (void) stat_warn_permissions(filename, &st);
9fd8d678 328 } else
8524db50 329 st = (struct stat) {};
fdb9161c 330
9dd7ea9a 331 for (;;) {
e6dde451 332 _cleanup_free_ char *buf = NULL;
3dab2943 333 bool escaped = false;
92b5e605 334 char *l, *p, *e;
ed5bcfbe 335
e6dde451
LP
336 r = read_line(f, LONG_LINE_MAX, &buf);
337 if (r == 0)
338 break;
339 if (r == -ENOBUFS) {
bcde742e 340 if (flags & CONFIG_PARSE_WARN)
e6dde451
LP
341 log_error_errno(r, "%s:%u: Line too long", filename, line);
342
343 return r;
344 }
345 if (r < 0) {
5aca2e67 346 if (FLAGS_SET(flags, CONFIG_PARSE_WARN))
e6dde451 347 log_error_errno(r, "%s:%u: Error while reading configuration file: %m", filename, line);
ed5bcfbe 348
e6dde451 349 return r;
ed5bcfbe
LP
350 }
351
68c1ac15
YW
352 line++;
353
0ef69585
YW
354 l = skip_leading_chars(buf, WHITESPACE);
355 if (*l != '\0' && strchr(COMMENTS, *l))
9adbfeb3
YW
356 continue;
357
9dd7ea9a 358 l = buf;
f9761a89 359 if (!bom_seen) {
e6dde451 360 char *q;
9dd7ea9a 361
e6dde451
LP
362 q = startswith(buf, UTF8_BYTE_ORDER_MARK);
363 if (q) {
364 l = q;
f9761a89 365 bom_seen = true;
e6dde451
LP
366 }
367 }
3dab2943
LP
368
369 if (continuation) {
e6dde451 370 if (strlen(continuation) + strlen(l) > LONG_LINE_MAX) {
bcde742e 371 if (flags & CONFIG_PARSE_WARN)
e6dde451
LP
372 log_error("%s:%u: Continuation line too long", filename, line);
373 return -ENOBUFS;
374 }
375
c2bc710b 376 if (!strextend(&continuation, l)) {
bcde742e 377 if (flags & CONFIG_PARSE_WARN)
36f822c4 378 log_oom();
245802dd 379 return -ENOMEM;
36f822c4 380 }
3dab2943 381
92b5e605 382 p = continuation;
3dab2943
LP
383 } else
384 p = l;
385
386 for (e = p; *e; e++) {
387 if (escaped)
388 escaped = false;
389 else if (*e == '\\')
390 escaped = true;
391 }
392
393 if (escaped) {
394 *(e-1) = ' ';
395
92b5e605 396 if (!continuation) {
f975e971 397 continuation = strdup(l);
36f822c4 398 if (!continuation) {
bcde742e 399 if (flags & CONFIG_PARSE_WARN)
36f822c4 400 log_oom();
245802dd 401 return -ENOMEM;
36f822c4 402 }
3dab2943
LP
403 }
404
405 continue;
406 }
407
e8e581bf
ZJS
408 r = parse_line(unit,
409 filename,
68c1ac15 410 line,
e8e581bf
ZJS
411 sections,
412 lookup,
413 table,
bcde742e 414 flags,
e8e581bf 415 &section,
71a61510 416 &section_line,
342aea19 417 &section_ignored,
e8e581bf
ZJS
418 p,
419 userdata);
36f822c4 420 if (r < 0) {
bcde742e 421 if (flags & CONFIG_PARSE_WARN)
e6dde451 422 log_warning_errno(r, "%s:%u: Failed to parse file: %m", filename, line);
245802dd 423 return r;
36f822c4 424 }
92b5e605
LP
425
426 continuation = mfree(continuation);
ed5bcfbe
LP
427 }
428
4f29e0db
FB
429 if (continuation) {
430 r = parse_line(unit,
431 filename,
432 ++line,
433 sections,
434 lookup,
435 table,
436 flags,
437 &section,
438 &section_line,
439 &section_ignored,
440 continuation,
441 userdata);
442 if (r < 0) {
443 if (flags & CONFIG_PARSE_WARN)
444 log_warning_errno(r, "%s:%u: Failed to parse file: %m", filename, line);
445 return r;
4f29e0db
FB
446 }
447 }
448
8524db50
YW
449 if (ret_stat)
450 *ret_stat = st;
4f9ff96a 451
8b8024f1 452 return 1;
ed5bcfbe
LP
453}
454
acfbd71c 455int hashmap_put_stats_by_path(Hashmap **stats_by_path, const char *path, const struct stat *st) {
8524db50
YW
456 _cleanup_free_ struct stat *st_copy = NULL;
457 _cleanup_free_ char *path_copy = NULL;
458 int r;
459
460 assert(stats_by_path);
461 assert(path);
462 assert(st);
463
8524db50
YW
464 st_copy = newdup(struct stat, st, 1);
465 if (!st_copy)
466 return -ENOMEM;
467
468 path_copy = strdup(path);
0fa25bd5 469 if (!path_copy)
8524db50
YW
470 return -ENOMEM;
471
a95ae2d3 472 r = hashmap_ensure_put(stats_by_path, &path_hash_ops_free_free, path_copy, st_copy);
8524db50
YW
473 if (r < 0)
474 return r;
475
476 assert(r > 0);
477 TAKE_PTR(path_copy);
478 TAKE_PTR(st_copy);
479 return 0;
480}
481
23bb31aa 482static int config_parse_many_files(
d8a91c6b 483 const char *root,
8b8024f1 484 const char* const* conf_files,
23bb31aa 485 char **files,
43688c49
ZJS
486 const char *sections,
487 ConfigItemLookup lookup,
488 const void *table,
bcde742e 489 ConfigParseFlags flags,
4f9ff96a 490 void *userdata,
8524db50 491 Hashmap **ret_stats_by_path) {
43688c49 492
8524db50 493 _cleanup_hashmap_free_ Hashmap *stats_by_path = NULL;
9ac2f3c4 494 _cleanup_ordered_hashmap_free_ OrderedHashmap *dropins = NULL;
93f1da45 495 _cleanup_set_free_ Set *inodes = NULL;
8524db50 496 struct stat st;
be8e4b1a 497 int r, level = FLAGS_SET(flags, CONFIG_PARSE_WARN) ? LOG_WARNING : LOG_DEBUG;
e8461023 498
8524db50
YW
499 if (ret_stats_by_path) {
500 stats_by_path = hashmap_new(&path_hash_ops_free_free);
501 if (!stats_by_path)
be8e4b1a 502 return log_oom_full(level);
8524db50
YW
503 }
504
93f1da45 505 STRV_FOREACH(fn, files) {
9ac2f3c4 506 _cleanup_fclose_ FILE *f = NULL;
d8a91c6b 507 _cleanup_free_ char *fname = NULL;
9ac2f3c4 508
d8a91c6b
ZJS
509 r = chase_and_fopen_unlocked(*fn, root, CHASE_AT_RESOLVE_IN_ROOT, "re", &fname, &f);
510 if (r == -ENOENT)
511 continue;
512 if (r < 0)
be8e4b1a 513 return log_full_errno(level, r, "Failed to open %s: %m", *fn);
9ac2f3c4 514
d8a91c6b 515 int fd = fileno(f);
9ac2f3c4
MY
516
517 r = ordered_hashmap_ensure_put(&dropins, &config_file_hash_ops_fclose, *fn, f);
518 if (r < 0) {
be8e4b1a
YW
519 assert(r == -ENOMEM);
520 return log_oom_full(level);
9ac2f3c4
MY
521 }
522 assert(r > 0);
523 TAKE_PTR(f);
524
525 /* Get inodes for all drop-ins. Later we'll verify if main config is a symlink to or is
526 * symlinked as one of them. If so, we skip reading main config file directly. */
93f1da45 527
d8a91c6b 528 _cleanup_free_ struct stat *st_dropin = new(struct stat, 1);
93f1da45 529 if (!st_dropin)
be8e4b1a 530 return log_oom_full(level);
93f1da45 531
9ac2f3c4 532 if (fstat(fd, st_dropin) < 0)
be8e4b1a 533 return log_full_errno(level, errno, "Failed to stat %s: %m", *fn);
93f1da45
MY
534
535 r = set_ensure_consume(&inodes, &inode_hash_ops, TAKE_PTR(st_dropin));
536 if (r < 0)
be8e4b1a 537 return log_oom_full(level);
93f1da45
MY
538 }
539
8b8024f1 540 /* First read the first found main config file. */
2034c8b8 541 STRV_FOREACH(fn, conf_files) {
9ac2f3c4
MY
542 _cleanup_fclose_ FILE *f = NULL;
543
d8a91c6b
ZJS
544 r = chase_and_fopen_unlocked(*fn, root, CHASE_AT_RESOLVE_IN_ROOT, "re", NULL, &f);
545 if (r == -ENOENT)
546 continue;
547 if (r < 0)
be8e4b1a 548 return log_full_errno(level, r, "Failed to open %s: %m", *fn);
9ac2f3c4 549
93f1da45 550 if (inodes) {
9ac2f3c4 551 if (fstat(fileno(f), &st) < 0)
be8e4b1a 552 return log_full_errno(level, errno, "Failed to stat %s: %m", *fn);
93f1da45
MY
553
554 if (set_contains(inodes, &st)) {
9ac2f3c4 555 log_debug("%s: symlink to/symlinked as drop-in, will be read later.", *fn);
0ca66adf 556 break;
93f1da45
MY
557 }
558 }
559
b7d62bdb 560 r = config_parse(/* unit= */ NULL, *fn, f, sections, lookup, table, flags, userdata, &st);
e8461023 561 if (r < 0)
be8e4b1a 562 return r; /* config_parse() logs internally. */
8ea288db 563 assert(r > 0);
8524db50 564
8ea288db
MY
565 if (ret_stats_by_path) {
566 r = hashmap_put_stats_by_path(&stats_by_path, *fn, &st);
567 if (r < 0)
be8e4b1a 568 return log_full_errno(level, r, "Failed to save stats of %s: %m", *fn);
8524db50 569 }
0ca66adf
MY
570
571 break;
e8461023
JT
572 }
573
8b8024f1 574 /* Then read all the drop-ins. */
9ac2f3c4
MY
575
576 const char *path_dropin;
577 FILE *f_dropin;
578 ORDERED_HASHMAP_FOREACH_KEY(f_dropin, path_dropin, dropins) {
b7d62bdb 579 r = config_parse(/* unit= */ NULL, path_dropin, f_dropin, sections, lookup, table, flags, userdata, &st);
e8461023 580 if (r < 0)
be8e4b1a 581 return r; /* config_parse() logs internally. */
8ea288db 582 assert(r > 0);
8524db50
YW
583
584 if (ret_stats_by_path) {
9ac2f3c4 585 r = hashmap_put_stats_by_path(&stats_by_path, path_dropin, &st);
8524db50 586 if (r < 0)
be8e4b1a 587 return log_full_errno(level, r, "Failed to save stats of %s: %m", path_dropin);
8524db50 588 }
e8461023
JT
589 }
590
8524db50
YW
591 if (ret_stats_by_path)
592 *ret_stats_by_path = TAKE_PTR(stats_by_path);
4f9ff96a 593
e8461023
JT
594 return 0;
595}
596
23bb31aa
ZJS
597/* Parse each config file in the directories specified as strv. */
598int config_parse_many(
8b8024f1 599 const char* const* conf_files,
23bb31aa
ZJS
600 const char* const* conf_file_dirs,
601 const char *dropin_dirname,
947f59ba 602 const char *root,
23bb31aa
ZJS
603 const char *sections,
604 ConfigItemLookup lookup,
605 const void *table,
bcde742e 606 ConfigParseFlags flags,
9f83091e 607 void *userdata,
ead3a3fc
RP
608 Hashmap **ret_stats_by_path,
609 char ***ret_dropin_files) {
23bb31aa 610
23bb31aa 611 _cleanup_strv_free_ char **files = NULL;
23bb31aa
ZJS
612 int r;
613
bdb2d3c6
YW
614 assert(conf_file_dirs);
615 assert(dropin_dirname);
bdb2d3c6
YW
616 assert(table);
617
35c0e344 618 r = conf_files_list_dropins(&files, dropin_dirname, root, conf_file_dirs);
bdb2d3c6 619 if (r < 0)
be8e4b1a
YW
620 return log_full_errno(FLAGS_SET(flags, CONFIG_PARSE_WARN) ? LOG_WARNING : LOG_DEBUG, r,
621 "Failed to list up drop-in configs in %s: %m", dropin_dirname);
bdb2d3c6 622
d8a91c6b 623 r = config_parse_many_files(root, conf_files, files, sections, lookup, table, flags, userdata, ret_stats_by_path);
ead3a3fc 624 if (r < 0)
be8e4b1a 625 return r; /* config_parse_many_files() logs internally. */
ead3a3fc
RP
626
627 if (ret_dropin_files)
628 *ret_dropin_files = TAKE_PTR(files);
629
630 return 0;
bdb2d3c6
YW
631}
632
e7e52ff9
ZJS
633int config_parse_standard_file_with_dropins_full(
634 const char *root,
635 const char *main_file, /* A path like "systemd/frobnicator.conf" */
636 const char *sections,
637 ConfigItemLookup lookup,
638 const void *table,
639 ConfigParseFlags flags,
640 void *userdata,
641 Hashmap **ret_stats_by_path,
642 char ***ret_dropin_files) {
643
644 const char* const *conf_paths = (const char* const*) CONF_PATHS_STRV("");
645 _cleanup_strv_free_ char **configs = NULL;
be8e4b1a 646 int r, level = FLAGS_SET(flags, CONFIG_PARSE_WARN) ? LOG_WARNING : LOG_DEBUG;
e7e52ff9
ZJS
647
648 /* Build the list of main config files */
649 r = strv_extend_strv_biconcat(&configs, root, conf_paths, main_file);
be8e4b1a
YW
650 if (r < 0)
651 return log_oom_full(level);
e7e52ff9
ZJS
652
653 _cleanup_free_ char *dropin_dirname = strjoin(main_file, ".d");
be8e4b1a
YW
654 if (!dropin_dirname)
655 return log_oom_full(level);
e7e52ff9
ZJS
656
657 return config_parse_many(
658 (const char* const*) configs,
659 conf_paths,
660 dropin_dirname,
661 root,
662 sections,
663 lookup,
664 table,
665 flags,
666 userdata,
667 ret_stats_by_path,
668 ret_dropin_files);
669}
670
3f4dfd9d 671static int dropins_get_stats_by_path(
bdb2d3c6
YW
672 const char* conf_file,
673 const char* const* conf_file_dirs,
3f4dfd9d 674 Hashmap **stats_by_path) {
bdb2d3c6
YW
675
676 _cleanup_strv_free_ char **files = NULL;
677 _cleanup_free_ char *dropin_dirname = NULL;
bdb2d3c6
YW
678 int r;
679
680 assert(conf_file);
681 assert(conf_file_dirs);
682 assert(stats_by_path);
683
bdb2d3c6 684 r = path_extract_filename(conf_file, &dropin_dirname);
23bb31aa
ZJS
685 if (r < 0)
686 return r;
bdb2d3c6
YW
687 if (r == O_DIRECTORY)
688 return -EINVAL;
689
690 if (!strextend(&dropin_dirname, ".d"))
691 return -ENOMEM;
23bb31aa 692
35c0e344 693 r = conf_files_list_dropins(&files, dropin_dirname, /* root = */ NULL, conf_file_dirs);
23bb31aa
ZJS
694 if (r < 0)
695 return r;
696
bdb2d3c6 697 STRV_FOREACH(fn, files) {
3f4dfd9d
YW
698 struct stat st;
699
bdb2d3c6
YW
700 if (stat(*fn, &st) < 0) {
701 if (errno == ENOENT)
702 continue;
703
704 return -errno;
705 }
706
3f4dfd9d 707 r = hashmap_put_stats_by_path(stats_by_path, *fn, &st);
bdb2d3c6
YW
708 if (r < 0)
709 return r;
710 }
711
712 return 0;
713}
714
715int config_get_stats_by_path(
716 const char *suffix,
717 const char *root,
718 unsigned flags,
719 const char* const* dirs,
3f4dfd9d 720 bool check_dropins,
bdb2d3c6
YW
721 Hashmap **ret) {
722
723 _cleanup_hashmap_free_ Hashmap *stats_by_path = NULL;
724 _cleanup_strv_free_ char **files = NULL;
725 int r;
726
727 assert(suffix);
728 assert(dirs);
729 assert(ret);
730
3f4dfd9d
YW
731 /* Unlike config_parse(), this does not support stream. */
732
bdb2d3c6
YW
733 r = conf_files_list_strv(&files, suffix, root, flags, dirs);
734 if (r < 0)
735 return r;
736
bdb2d3c6 737 STRV_FOREACH(f, files) {
3f4dfd9d
YW
738 struct stat st;
739
740 /* First read the main config file. */
741 if (stat(*f, &st) < 0) {
742 if (errno == ENOENT)
743 continue;
744
745 return -errno;
746 }
747
2ae79a31
LZ
748 /* Skipping an empty file. */
749 if (null_or_empty(&st))
750 continue;
751
3f4dfd9d
YW
752 r = hashmap_put_stats_by_path(&stats_by_path, *f, &st);
753 if (r < 0)
754 return r;
755
756 if (!check_dropins)
757 continue;
758
759 /* Then read all the drop-ins if requested. */
760 r = dropins_get_stats_by_path(*f, dirs, &stats_by_path);
bdb2d3c6
YW
761 if (r < 0)
762 return r;
763 }
764
765 *ret = TAKE_PTR(stats_by_path);
766 return 0;
767}
768
769bool stats_by_path_equal(Hashmap *a, Hashmap *b) {
770 struct stat *st_a, *st_b;
771 const char *path;
772
773 if (hashmap_size(a) != hashmap_size(b))
774 return false;
775
776 HASHMAP_FOREACH_KEY(st_a, path, a) {
777 st_b = hashmap_get(b, path);
778 if (!st_b)
779 return false;
780
781 if (!stat_inode_unmodified(st_a, st_b))
782 return false;
783 }
784
785 return true;
23bb31aa
ZJS
786}
787
152b8a4e
YW
788int config_section_parse(
789 const ConfigSectionParser *parsers,
790 size_t n_parsers,
791 const char *unit,
792 const char *filename,
793 unsigned line,
794 const char *section,
795 unsigned section_line,
796 const char *lvalue,
797 int ltype,
798 const char *rvalue,
799 void *userdata) {
800
801 assert(parsers);
802 assert(n_parsers > 0);
803 assert(ltype >= 0);
804 assert((size_t) ltype < n_parsers);
805 assert(userdata);
806
807 const ConfigSectionParser *e = parsers + ltype;
808 assert(e->parser);
809
810 /* This is used when a object is dynamically allocated per [SECTION] in a config parser, e.g.
811 * [Address] for systemd.network. Takes the allocated object as 'userdata', then it is passed to
812 * config parsers in the table. The 'data' field points to an element of the passed object, where
813 * its offset is given by the table. */
814
815 return e->parser(unit, filename, line, section, section_line, lvalue, e->ltype, rvalue,
816 (uint8_t*) userdata + e->offset, userdata);
817}
818
b46d1694 819void config_section_hash_func(const ConfigSection *c, struct siphash *state) {
307fe3cd 820 siphash24_compress_string(c->filename, state);
c01a5c05 821 siphash24_compress_typesafe(c->line, state);
307fe3cd
YW
822}
823
b46d1694 824int config_section_compare_func(const ConfigSection *x, const ConfigSection *y) {
307fe3cd
YW
825 int r;
826
827 r = strcmp(x->filename, y->filename);
828 if (r != 0)
829 return r;
830
831 return CMP(x->line, y->line);
832}
833
834DEFINE_HASH_OPS(config_section_hash_ops, ConfigSection, config_section_hash_func, config_section_compare_func);
835
08ca764d 836int config_section_new(const char *filename, unsigned line, ConfigSection **ret) {
307fe3cd
YW
837 ConfigSection *cs;
838
08ca764d
YW
839 assert(filename);
840 assert(line > 0);
841 assert(ret);
842
307fe3cd
YW
843 cs = malloc0(offsetof(ConfigSection, filename) + strlen(filename) + 1);
844 if (!cs)
845 return -ENOMEM;
846
847 strcpy(cs->filename, filename);
848 cs->line = line;
849
08ca764d 850 *ret = TAKE_PTR(cs);
307fe3cd
YW
851 return 0;
852}
853
dbef7bcf 854static int _hashmap_by_section_find_unused_line(
e63c6e9f 855 HashmapBase *entries_by_section,
d9171a23
YW
856 const char *filename,
857 unsigned *ret) {
858
307fe3cd
YW
859 ConfigSection *cs;
860 unsigned n = 0;
861 void *entry;
862
e63c6e9f 863 HASHMAP_BASE_FOREACH_KEY(entry, cs, entries_by_section) {
d9171a23
YW
864 if (filename && !streq(cs->filename, filename))
865 continue;
866 n = MAX(n, cs->line);
867 }
868
869 /* overflow? */
870 if (n >= UINT_MAX)
871 return -EFBIG;
307fe3cd 872
d9171a23
YW
873 *ret = n + 1;
874 return 0;
307fe3cd
YW
875}
876
69a283c5
DDM
877int hashmap_by_section_find_unused_line(
878 Hashmap *entries_by_section,
879 const char *filename,
880 unsigned *ret) {
881
882 return _hashmap_by_section_find_unused_line(HASHMAP_BASE(entries_by_section), filename, ret);
883}
884
885int ordered_hashmap_by_section_find_unused_line(
886 OrderedHashmap *entries_by_section,
887 const char *filename,
888 unsigned *ret) {
889
890 return _hashmap_by_section_find_unused_line(HASHMAP_BASE(entries_by_section), filename, ret);
891}
892
eb3491d9 893#define DEFINE_PARSER(type, vartype, conv_func) \
42efe5be 894 DEFINE_CONFIG_PARSE_PTR(config_parse_##type, conv_func, vartype)
94d75d64
LP
895
896DEFINE_PARSER(int, int, safe_atoi);
897DEFINE_PARSER(long, long, safe_atoli);
134e24e1 898DEFINE_PARSER(uint8, uint8_t, safe_atou8);
c7440e74 899DEFINE_PARSER(uint16, uint16_t, safe_atou16);
94d75d64 900DEFINE_PARSER(uint32, uint32_t, safe_atou32);
b57ebc60 901DEFINE_PARSER(int32, int32_t, safe_atoi32);
94d75d64
LP
902DEFINE_PARSER(uint64, uint64_t, safe_atou64);
903DEFINE_PARSER(unsigned, unsigned, safe_atou);
904DEFINE_PARSER(double, double, safe_atod);
905DEFINE_PARSER(nsec, nsec_t, parse_nsec);
906DEFINE_PARSER(sec, usec_t, parse_sec);
7b61ce3c 907DEFINE_PARSER(sec_def_infinity, usec_t, parse_sec_def_infinity);
94d75d64 908DEFINE_PARSER(mode, mode_t, parse_mode);
65a0ede2 909DEFINE_PARSER(pid, pid_t, parse_pid);
ed5bcfbe 910
c2f781bc 911int config_parse_iec_size(
152f3493 912 const char *unit,
c2f781bc
YW
913 const char *filename,
914 unsigned line,
915 const char *section,
916 unsigned section_line,
917 const char *lvalue,
918 int ltype,
919 const char *rvalue,
920 void *data,
921 void *userdata) {
ed5bcfbe 922
99534007 923 size_t *sz = ASSERT_PTR(data);
59f448cf 924 uint64_t v;
e8e581bf 925 int r;
ed5bcfbe
LP
926
927 assert(filename);
928 assert(lvalue);
929 assert(rvalue);
ed5bcfbe 930
59f448cf 931 r = parse_size(rvalue, 1024, &v);
1e5f4e8b
YW
932 if (r >= 0 && (uint64_t) (size_t) v != v)
933 r = -ERANGE;
6f12cb91
YW
934 if (r < 0)
935 return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
9ba1a159 936
59f448cf 937 *sz = (size_t) v;
6f12cb91 938 return 1;
9ba1a159
LP
939}
940
50299121 941int config_parse_si_uint64(
152f3493 942 const char *unit,
78f3c4bc
LP
943 const char *filename,
944 unsigned line,
945 const char *section,
946 unsigned section_line,
947 const char *lvalue,
948 int ltype,
949 const char *rvalue,
950 void *data,
951 void *userdata) {
5556b5fe 952
99534007 953 uint64_t *sz = ASSERT_PTR(data);
5556b5fe
LP
954 int r;
955
956 assert(filename);
957 assert(lvalue);
958 assert(rvalue);
5556b5fe 959
50299121 960 r = parse_size(rvalue, 1000, sz);
d96edb2c 961 if (r < 0)
6f12cb91 962 return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
5556b5fe 963
6f12cb91 964 return 1;
5556b5fe 965}
9ba1a159 966
78f3c4bc 967int config_parse_iec_uint64(
152f3493 968 const char *unit,
78f3c4bc
LP
969 const char *filename,
970 unsigned line,
971 const char *section,
972 unsigned section_line,
973 const char *lvalue,
974 int ltype,
975 const char *rvalue,
976 void *data,
977 void *userdata) {
9ba1a159 978
99534007 979 uint64_t *bytes = ASSERT_PTR(data);
e8e581bf 980 int r;
9ba1a159
LP
981
982 assert(filename);
983 assert(lvalue);
984 assert(rvalue);
9ba1a159 985
5556b5fe 986 r = parse_size(rvalue, 1024, bytes);
e8e581bf 987 if (r < 0)
6f12cb91 988 return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
ed5bcfbe 989
6f12cb91 990 return 1;
ed5bcfbe
LP
991}
992
6e8791a0 993int config_parse_iec_uint64_infinity(
152f3493 994 const char *unit,
6e8791a0
TB
995 const char *filename,
996 unsigned line,
997 const char *section,
998 unsigned section_line,
999 const char *lvalue,
1000 int ltype,
1001 const char *rvalue,
1002 void *data,
1003 void *userdata) {
1004
99534007 1005 uint64_t *bytes = ASSERT_PTR(data);
6e8791a0
TB
1006
1007 assert(rvalue);
6e8791a0
TB
1008
1009 if (streq(rvalue, "infinity")) {
1010 *bytes = UINT64_MAX;
6f12cb91 1011 return 1;
6e8791a0
TB
1012 }
1013
1014 return config_parse_iec_uint64(unit, filename, line, section, section_line, lvalue, ltype, rvalue, data, userdata);
1015}
1016
c2f781bc 1017int config_parse_bool(
152f3493 1018 const char *unit,
c2f781bc
YW
1019 const char *filename,
1020 unsigned line,
1021 const char *section,
1022 unsigned section_line,
1023 const char *lvalue,
1024 int ltype,
1025 const char *rvalue,
1026 void *data,
1027 void *userdata) {
ed5bcfbe 1028
99534007 1029 bool *b = ASSERT_PTR(data);
2c75fb73 1030 bool fatal = ltype;
6f12cb91 1031 int r;
ed5bcfbe
LP
1032
1033 assert(filename);
1034 assert(lvalue);
1035 assert(rvalue);
ed5bcfbe 1036
6f12cb91
YW
1037 r = parse_boolean(rvalue);
1038 if (r < 0) {
1039 log_syntax_parse_error_full(unit, filename, line, r, fatal, lvalue, rvalue);
2c75fb73 1040 return fatal ? -ENOEXEC : 0;
ed5bcfbe
LP
1041 }
1042
6f12cb91 1043 *b = r;
f4810fe2 1044 return 1; /* set */
ed5bcfbe
LP
1045}
1046
6db311fd
YW
1047int config_parse_uint32_flag(
1048 const char *unit,
1049 const char *filename,
1050 unsigned line,
1051 const char *section,
1052 unsigned section_line,
1053 const char *lvalue,
1054 int ltype,
1055 const char *rvalue,
1056 void *data,
1057 void *userdata) {
1058
1059 uint32_t *flags = ASSERT_PTR(data);
1060 int r;
1061
1062 assert(ltype != 0);
1063
1064 r = isempty(rvalue) ? 0 : parse_boolean(rvalue);
6f12cb91
YW
1065 if (r < 0)
1066 return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
6db311fd
YW
1067
1068 SET_FLAG(*flags, ltype, r);
1069 return 1;
1070}
1071
ff616da4
YW
1072int config_parse_uint32_invert_flag(
1073 const char *unit,
1074 const char *filename,
1075 unsigned line,
1076 const char *section,
1077 unsigned section_line,
1078 const char *lvalue,
1079 int ltype,
1080 const char *rvalue,
1081 void *data,
1082 void *userdata) {
1083
1084 uint32_t *flags = ASSERT_PTR(data);
1085 int r;
1086
1087 assert(ltype != 0);
1088
1089 r = isempty(rvalue) ? 0 : parse_boolean(rvalue);
1090 if (r < 0)
1091 return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
1092
1093 SET_FLAG(*flags, ltype, !r);
1094 return 1;
1095}
1096
12963533
TH
1097int config_parse_id128(
1098 const char *unit,
1099 const char *filename,
1100 unsigned line,
1101 const char *section,
1102 unsigned section_line,
1103 const char *lvalue,
1104 int ltype,
1105 const char *rvalue,
1106 void *data,
1107 void *userdata) {
1108
aea3f594 1109 sd_id128_t *result = data;
12963533
TH
1110 int r;
1111
1112 assert(filename);
1113 assert(lvalue);
1114 assert(rvalue);
1115
aea3f594 1116 r = id128_from_string_nonzero(rvalue, result);
6f12cb91 1117 if (r == -ENXIO) {
aea3f594 1118 log_syntax(unit, LOG_WARNING, filename, line, r, "128-bit ID/UUID is all 0, ignoring: %s", rvalue);
6f12cb91
YW
1119 return 0;
1120 }
1121 if (r < 0)
1122 return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
12963533 1123
6f12cb91 1124 return 1;
12963533
TH
1125}
1126
f757855e 1127int config_parse_tristate(
152f3493 1128 const char *unit,
f757855e
LP
1129 const char *filename,
1130 unsigned line,
1131 const char *section,
1132 unsigned section_line,
1133 const char *lvalue,
1134 int ltype,
1135 const char *rvalue,
1136 void *data,
1137 void *userdata) {
1138
b71a721f 1139 int r, *t = ASSERT_PTR(data);
f757855e
LP
1140
1141 assert(filename);
1142 assert(lvalue);
1143 assert(rvalue);
f757855e 1144
33f2de7b
YW
1145 /* A tristate is pretty much a boolean, except that it can also take an empty string,
1146 * indicating "uninitialized", much like NULL is for a pointer type. */
1147
1148 if (isempty(rvalue)) {
1149 *t = -1;
4207f6c0 1150 return 1;
33f2de7b 1151 }
f757855e 1152
b71a721f 1153 r = parse_tristate(rvalue, t);
6f12cb91
YW
1154 if (r < 0)
1155 return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
f757855e 1156
4207f6c0 1157 return 1;
f757855e
LP
1158}
1159
8f2665a4
LP
1160int config_parse_string(
1161 const char *unit,
1162 const char *filename,
1163 unsigned line,
1164 const char *section,
1165 unsigned section_line,
1166 const char *lvalue,
1167 int ltype,
1168 const char *rvalue,
1169 void *data,
1170 void *userdata) {
1171
3f87eaa5 1172 char **s = ASSERT_PTR(data);
9aa3c079 1173 int r;
ed5bcfbe
LP
1174
1175 assert(filename);
1176 assert(lvalue);
1177 assert(rvalue);
ed5bcfbe 1178
3f87eaa5
YW
1179 if (isempty(rvalue)) {
1180 *s = mfree(*s);
9aa3c079 1181 return 1;
3f87eaa5 1182 }
2d17d699 1183
3f87eaa5
YW
1184 if (FLAGS_SET(ltype, CONFIG_PARSE_STRING_SAFE) && !string_is_safe(rvalue)) {
1185 _cleanup_free_ char *escaped = NULL;
2d17d699 1186
3f87eaa5
YW
1187 escaped = cescape(rvalue);
1188 log_syntax(unit, LOG_WARNING, filename, line, 0,
1189 "Specified string contains unsafe characters, ignoring: %s", strna(escaped));
2d17d699
LP
1190 return 0;
1191 }
1192
e289ce7f
YW
1193 if (FLAGS_SET(ltype, CONFIG_PARSE_STRING_ASCII) && !ascii_is_valid(rvalue)) {
1194 _cleanup_free_ char *escaped = NULL;
1195
1196 escaped = cescape(rvalue);
1197 log_syntax(unit, LOG_WARNING, filename, line, 0,
1198 "Specified string contains invalid ASCII characters, ignoring: %s", strna(escaped));
1199 return 0;
1200 }
1201
6f12cb91 1202 r = free_and_strdup_warn(s, rvalue);
9aa3c079
YW
1203 if (r < 0)
1204 return r;
1205
1206 return 1;
2d17d699
LP
1207}
1208
fa787a13
YW
1209int config_parse_dns_name(
1210 const char *unit,
1211 const char *filename,
1212 unsigned line,
1213 const char *section,
1214 unsigned section_line,
1215 const char *lvalue,
1216 int ltype,
1217 const char *rvalue,
1218 void *data,
1219 void *userdata) {
1220
1221 char **hostname = ASSERT_PTR(data);
1222 int r;
1223
1224 assert(filename);
1225 assert(lvalue);
1226 assert(rvalue);
1227
1228 if (isempty(rvalue)) {
1229 *hostname = mfree(*hostname);
6f12cb91 1230 return 1;
fa787a13
YW
1231 }
1232
1233 r = dns_name_is_valid(rvalue);
1234 if (r < 0) {
1235 log_syntax(unit, LOG_WARNING, filename, line, r,
1236 "Failed to check validity of DNS domain name '%s', ignoring assignment: %m", rvalue);
1237 return 0;
1238 }
1239 if (r == 0) {
1240 log_syntax(unit, LOG_WARNING, filename, line, 0,
1241 "Specified invalid DNS domain name, ignoring assignment: %s", rvalue);
1242 return 0;
1243 }
1244
6f12cb91
YW
1245 r = free_and_strdup_warn(hostname, rvalue);
1246 if (r < 0)
1247 return r;
1248
1249 return 1;
fa787a13
YW
1250}
1251
1252int config_parse_hostname(
1253 const char *unit,
1254 const char *filename,
1255 unsigned line,
1256 const char *section,
1257 unsigned section_line,
1258 const char *lvalue,
1259 int ltype,
1260 const char *rvalue,
1261 void *data,
1262 void *userdata) {
1263
1264 char **hostname = ASSERT_PTR(data);
1265
1266 assert(filename);
1267 assert(lvalue);
1268 assert(rvalue);
1269
1270 if (isempty(rvalue)) {
1271 *hostname = mfree(*hostname);
6f12cb91 1272 return 1;
fa787a13
YW
1273 }
1274
1275 if (!hostname_is_valid(rvalue, 0)) {
1276 log_syntax(unit, LOG_WARNING, filename, line, 0,
1277 "Specified invalid hostname, ignoring assignment: %s", rvalue);
1278 return 0;
1279 }
1280
1281 return config_parse_dns_name(unit, filename, line, section, section_line,
1282 lvalue, ltype, rvalue, data, userdata);
1283}
1284
8f2665a4
LP
1285int config_parse_path(
1286 const char *unit,
1287 const char *filename,
1288 unsigned line,
1289 const char *section,
1290 unsigned section_line,
1291 const char *lvalue,
1292 int ltype,
1293 const char *rvalue,
1294 void *data,
1295 void *userdata) {
034c6ed7 1296
c0d72c43 1297 _cleanup_free_ char *n = NULL;
2c75fb73 1298 bool fatal = ltype;
99534007 1299 char **s = ASSERT_PTR(data);
cd4f53c5 1300 int r;
034c6ed7
LP
1301
1302 assert(filename);
1303 assert(lvalue);
1304 assert(rvalue);
034c6ed7 1305
6f12cb91
YW
1306 if (isempty(rvalue)) {
1307 *s = mfree(*s);
1308 return 1;
1309 }
0fe50629 1310
7f110ff9
LP
1311 n = strdup(rvalue);
1312 if (!n)
74051b9b 1313 return log_oom();
034c6ed7 1314
cd4f53c5
YW
1315 r = path_simplify_and_warn(n, PATH_CHECK_ABSOLUTE | (fatal ? PATH_CHECK_FATAL : 0), unit, filename, line, lvalue);
1316 if (r < 0)
1317 return fatal ? -ENOEXEC : 0;
01f78473 1318
6f12cb91
YW
1319 free_and_replace(*s, n);
1320 return 1;
034c6ed7 1321}
57d42a5f 1322
8249bb72
LP
1323int config_parse_strv(
1324 const char *unit,
1325 const char *filename,
1326 unsigned line,
1327 const char *section,
1328 unsigned section_line,
1329 const char *lvalue,
c33aacdc 1330 int ltype, /* When true, duplicated entries will be filtered. */
8249bb72
LP
1331 const char *rvalue,
1332 void *data,
1333 void *userdata) {
57d42a5f 1334
99534007 1335 char ***sv = ASSERT_PTR(data);
00d0fd06 1336 int r;
57d42a5f
LP
1337
1338 assert(filename);
1339 assert(lvalue);
1340 assert(rvalue);
57d42a5f 1341
74051b9b 1342 if (isempty(rvalue)) {
8249bb72 1343 *sv = strv_free(*sv);
6f12cb91 1344 return 1;
74051b9b
LP
1345 }
1346
c33aacdc 1347 _cleanup_strv_free_ char **strv = NULL;
d96edb2c 1348 for (const char *p = rvalue;;) {
c33aacdc 1349 char *word;
00d0fd06 1350
d96edb2c 1351 r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
6f12cb91
YW
1352 if (r < 0)
1353 return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
34f253f0 1354 if (r == 0)
c33aacdc 1355 break;
853b8397 1356
c33aacdc 1357 r = strv_consume(&strv, word);
853b8397
LP
1358 if (r < 0)
1359 return log_oom();
7f110ff9 1360 }
c33aacdc 1361
a2c8652a 1362 r = strv_extend_strv_consume(sv, TAKE_PTR(strv), /* filter_duplicates = */ ltype);
c33aacdc
YW
1363 if (r < 0)
1364 return log_oom();
1365
6f12cb91 1366 return 1;
57d42a5f 1367}
15ae422b 1368
1e35c5ab
RP
1369int config_parse_warn_compat(
1370 const char *unit,
1371 const char *filename,
1372 unsigned line,
1373 const char *section,
1374 unsigned section_line,
1375 const char *lvalue,
1376 int ltype,
1377 const char *rvalue,
1378 void *data,
1379 void *userdata) {
7ef7e15b 1380
1e35c5ab
RP
1381 Disabled reason = ltype;
1382
79893116 1383 switch (reason) {
7ef7e15b 1384
1e35c5ab
RP
1385 case DISABLED_CONFIGURATION:
1386 log_syntax(unit, LOG_DEBUG, filename, line, 0,
1387 "Support for option %s= has been disabled at compile time and it is ignored", lvalue);
1388 break;
7ef7e15b 1389
1e35c5ab
RP
1390 case DISABLED_LEGACY:
1391 log_syntax(unit, LOG_INFO, filename, line, 0,
1392 "Support for option %s= has been removed and it is ignored", lvalue);
1393 break;
7ef7e15b 1394
1e35c5ab
RP
1395 case DISABLED_EXPERIMENTAL:
1396 log_syntax(unit, LOG_INFO, filename, line, 0,
1397 "Support for option %s= has not yet been enabled and it is ignored", lvalue);
1398 break;
7ef7e15b 1399 }
1e35c5ab
RP
1400
1401 return 0;
1402}
1403
ca37242e
LP
1404int config_parse_log_facility(
1405 const char *unit,
1406 const char *filename,
1407 unsigned line,
1408 const char *section,
1409 unsigned section_line,
1410 const char *lvalue,
1411 int ltype,
1412 const char *rvalue,
1413 void *data,
1414 void *userdata) {
213ba152 1415
213ba152
LP
1416 int *o = data, x;
1417
1418 assert(filename);
1419 assert(lvalue);
1420 assert(rvalue);
1421 assert(data);
1422
1423 x = log_facility_unshifted_from_string(rvalue);
6f12cb91
YW
1424 if (x < 0)
1425 return log_syntax_parse_error(unit, filename, line, x, lvalue, rvalue);
213ba152
LP
1426
1427 *o = (x << 3) | LOG_PRI(*o);
1428
6f12cb91 1429 return 1;
213ba152
LP
1430}
1431
ca37242e
LP
1432int config_parse_log_level(
1433 const char *unit,
1434 const char *filename,
1435 unsigned line,
1436 const char *section,
1437 unsigned section_line,
1438 const char *lvalue,
1439 int ltype,
1440 const char *rvalue,
1441 void *data,
1442 void *userdata) {
213ba152 1443
213ba152
LP
1444 int *o = data, x;
1445
1446 assert(filename);
1447 assert(lvalue);
1448 assert(rvalue);
1449 assert(data);
1450
1451 x = log_level_from_string(rvalue);
6f12cb91
YW
1452 if (x < 0)
1453 return log_syntax_parse_error(unit, filename, line, x, lvalue, rvalue);
213ba152 1454
d3070fbd
LP
1455 if (*o < 0) /* if it wasn't initialized so far, assume zero facility */
1456 *o = x;
1457 else
1458 *o = (*o & LOG_FACMASK) | x;
1459
6f12cb91 1460 return 1;
213ba152 1461}
f757855e
LP
1462
1463int config_parse_signal(
1464 const char *unit,
1465 const char *filename,
1466 unsigned line,
1467 const char *section,
1468 unsigned section_line,
1469 const char *lvalue,
1470 int ltype,
1471 const char *rvalue,
1472 void *data,
1473 void *userdata) {
1474
1475 int *sig = data, r;
1476
1477 assert(filename);
1478 assert(lvalue);
1479 assert(rvalue);
1480 assert(sig);
1481
29a3db75 1482 r = signal_from_string(rvalue);
6f12cb91
YW
1483 if (r <= 0)
1484 return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
f757855e
LP
1485
1486 *sig = r;
6f12cb91 1487 return 1;
f757855e
LP
1488}
1489
1490int config_parse_personality(
1491 const char *unit,
1492 const char *filename,
1493 unsigned line,
1494 const char *section,
1495 unsigned section_line,
1496 const char *lvalue,
1497 int ltype,
1498 const char *rvalue,
1499 void *data,
1500 void *userdata) {
1501
1502 unsigned long *personality = data, p;
1503
1504 assert(filename);
1505 assert(lvalue);
1506 assert(rvalue);
1507 assert(personality);
1508
6f12cb91
YW
1509 if (isempty(rvalue)) {
1510 *personality = PERSONALITY_INVALID;
1511 return 1;
f757855e
LP
1512 }
1513
6f12cb91
YW
1514 p = personality_from_string(rvalue);
1515 if (p == PERSONALITY_INVALID)
1516 return log_syntax_parse_error(unit, filename, line, 0, lvalue, rvalue);
1517
f757855e 1518 *personality = p;
6f12cb91 1519 return 1;
f757855e 1520}
d31645ad
LP
1521
1522int config_parse_ifname(
1523 const char *unit,
1524 const char *filename,
1525 unsigned line,
1526 const char *section,
1527 unsigned section_line,
1528 const char *lvalue,
1529 int ltype,
1530 const char *rvalue,
1531 void *data,
1532 void *userdata) {
1533
99534007 1534 char **s = ASSERT_PTR(data);
d31645ad
LP
1535 int r;
1536
1537 assert(filename);
1538 assert(lvalue);
1539 assert(rvalue);
d31645ad
LP
1540
1541 if (isempty(rvalue)) {
1542 *s = mfree(*s);
f4810fe2 1543 return 1;
d31645ad
LP
1544 }
1545
1546 if (!ifname_valid(rvalue)) {
d96edb2c 1547 log_syntax(unit, LOG_WARNING, filename, line, 0, "Interface name is not valid or too long, ignoring assignment: %s", rvalue);
d31645ad
LP
1548 return 0;
1549 }
1550
6f12cb91 1551 r = free_and_strdup_warn(s, rvalue);
d31645ad 1552 if (r < 0)
6f12cb91 1553 return r;
d31645ad 1554
f4810fe2 1555 return 1;
d31645ad 1556}
177d0b20 1557
a5053a15
YW
1558int config_parse_ifnames(
1559 const char *unit,
1560 const char *filename,
1561 unsigned line,
1562 const char *section,
1563 unsigned section_line,
1564 const char *lvalue,
1565 int ltype,
1566 const char *rvalue,
1567 void *data,
1568 void *userdata) {
1569
1570 _cleanup_strv_free_ char **names = NULL;
99534007 1571 char ***s = ASSERT_PTR(data);
a5053a15
YW
1572 int r;
1573
1574 assert(filename);
1575 assert(lvalue);
1576 assert(rvalue);
a5053a15
YW
1577
1578 if (isempty(rvalue)) {
1579 *s = strv_free(*s);
6f12cb91 1580 return 1;
a5053a15
YW
1581 }
1582
d96edb2c 1583 for (const char *p = rvalue;;) {
a5053a15
YW
1584 _cleanup_free_ char *word = NULL;
1585
1586 r = extract_first_word(&p, &word, NULL, 0);
6f12cb91
YW
1587 if (r < 0)
1588 return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
a5053a15
YW
1589 if (r == 0)
1590 break;
1591
1592 if (!ifname_valid_full(word, ltype)) {
d96edb2c 1593 log_syntax(unit, LOG_WARNING, filename, line, 0,
a5053a15
YW
1594 "Interface name is not valid or too long, ignoring assignment: %s",
1595 word);
1596 continue;
1597 }
1598
1599 r = strv_consume(&names, TAKE_PTR(word));
1600 if (r < 0)
1601 return log_oom();
1602 }
1603
1604 r = strv_extend_strv(s, names, true);
1605 if (r < 0)
1606 return log_oom();
1607
6f12cb91 1608 return 1;
a5053a15
YW
1609}
1610
177d0b20
SS
1611int config_parse_ip_port(
1612 const char *unit,
1613 const char *filename,
1614 unsigned line,
1615 const char *section,
1616 unsigned section_line,
1617 const char *lvalue,
1618 int ltype,
1619 const char *rvalue,
1620 void *data,
1621 void *userdata) {
1622
99534007 1623 uint16_t *s = ASSERT_PTR(data);
177d0b20
SS
1624 uint16_t port;
1625 int r;
1626
1627 assert(filename);
1628 assert(lvalue);
1629 assert(rvalue);
177d0b20
SS
1630
1631 if (isempty(rvalue)) {
1632 *s = 0;
6f12cb91 1633 return 1;
177d0b20
SS
1634 }
1635
1636 r = parse_ip_port(rvalue, &port);
6f12cb91
YW
1637 if (r < 0)
1638 return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
177d0b20
SS
1639
1640 *s = port;
6f12cb91 1641 return 1;
177d0b20 1642}
9ecdba8c 1643
79138a38
LP
1644int config_parse_mtu(
1645 const char *unit,
1646 const char *filename,
1647 unsigned line,
1648 const char *section,
1649 unsigned section_line,
1650 const char *lvalue,
1651 int ltype,
1652 const char *rvalue,
1653 void *data,
1654 void *userdata) {
1655
99534007 1656 uint32_t *mtu = ASSERT_PTR(data);
79138a38
LP
1657 int r;
1658
1659 assert(rvalue);
79138a38
LP
1660
1661 r = parse_mtu(ltype, rvalue, mtu);
1662 if (r == -ERANGE) {
d96edb2c 1663 log_syntax(unit, LOG_WARNING, filename, line, r,
79138a38
LP
1664 "Maximum transfer unit (MTU) value out of range. Permitted range is %" PRIu32 "…%" PRIu32 ", ignoring: %s",
1665 (uint32_t) (ltype == AF_INET6 ? IPV6_MIN_MTU : IPV4_MIN_MTU), (uint32_t) UINT32_MAX,
1666 rvalue);
1667 return 0;
1668 }
6f12cb91
YW
1669 if (r < 0)
1670 return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
79138a38 1671
18c4c5d8 1672 return 1;
79138a38 1673}
4f424df7
LP
1674
1675int config_parse_rlimit(
1676 const char *unit,
1677 const char *filename,
1678 unsigned line,
1679 const char *section,
1680 unsigned section_line,
1681 const char *lvalue,
1682 int ltype,
1683 const char *rvalue,
1684 void *data,
1685 void *userdata) {
1686
1687 struct rlimit **rl = data, d = {};
1688 int r;
1689
1690 assert(rvalue);
1691 assert(rl);
1692
1693 r = rlimit_parse(ltype, rvalue, &d);
1694 if (r == -EILSEQ) {
1695 log_syntax(unit, LOG_WARNING, filename, line, r, "Soft resource limit chosen higher than hard limit, ignoring: %s", rvalue);
1696 return 0;
1697 }
6f12cb91
YW
1698 if (r < 0)
1699 return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
4f424df7
LP
1700
1701 if (rl[ltype])
1702 *rl[ltype] = d;
1703 else {
1704 rl[ltype] = newdup(struct rlimit, &d, 1);
1705 if (!rl[ltype])
1706 return log_oom();
1707 }
1708
6f12cb91 1709 return 1;
4f424df7 1710}
c07b23ca 1711
c2f781bc 1712int config_parse_permille(
152f3493 1713 const char *unit,
c2f781bc
YW
1714 const char *filename,
1715 unsigned line,
1716 const char *section,
1717 unsigned section_line,
1718 const char *lvalue,
1719 int ltype,
1720 const char *rvalue,
1721 void *data,
1722 void *userdata) {
c07b23ca 1723
99534007 1724 unsigned *permille = ASSERT_PTR(data);
c07b23ca
MKB
1725 int r;
1726
1727 assert(filename);
1728 assert(lvalue);
1729 assert(rvalue);
c07b23ca
MKB
1730
1731 r = parse_permille(rvalue);
6f12cb91
YW
1732 if (r < 0)
1733 return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
c07b23ca
MKB
1734
1735 *permille = (unsigned) r;
6f12cb91 1736 return 1;
c07b23ca 1737}
4df4df5b 1738
c2f781bc 1739int config_parse_vlanprotocol(
152f3493 1740 const char *unit,
c2f781bc
YW
1741 const char *filename,
1742 unsigned line,
1743 const char *section,
1744 unsigned section_line,
1745 const char *lvalue,
1746 int ltype,
1747 const char *rvalue,
1748 void *data,
1749 void *userdata) {
1750
4df4df5b 1751 int *vlan_protocol = data;
c2f781bc 1752
4df4df5b
RF
1753 assert(filename);
1754 assert(lvalue);
1755
1756 if (isempty(rvalue)) {
1757 *vlan_protocol = -1;
6f12cb91 1758 return 1;
4df4df5b
RF
1759 }
1760
1761 if (STR_IN_SET(rvalue, "802.1ad", "802.1AD"))
1762 *vlan_protocol = ETH_P_8021AD;
1763 else if (STR_IN_SET(rvalue, "802.1q", "802.1Q"))
1764 *vlan_protocol = ETH_P_8021Q;
6f12cb91
YW
1765 else
1766 return log_syntax_parse_error(unit, filename, line, 0, lvalue, rvalue);
4df4df5b 1767
6f12cb91 1768 return 1;
4df4df5b 1769}
9de5e321 1770
99628f36
YW
1771int config_parse_hw_addr(
1772 const char *unit,
1773 const char *filename,
1774 unsigned line,
1775 const char *section,
1776 unsigned section_line,
1777 const char *lvalue,
1778 int ltype,
1779 const char *rvalue,
1780 void *data,
1781 void *userdata) {
1782
1775654e 1783 struct hw_addr_data *hwaddr = ASSERT_PTR(data);
99628f36
YW
1784 int r;
1785
1786 assert(filename);
1787 assert(lvalue);
1788 assert(rvalue);
99628f36
YW
1789
1790 if (isempty(rvalue)) {
1791 *hwaddr = HW_ADDR_NULL;
6f12cb91 1792 return 1;
99628f36
YW
1793 }
1794
1775654e 1795 r = parse_hw_addr_full(rvalue, ltype, hwaddr);
6f12cb91
YW
1796 if (r < 0)
1797 return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
99628f36 1798
6f12cb91 1799 return 1;
99628f36
YW
1800}
1801
1802int config_parse_hw_addrs(
1803 const char *unit,
1804 const char *filename,
1805 unsigned line,
1806 const char *section,
1807 unsigned section_line,
1808 const char *lvalue,
1809 int ltype,
1810 const char *rvalue,
1811 void *data,
1812 void *userdata) {
1813
99534007 1814 Set **hwaddrs = ASSERT_PTR(data);
99628f36
YW
1815 int r;
1816
1817 assert(filename);
1818 assert(lvalue);
1819 assert(rvalue);
99628f36
YW
1820
1821 if (isempty(rvalue)) {
1822 /* Empty assignment resets the list */
1823 *hwaddrs = set_free(*hwaddrs);
6f12cb91 1824 return 1;
99628f36
YW
1825 }
1826
1827 for (const char *p = rvalue;;) {
1828 _cleanup_free_ char *word = NULL;
1829 _cleanup_free_ struct hw_addr_data *n = NULL;
1830
1831 r = extract_first_word(&p, &word, NULL, 0);
6f12cb91
YW
1832 if (r < 0)
1833 return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
99628f36 1834 if (r == 0)
6f12cb91 1835 return 1;
99628f36
YW
1836
1837 n = new(struct hw_addr_data, 1);
1838 if (!n)
1839 return log_oom();
1840
1841 r = parse_hw_addr_full(word, ltype, n);
1842 if (r < 0) {
1843 log_syntax(unit, LOG_WARNING, filename, line, r,
1844 "Not a valid hardware address, ignoring: %s", word);
1845 continue;
1846 }
1847
1848 r = set_ensure_consume(hwaddrs, &hw_addr_hash_ops_free, TAKE_PTR(n));
1849 if (r < 0)
1850 return log_oom();
1851 }
1852}
1853
aa4f7653 1854int config_parse_ether_addr(
0ec2a7a1
YW
1855 const char *unit,
1856 const char *filename,
1857 unsigned line,
1858 const char *section,
1859 unsigned section_line,
1860 const char *lvalue,
1861 int ltype,
1862 const char *rvalue,
1863 void *data,
1864 void *userdata) {
1865
1866 _cleanup_free_ struct ether_addr *n = NULL;
99534007 1867 struct ether_addr **hwaddr = ASSERT_PTR(data);
0ec2a7a1
YW
1868 int r;
1869
1870 assert(filename);
1871 assert(lvalue);
1872 assert(rvalue);
0ec2a7a1
YW
1873
1874 if (isempty(rvalue)) {
1875 *hwaddr = mfree(*hwaddr);
6f12cb91 1876 return 1;
0ec2a7a1
YW
1877 }
1878
1879 n = new0(struct ether_addr, 1);
1880 if (!n)
1881 return log_oom();
1882
227e9ce2 1883 r = parse_ether_addr(rvalue, n);
6f12cb91
YW
1884 if (r < 0)
1885 return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
0ec2a7a1
YW
1886
1887 free_and_replace(*hwaddr, n);
6f12cb91 1888 return 1;
0ec2a7a1
YW
1889}
1890
aa4f7653 1891int config_parse_ether_addrs(
0ec2a7a1
YW
1892 const char *unit,
1893 const char *filename,
1894 unsigned line,
1895 const char *section,
1896 unsigned section_line,
1897 const char *lvalue,
1898 int ltype,
1899 const char *rvalue,
1900 void *data,
1901 void *userdata) {
1902
99534007 1903 Set **hwaddrs = ASSERT_PTR(data);
0ec2a7a1
YW
1904 int r;
1905
1906 assert(filename);
1907 assert(lvalue);
1908 assert(rvalue);
0ec2a7a1
YW
1909
1910 if (isempty(rvalue)) {
1911 /* Empty assignment resets the list */
c6df73ca 1912 *hwaddrs = set_free(*hwaddrs);
6f12cb91 1913 return 1;
0ec2a7a1
YW
1914 }
1915
1916 for (const char *p = rvalue;;) {
1917 _cleanup_free_ char *word = NULL;
1918 _cleanup_free_ struct ether_addr *n = NULL;
1919
1920 r = extract_first_word(&p, &word, NULL, 0);
6f12cb91
YW
1921 if (r < 0)
1922 return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
0ec2a7a1 1923 if (r == 0)
6f12cb91 1924 return 1;
0ec2a7a1
YW
1925
1926 n = new(struct ether_addr, 1);
1927 if (!n)
1928 return log_oom();
1929
227e9ce2 1930 r = parse_ether_addr(word, n);
0ec2a7a1
YW
1931 if (r < 0) {
1932 log_syntax(unit, LOG_WARNING, filename, line, r,
1933 "Not a valid MAC address, ignoring: %s", word);
1934 continue;
1935 }
1936
c6df73ca 1937 r = set_ensure_consume(hwaddrs, &ether_addr_hash_ops_free, TAKE_PTR(n));
0ec2a7a1
YW
1938 if (r < 0)
1939 return log_oom();
0ec2a7a1
YW
1940 }
1941}
1942
cf074772
YW
1943int config_parse_in_addr_non_null(
1944 const char *unit,
1945 const char *filename,
1946 unsigned line,
1947 const char *section,
1948 unsigned section_line,
1949 const char *lvalue,
1950 int ltype,
1951 const char *rvalue,
1952 void *data,
1953 void *userdata) {
1954
1955 /* data must be a pointer to struct in_addr or in6_addr, and the type is determined by ltype. */
99534007
DT
1956 struct in_addr *ipv4 = ASSERT_PTR(data);
1957 struct in6_addr *ipv6 = ASSERT_PTR(data);
cf074772
YW
1958 union in_addr_union a;
1959 int r;
1960
1961 assert(filename);
1962 assert(lvalue);
1963 assert(rvalue);
cf074772
YW
1964 assert(IN_SET(ltype, AF_INET, AF_INET6));
1965
1966 if (isempty(rvalue)) {
1967 if (ltype == AF_INET)
1968 *ipv4 = (struct in_addr) {};
1969 else
1970 *ipv6 = (struct in6_addr) {};
6f12cb91 1971 return 1;
cf074772
YW
1972 }
1973
1974 r = in_addr_from_string(ltype, rvalue, &a);
6f12cb91
YW
1975 if (r < 0)
1976 return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
cf074772
YW
1977
1978 if (!in_addr_is_set(ltype, &a)) {
1979 log_syntax(unit, LOG_WARNING, filename, line, 0,
1980 "%s= cannot be the ANY address, ignoring: %s", lvalue, rvalue);
1981 return 0;
1982 }
1983
1984 if (ltype == AF_INET)
1985 *ipv4 = a.in;
1986 else
1987 *ipv6 = a.in6;
6f12cb91 1988 return 1;
cf074772
YW
1989}
1990
0ea6d55a
YW
1991int config_parse_in_addr_data(
1992 const char *unit,
1993 const char *filename,
1994 unsigned line,
1995 const char *section,
1996 unsigned section_line,
1997 const char *lvalue,
1998 int ltype,
1999 const char *rvalue,
2000 void *data,
2001 void *userdata) {
2002
2003 struct in_addr_data *p = ASSERT_PTR(data);
2004 int r;
2005
2006 assert(filename);
2007 assert(lvalue);
2008
2009 if (isempty(rvalue)) {
2010 *p = (struct in_addr_data) {};
2011 return 1;
2012 }
2013
2014 r = in_addr_from_string_auto(rvalue, &p->family, &p->address);
2015 if (r < 0)
2016 return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
2017
2018 return 1;
2019}
2020
8cde9f6c
YW
2021int config_parse_in_addr_prefix(
2022 const char *unit,
2023 const char *filename,
2024 unsigned line,
2025 const char *section,
2026 unsigned section_line,
2027 const char *lvalue,
2028 int ltype, /* takes boolean, whether we warn about missing prefixlen */
2029 const char *rvalue,
2030 void *data,
2031 void *userdata) {
2032
2033 struct in_addr_prefix *p = ASSERT_PTR(data);
2034 int r;
2035
2036 assert(filename);
2037 assert(lvalue);
2038
2039 if (isempty(rvalue)) {
2040 *p = (struct in_addr_prefix) {};
2041 return 1;
2042 }
2043
2044 r = in_addr_prefix_from_string_auto_full(rvalue, ltype ? PREFIXLEN_REFUSE : PREFIXLEN_FULL, &p->family, &p->address, &p->prefixlen);
2045 if (r == -ENOANO) {
2046 r = in_addr_prefix_from_string_auto(rvalue, &p->family, &p->address, &p->prefixlen);
2047 if (r >= 0)
2048 log_syntax(unit, LOG_WARNING, filename, line, r,
2049 "%s=%s is specified without prefix length. Assuming the prefix length is %u. "
2050 "Please specify the prefix length explicitly.", lvalue, rvalue, p->prefixlen);
2051 }
2052 if (r < 0)
2053 return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
2054
2055 return 1;
2056}
2057
851cdffd
ZJS
2058int config_parse_unsigned_bounded(
2059 const char *unit,
2060 const char *filename,
2061 unsigned line,
2062 const char *section,
2063 unsigned section_line,
6f12cb91
YW
2064 const char *lvalue,
2065 const char *rvalue,
851cdffd
ZJS
2066 unsigned min,
2067 unsigned max,
2068 bool ignoring,
2069 unsigned *ret) {
2070
2071 int r;
2072
2073 assert(filename);
6f12cb91
YW
2074 assert(lvalue);
2075 assert(rvalue);
851cdffd
ZJS
2076 assert(ret);
2077
6f12cb91
YW
2078 r = safe_atou_bounded(rvalue, min, max, ret);
2079 if (r == -ERANGE) {
851cdffd
ZJS
2080 log_syntax(unit, LOG_WARNING, filename, line, r,
2081 "Invalid '%s=%s', allowed range is %u..%u%s.",
6f12cb91
YW
2082 lvalue, rvalue, min, max, ignoring ? ", ignoring" : "");
2083 return ignoring ? 0 : r;
2084 }
2085 if (r < 0)
2086 return log_syntax_parse_error_full(unit, filename, line, r, /* critical = */ !ignoring, lvalue, rvalue);
851cdffd 2087
6f12cb91 2088 return 1; /* Return 1 if something was set */
851cdffd
ZJS
2089}
2090
0e10c3d8
LN
2091int config_parse_calendar(
2092 const char *unit,
2093 const char *filename,
2094 unsigned line,
2095 const char *section,
2096 unsigned section_line,
2097 const char *lvalue,
2098 int ltype,
2099 const char *rvalue,
2100 void *data,
2101 void *userdata) {
2102
2103 CalendarSpec **cr = data;
2104 _cleanup_(calendar_spec_freep) CalendarSpec *c = NULL;
2105 int r;
2106
2107 assert(filename);
2108 assert(lvalue);
2109 assert(rvalue);
2110 assert(data);
2111
2112 if (isempty(rvalue)) {
2113 *cr = calendar_spec_free(*cr);
6f12cb91 2114 return 1;
0e10c3d8
LN
2115 }
2116
2117 r = calendar_spec_from_string(rvalue, &c);
6f12cb91
YW
2118 if (r < 0)
2119 return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
0e10c3d8 2120
8b4ef777 2121 free_and_replace_full(*cr, c, calendar_spec_free);
6f12cb91 2122 return 1;
0e10c3d8
LN
2123}
2124
42efe5be
YW
2125DEFINE_CONFIG_PARSE(config_parse_percent, parse_percent);
2126DEFINE_CONFIG_PARSE(config_parse_permyriad, parse_permyriad);
2127DEFINE_CONFIG_PARSE_PTR(config_parse_sec_fix_0, parse_sec_fix_0, usec_t);
f72e851f
YW
2128
2129int config_parse_timezone(
2130 const char *unit,
2131 const char *filename,
2132 unsigned line,
2133 const char *section,
2134 unsigned section_line,
2135 const char *lvalue,
2136 int ltype,
2137 const char *rvalue,
2138 void *data,
2139 void *userdata) {
2140
2141 char **tz = ASSERT_PTR(data);
2142 int r;
2143
2144 assert(filename);
2145 assert(lvalue);
2146 assert(rvalue);
2147
2148 if (isempty(rvalue)) {
2149 *tz = mfree(*tz);
6f12cb91 2150 return 1;
f72e851f
YW
2151 }
2152
2153 r = verify_timezone(rvalue, LOG_WARNING);
6f12cb91
YW
2154 if (r < 0)
2155 return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
2156
2157 r = free_and_strdup_warn(tz, rvalue);
2158 if (r < 0)
2159 return r;
f72e851f 2160
6f12cb91 2161 return 1;
f72e851f 2162}
f7a1e57e
YW
2163
2164int config_parse_ip_protocol(
2165 const char *unit,
2166 const char *filename,
2167 unsigned line,
2168 const char *section,
2169 unsigned section_line,
2170 const char *lvalue,
2171 int ltype,
2172 const char *rvalue,
2173 void *data,
2174 void *userdata) {
2175
2176 uint8_t *proto = ASSERT_PTR(data);
2177 int r;
2178
2179 r = isempty(rvalue) ? 0 : parse_ip_protocol_full(rvalue, /* relaxed= */ ltype);
6f12cb91
YW
2180 if (r < 0)
2181 return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
f7a1e57e
YW
2182
2183 if (r > UINT8_MAX) {
2184 /* linux/fib_rules.h and linux/fou.h define the netlink field as one byte, so we need to
2185 * reject protocols numbers that don't fit in one byte. */
2186 log_syntax(unit, LOG_WARNING, filename, line, r,
2187 "Invalid '%s=%s', allowed range is 0..255, ignoring.",
2188 lvalue, rvalue);
2189 return 0;
2190 }
2191
2192 *proto = r;
2193 return 1; /* done. */
2194}
015a3b8c
SEL
2195
2196int config_parse_loadavg(
2197 const char *unit,
2198 const char *filename,
2199 unsigned line,
2200 const char *section,
2201 unsigned section_line,
2202 const char *lvalue,
2203 int ltype,
2204 const char *rvalue,
2205 void *data,
2206 void *userdata) {
2207
2208 loadavg_t *i = ASSERT_PTR(data);
2209 int r;
2210
2211 assert(rvalue);
2212
2213 r = parse_permyriad(rvalue);
2214 if (r < 0)
2215 return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
2216
2217 r = store_loadavg_fixed_point(r / 100, r % 100, i);
2218 if (r < 0)
2219 return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
2220
2221 return 1; /* done. */
2222}