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