]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/conf-parser.c
tree-wide: use config_parse_safe_string() at various places
[thirdparty/systemd.git] / src / shared / conf-parser.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
a7334b09 2
ed5bcfbe 3#include <errno.h>
a8fbdf54
TA
4#include <limits.h>
5#include <stdint.h>
07630cea 6#include <stdio.h>
ed5bcfbe 7#include <stdlib.h>
a8fbdf54 8#include <sys/types.h>
07630cea 9
b5efdb8a 10#include "alloc-util.h"
e8461023 11#include "conf-files.h"
6bedfcbb 12#include "conf-parser.h"
e6dde451 13#include "def.h"
0ec2a7a1 14#include "ether-addr-util.h"
a8fbdf54 15#include "extract-word.h"
6bedfcbb 16#include "fd-util.h"
e6dde451 17#include "fileio.h"
f4f15635 18#include "fs-util.h"
cf074772 19#include "in-addr-util.h"
16354eff 20#include "log.h"
07630cea 21#include "macro.h"
f5947a5e 22#include "missing_network.h"
d8b4d14d 23#include "nulstr-util.h"
6bedfcbb 24#include "parse-util.h"
9eb977db 25#include "path-util.h"
ed5033fd 26#include "percent-util.h"
7b3e062c 27#include "process-util.h"
ef118d00 28#include "rlimit-util.h"
12963533 29#include "sd-id128.h"
0ec2a7a1 30#include "set.h"
f757855e 31#include "signal-util.h"
d31645ad 32#include "socket-util.h"
07630cea
LP
33#include "string-util.h"
34#include "strv.h"
7b3e062c 35#include "syslog-util.h"
a8fbdf54 36#include "time-util.h"
07630cea 37#include "utf8.h"
e8e581bf 38
f975e971 39int config_item_table_lookup(
e9f3d2d5 40 const void *table,
ed5bcfbe 41 const char *section,
ed5bcfbe 42 const char *lvalue,
0b954099
LP
43 ConfigParserCallback *ret_func,
44 int *ret_ltype,
45 void **ret_data,
ed5bcfbe
LP
46 void *userdata) {
47
e9f3d2d5 48 const ConfigTableItem *t;
f975e971
LP
49
50 assert(table);
ed5bcfbe 51 assert(lvalue);
0b954099
LP
52 assert(ret_func);
53 assert(ret_ltype);
54 assert(ret_data);
ed5bcfbe 55
f975e971 56 for (t = table; t->lvalue; t++) {
ed5bcfbe 57
f975e971 58 if (!streq(lvalue, t->lvalue))
ed5bcfbe
LP
59 continue;
60
f975e971 61 if (!streq_ptr(section, t->section))
ed5bcfbe
LP
62 continue;
63
0b954099
LP
64 *ret_func = t->parse;
65 *ret_ltype = t->ltype;
66 *ret_data = t->data;
f975e971
LP
67 return 1;
68 }
ed5bcfbe 69
0b954099
LP
70 *ret_func = NULL;
71 *ret_ltype = 0;
72 *ret_data = NULL;
f975e971
LP
73 return 0;
74}
10e87ee7 75
f975e971 76int config_item_perf_lookup(
e9f3d2d5 77 const void *table,
f975e971
LP
78 const char *section,
79 const char *lvalue,
0b954099
LP
80 ConfigParserCallback *ret_func,
81 int *ret_ltype,
82 void **ret_data,
f975e971
LP
83 void *userdata) {
84
85 ConfigPerfItemLookup lookup = (ConfigPerfItemLookup) table;
86 const ConfigPerfItem *p;
87
88 assert(table);
89 assert(lvalue);
0b954099
LP
90 assert(ret_func);
91 assert(ret_ltype);
92 assert(ret_data);
f975e971 93
4472fa6d
LP
94 if (section) {
95 const char *key;
f975e971 96
4472fa6d 97 key = strjoina(section, ".", lvalue);
f975e971 98 p = lookup(key, strlen(key));
4472fa6d
LP
99 } else
100 p = lookup(lvalue, strlen(lvalue));
0b954099
LP
101 if (!p) {
102 *ret_func = NULL;
103 *ret_ltype = 0;
104 *ret_data = NULL;
f975e971 105 return 0;
0b954099 106 }
f975e971 107
0b954099
LP
108 *ret_func = p->parse;
109 *ret_ltype = p->ltype;
110 *ret_data = (uint8_t*) userdata + p->offset;
f975e971
LP
111 return 1;
112}
113
114/* Run the user supplied parser for an assignment */
bcde742e
LP
115static int next_assignment(
116 const char *unit,
117 const char *filename,
118 unsigned line,
119 ConfigItemLookup lookup,
120 const void *table,
121 const char *section,
122 unsigned section_line,
123 const char *lvalue,
124 const char *rvalue,
125 ConfigParseFlags flags,
126 void *userdata) {
f975e971
LP
127
128 ConfigParserCallback func = NULL;
129 int ltype = 0;
130 void *data = NULL;
131 int r;
132
133 assert(filename);
134 assert(line > 0);
135 assert(lookup);
136 assert(lvalue);
137 assert(rvalue);
138
139 r = lookup(table, section, lvalue, &func, &ltype, &data, userdata);
140 if (r < 0)
141 return r;
d937fbbd 142 if (r > 0) {
0b954099
LP
143 if (!func)
144 return 0;
d937fbbd 145
0b954099
LP
146 return func(unit, filename, line, section, section_line,
147 lvalue, ltype, rvalue, data, userdata);
d937fbbd 148 }
f975e971 149
46205bb6 150 /* Warn about unknown non-extension fields. */
bcde742e 151 if (!(flags & CONFIG_PARSE_RELAXED) && !startswith(lvalue, "X-"))
28f30f40
ZJS
152 log_syntax(unit, LOG_WARNING, filename, line, 0,
153 "Unknown key name '%s' in section '%s', ignoring.", lvalue, section);
46205bb6 154
f1857be0 155 return 0;
ed5bcfbe
LP
156}
157
8a37ce65 158/* Parse a single logical line */
bcde742e
LP
159static int parse_line(
160 const char* unit,
161 const char *filename,
162 unsigned line,
163 const char *sections,
164 ConfigItemLookup lookup,
165 const void *table,
166 ConfigParseFlags flags,
167 char **section,
168 unsigned *section_line,
169 bool *section_ignored,
73a4ac8a 170 char *l, /* is modified */
bcde742e 171 void *userdata) {
f975e971 172
7ade8982 173 char *e;
ed5bcfbe 174
f975e971
LP
175 assert(filename);
176 assert(line > 0);
177 assert(lookup);
178 assert(l);
179
b2aa81ef 180 l = strstrip(l);
73a4ac8a 181 if (isempty(l))
ed5bcfbe 182 return 0;
1ea86b18 183
73a4ac8a 184 if (l[0] == '\n')
1ea86b18 185 return 0;
ed5bcfbe 186
78d17fa0
YW
187 if (!utf8_is_valid(l))
188 return log_syntax_invalid_utf8(unit, LOG_WARNING, filename, line, l);
189
deec0b6d
LP
190 if (l[0] == '[') {
191 _cleanup_free_ char *n = NULL;
ed5bcfbe 192 size_t k;
ed5bcfbe 193
b2aa81ef 194 k = strlen(l);
ed5bcfbe
LP
195 assert(k > 0);
196
3de39a1a
YW
197 if (l[k-1] != ']')
198 return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EBADMSG), "Invalid section header '%s'", l);
ed5bcfbe 199
f975e971
LP
200 n = strndup(l+1, k-2);
201 if (!n)
7a602af0 202 return log_oom();
ed5bcfbe 203
cec7f09d
LP
204 if (!string_is_safe(n))
205 return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EBADMSG), "Bad characters in section header '%s'", l);
206
f975e971 207 if (sections && !nulstr_contains(sections, n)) {
73a4ac8a 208 bool ignore;
ddeb3f5d 209 const char *t;
42f4e3c4 210
73a4ac8a 211 ignore = (flags & CONFIG_PARSE_RELAXED) || startswith(n, "X-");
ddeb3f5d
ZJS
212
213 if (!ignore)
214 NULSTR_FOREACH(t, sections)
73a4ac8a 215 if (streq_ptr(n, startswith(t, "-"))) { /* Ignore sections prefixed with "-" in valid section list */
ddeb3f5d
ZJS
216 ignore = true;
217 break;
218 }
219
220 if (!ignore)
12ca818f 221 log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown section '%s'. Ignoring.", n);
f975e971 222
a1e58e8e 223 *section = mfree(*section);
71a61510 224 *section_line = 0;
342aea19 225 *section_ignored = true;
f975e971 226 } else {
97b9c506 227 free_and_replace(*section, n);
71a61510 228 *section_line = line;
342aea19 229 *section_ignored = false;
f975e971 230 }
ed5bcfbe
LP
231
232 return 0;
233 }
234
62f168a0 235 if (sections && !*section) {
bcde742e 236 if (!(flags & CONFIG_PARSE_RELAXED) && !*section_ignored)
12ca818f 237 log_syntax(unit, LOG_WARNING, filename, line, 0, "Assignment outside of section. Ignoring.");
62f168a0 238
10e87ee7 239 return 0;
62f168a0 240 }
10e87ee7 241
f975e971 242 e = strchr(l, '=');
2d4fffb0
ZJS
243 if (!e)
244 return log_syntax(unit, LOG_WARNING, filename, line, 0,
245 "Missing '=', ignoring line.");
8be8ed8c
ZJS
246 if (e == l)
247 return log_syntax(unit, LOG_WARNING, filename, line, 0,
248 "Missing key name before '=', ignoring line.");
ed5bcfbe
LP
249
250 *e = 0;
251 e++;
252
e8e581bf
ZJS
253 return next_assignment(unit,
254 filename,
255 line,
256 lookup,
257 table,
258 *section,
71a61510 259 *section_line,
e8e581bf
ZJS
260 strstrip(l),
261 strstrip(e),
bcde742e 262 flags,
e8e581bf 263 userdata);
ed5bcfbe
LP
264}
265
266/* Go through the file and parse each line */
c2f781bc
YW
267int config_parse(
268 const char *unit,
269 const char *filename,
270 FILE *f,
271 const char *sections,
272 ConfigItemLookup lookup,
273 const void *table,
274 ConfigParseFlags flags,
275 void *userdata,
8524db50 276 struct stat *ret_stat) {
f975e971 277
7fd1b19b
HH
278 _cleanup_free_ char *section = NULL, *continuation = NULL;
279 _cleanup_fclose_ FILE *ours = NULL;
71a61510 280 unsigned line = 0, section_line = 0;
f9761a89 281 bool section_ignored = false, bom_seen = false;
8524db50 282 struct stat st;
14f594b9 283 int r, fd;
ed5bcfbe
LP
284
285 assert(filename);
f975e971 286 assert(lookup);
ed5bcfbe 287
87f0e418 288 if (!f) {
245802dd 289 f = ours = fopen(filename, "re");
f975e971 290 if (!f) {
36f822c4
ZJS
291 /* Only log on request, except for ENOENT,
292 * since we return 0 to the caller. */
bcde742e 293 if ((flags & CONFIG_PARSE_WARN) || errno == ENOENT)
b8b846d7
LP
294 log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_ERR, errno,
295 "Failed to open configuration file '%s': %m", filename);
8524db50
YW
296
297 if (errno == ENOENT) {
298 if (ret_stat)
299 *ret_stat = (struct stat) {};
300
301 return 0;
302 }
303
304 return -errno;
87f0e418 305 }
ed5bcfbe
LP
306 }
307
14f594b9 308 fd = fileno(f);
4f9ff96a 309 if (fd >= 0) { /* stream might not have an fd, let's be careful hence */
4f9ff96a
LP
310
311 if (fstat(fd, &st) < 0)
312 return log_full_errno(FLAGS_SET(flags, CONFIG_PARSE_WARN) ? LOG_ERR : LOG_DEBUG, errno,
313 "Failed to fstat(%s): %m", filename);
314
315 (void) stat_warn_permissions(filename, &st);
9fd8d678 316 } else
8524db50 317 st = (struct stat) {};
fdb9161c 318
9dd7ea9a 319 for (;;) {
e6dde451 320 _cleanup_free_ char *buf = NULL;
3dab2943 321 bool escaped = false;
92b5e605 322 char *l, *p, *e;
ed5bcfbe 323
e6dde451
LP
324 r = read_line(f, LONG_LINE_MAX, &buf);
325 if (r == 0)
326 break;
327 if (r == -ENOBUFS) {
bcde742e 328 if (flags & CONFIG_PARSE_WARN)
e6dde451
LP
329 log_error_errno(r, "%s:%u: Line too long", filename, line);
330
331 return r;
332 }
333 if (r < 0) {
5aca2e67 334 if (FLAGS_SET(flags, CONFIG_PARSE_WARN))
e6dde451 335 log_error_errno(r, "%s:%u: Error while reading configuration file: %m", filename, line);
ed5bcfbe 336
e6dde451 337 return r;
ed5bcfbe
LP
338 }
339
68c1ac15
YW
340 line++;
341
0ef69585
YW
342 l = skip_leading_chars(buf, WHITESPACE);
343 if (*l != '\0' && strchr(COMMENTS, *l))
9adbfeb3
YW
344 continue;
345
9dd7ea9a 346 l = buf;
f9761a89 347 if (!bom_seen) {
e6dde451 348 char *q;
9dd7ea9a 349
e6dde451
LP
350 q = startswith(buf, UTF8_BYTE_ORDER_MARK);
351 if (q) {
352 l = q;
f9761a89 353 bom_seen = true;
e6dde451
LP
354 }
355 }
3dab2943
LP
356
357 if (continuation) {
e6dde451 358 if (strlen(continuation) + strlen(l) > LONG_LINE_MAX) {
bcde742e 359 if (flags & CONFIG_PARSE_WARN)
e6dde451
LP
360 log_error("%s:%u: Continuation line too long", filename, line);
361 return -ENOBUFS;
362 }
363
c2bc710b 364 if (!strextend(&continuation, l)) {
bcde742e 365 if (flags & CONFIG_PARSE_WARN)
36f822c4 366 log_oom();
245802dd 367 return -ENOMEM;
36f822c4 368 }
3dab2943 369
92b5e605 370 p = continuation;
3dab2943
LP
371 } else
372 p = l;
373
374 for (e = p; *e; e++) {
375 if (escaped)
376 escaped = false;
377 else if (*e == '\\')
378 escaped = true;
379 }
380
381 if (escaped) {
382 *(e-1) = ' ';
383
92b5e605 384 if (!continuation) {
f975e971 385 continuation = strdup(l);
36f822c4 386 if (!continuation) {
bcde742e 387 if (flags & CONFIG_PARSE_WARN)
36f822c4 388 log_oom();
245802dd 389 return -ENOMEM;
36f822c4 390 }
3dab2943
LP
391 }
392
393 continue;
394 }
395
e8e581bf
ZJS
396 r = parse_line(unit,
397 filename,
68c1ac15 398 line,
e8e581bf
ZJS
399 sections,
400 lookup,
401 table,
bcde742e 402 flags,
e8e581bf 403 &section,
71a61510 404 &section_line,
342aea19 405 &section_ignored,
e8e581bf
ZJS
406 p,
407 userdata);
36f822c4 408 if (r < 0) {
bcde742e 409 if (flags & CONFIG_PARSE_WARN)
e6dde451 410 log_warning_errno(r, "%s:%u: Failed to parse file: %m", filename, line);
245802dd 411 return r;
36f822c4 412 }
92b5e605
LP
413
414 continuation = mfree(continuation);
ed5bcfbe
LP
415 }
416
4f29e0db
FB
417 if (continuation) {
418 r = parse_line(unit,
419 filename,
420 ++line,
421 sections,
422 lookup,
423 table,
424 flags,
425 &section,
426 &section_line,
427 &section_ignored,
428 continuation,
429 userdata);
430 if (r < 0) {
431 if (flags & CONFIG_PARSE_WARN)
432 log_warning_errno(r, "%s:%u: Failed to parse file: %m", filename, line);
433 return r;
4f29e0db
FB
434 }
435 }
436
8524db50
YW
437 if (ret_stat)
438 *ret_stat = st;
4f9ff96a 439
8b8024f1 440 return 1;
ed5bcfbe
LP
441}
442
8524db50
YW
443static int hashmap_put_stats_by_path(Hashmap **stats_by_path, const char *path, const struct stat *st) {
444 _cleanup_free_ struct stat *st_copy = NULL;
445 _cleanup_free_ char *path_copy = NULL;
446 int r;
447
448 assert(stats_by_path);
449 assert(path);
450 assert(st);
451
452 r = hashmap_ensure_allocated(stats_by_path, &path_hash_ops_free_free);
453 if (r < 0)
454 return r;
455
456 st_copy = newdup(struct stat, st, 1);
457 if (!st_copy)
458 return -ENOMEM;
459
460 path_copy = strdup(path);
461 if (!path)
462 return -ENOMEM;
463
464 r = hashmap_put(*stats_by_path, path_copy, st_copy);
465 if (r < 0)
466 return r;
467
468 assert(r > 0);
469 TAKE_PTR(path_copy);
470 TAKE_PTR(st_copy);
471 return 0;
472}
473
23bb31aa 474static int config_parse_many_files(
8b8024f1 475 const char* const* conf_files,
23bb31aa 476 char **files,
43688c49
ZJS
477 const char *sections,
478 ConfigItemLookup lookup,
479 const void *table,
bcde742e 480 ConfigParseFlags flags,
4f9ff96a 481 void *userdata,
8524db50 482 Hashmap **ret_stats_by_path) {
43688c49 483
8524db50
YW
484 _cleanup_hashmap_free_ Hashmap *stats_by_path = NULL;
485 struct stat st;
e8461023
JT
486 char **fn;
487 int r;
488
8524db50
YW
489 if (ret_stats_by_path) {
490 stats_by_path = hashmap_new(&path_hash_ops_free_free);
491 if (!stats_by_path)
492 return -ENOMEM;
493 }
494
8b8024f1
ZJS
495 /* First read the first found main config file. */
496 STRV_FOREACH(fn, (char**) conf_files) {
8524db50 497 r = config_parse(NULL, *fn, NULL, sections, lookup, table, flags, userdata, &st);
e8461023
JT
498 if (r < 0)
499 return r;
8524db50
YW
500 if (r == 0)
501 continue;
502
503 if (ret_stats_by_path) {
504 r = hashmap_put_stats_by_path(&stats_by_path, *fn, &st);
505 if (r < 0)
506 return r;
507 }
508
509 break;
e8461023
JT
510 }
511
8b8024f1 512 /* Then read all the drop-ins. */
e8461023 513 STRV_FOREACH(fn, files) {
8524db50 514 r = config_parse(NULL, *fn, NULL, sections, lookup, table, flags, userdata, &st);
e8461023
JT
515 if (r < 0)
516 return r;
8524db50
YW
517 if (r == 0)
518 continue;
519
520 if (ret_stats_by_path) {
521 r = hashmap_put_stats_by_path(&stats_by_path, *fn, &st);
522 if (r < 0)
523 return r;
524 }
e8461023
JT
525 }
526
8524db50
YW
527 if (ret_stats_by_path)
528 *ret_stats_by_path = TAKE_PTR(stats_by_path);
4f9ff96a 529
e8461023
JT
530 return 0;
531}
532
23bb31aa
ZJS
533/* Parse each config file in the directories specified as nulstr. */
534int config_parse_many_nulstr(
535 const char *conf_file,
536 const char *conf_file_dirs,
537 const char *sections,
538 ConfigItemLookup lookup,
539 const void *table,
bcde742e 540 ConfigParseFlags flags,
4f9ff96a 541 void *userdata,
8524db50 542 Hashmap **ret_stats_by_path) {
23bb31aa
ZJS
543
544 _cleanup_strv_free_ char **files = NULL;
545 int r;
546
b5084605 547 r = conf_files_list_nulstr(&files, ".conf", NULL, 0, conf_file_dirs);
23bb31aa
ZJS
548 if (r < 0)
549 return r;
550
8b8024f1
ZJS
551 return config_parse_many_files(STRV_MAKE_CONST(conf_file),
552 files, sections, lookup, table, flags, userdata,
8524db50 553 ret_stats_by_path);
23bb31aa
ZJS
554}
555
556/* Parse each config file in the directories specified as strv. */
557int config_parse_many(
8b8024f1 558 const char* const* conf_files,
23bb31aa
ZJS
559 const char* const* conf_file_dirs,
560 const char *dropin_dirname,
561 const char *sections,
562 ConfigItemLookup lookup,
563 const void *table,
bcde742e 564 ConfigParseFlags flags,
9f83091e 565 void *userdata,
8524db50 566 Hashmap **ret_stats_by_path) {
23bb31aa
ZJS
567
568 _cleanup_strv_free_ char **dropin_dirs = NULL;
569 _cleanup_strv_free_ char **files = NULL;
570 const char *suffix;
571 int r;
572
573 suffix = strjoina("/", dropin_dirname);
574 r = strv_extend_strv_concat(&dropin_dirs, (char**) conf_file_dirs, suffix);
575 if (r < 0)
576 return r;
577
b5084605 578 r = conf_files_list_strv(&files, ".conf", NULL, 0, (const char* const*) dropin_dirs);
23bb31aa
ZJS
579 if (r < 0)
580 return r;
581
8524db50 582 return config_parse_many_files(conf_files, files, sections, lookup, table, flags, userdata, ret_stats_by_path);
23bb31aa
ZJS
583}
584
307fe3cd
YW
585static void config_section_hash_func(const ConfigSection *c, struct siphash *state) {
586 siphash24_compress_string(c->filename, state);
587 siphash24_compress(&c->line, sizeof(c->line), state);
588}
589
590static int config_section_compare_func(const ConfigSection *x, const ConfigSection *y) {
591 int r;
592
593 r = strcmp(x->filename, y->filename);
594 if (r != 0)
595 return r;
596
597 return CMP(x->line, y->line);
598}
599
600DEFINE_HASH_OPS(config_section_hash_ops, ConfigSection, config_section_hash_func, config_section_compare_func);
601
602int config_section_new(const char *filename, unsigned line, ConfigSection **s) {
603 ConfigSection *cs;
604
605 cs = malloc0(offsetof(ConfigSection, filename) + strlen(filename) + 1);
606 if (!cs)
607 return -ENOMEM;
608
609 strcpy(cs->filename, filename);
610 cs->line = line;
611
612 *s = TAKE_PTR(cs);
613
614 return 0;
615}
616
617unsigned hashmap_find_free_section_line(Hashmap *hashmap) {
618 ConfigSection *cs;
619 unsigned n = 0;
620 void *entry;
621
622 HASHMAP_FOREACH_KEY(entry, cs, hashmap)
623 if (n < cs->line)
624 n = cs->line;
625
626 return n + 1;
627}
628
eb3491d9 629#define DEFINE_PARSER(type, vartype, conv_func) \
2d1729ca 630 DEFINE_CONFIG_PARSE_PTR(config_parse_##type, conv_func, vartype, "Failed to parse " #type " value")
94d75d64
LP
631
632DEFINE_PARSER(int, int, safe_atoi);
633DEFINE_PARSER(long, long, safe_atoli);
134e24e1 634DEFINE_PARSER(uint8, uint8_t, safe_atou8);
c7440e74 635DEFINE_PARSER(uint16, uint16_t, safe_atou16);
94d75d64 636DEFINE_PARSER(uint32, uint32_t, safe_atou32);
b57ebc60 637DEFINE_PARSER(int32, int32_t, safe_atoi32);
94d75d64
LP
638DEFINE_PARSER(uint64, uint64_t, safe_atou64);
639DEFINE_PARSER(unsigned, unsigned, safe_atou);
640DEFINE_PARSER(double, double, safe_atod);
641DEFINE_PARSER(nsec, nsec_t, parse_nsec);
642DEFINE_PARSER(sec, usec_t, parse_sec);
7b61ce3c 643DEFINE_PARSER(sec_def_infinity, usec_t, parse_sec_def_infinity);
94d75d64 644DEFINE_PARSER(mode, mode_t, parse_mode);
ed5bcfbe 645
c2f781bc
YW
646int config_parse_iec_size(
647 const char* unit,
648 const char *filename,
649 unsigned line,
650 const char *section,
651 unsigned section_line,
652 const char *lvalue,
653 int ltype,
654 const char *rvalue,
655 void *data,
656 void *userdata) {
ed5bcfbe
LP
657
658 size_t *sz = data;
59f448cf 659 uint64_t v;
e8e581bf 660 int r;
ed5bcfbe
LP
661
662 assert(filename);
663 assert(lvalue);
664 assert(rvalue);
665 assert(data);
666
59f448cf 667 r = parse_size(rvalue, 1024, &v);
1e5f4e8b
YW
668 if (r >= 0 && (uint64_t) (size_t) v != v)
669 r = -ERANGE;
670 if (r < 0) {
d96edb2c 671 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse size value '%s', ignoring: %m", rvalue);
9ba1a159
LP
672 return 0;
673 }
674
59f448cf 675 *sz = (size_t) v;
9ba1a159
LP
676 return 0;
677}
678
50299121 679int config_parse_si_uint64(
78f3c4bc
LP
680 const char* unit,
681 const char *filename,
682 unsigned line,
683 const char *section,
684 unsigned section_line,
685 const char *lvalue,
686 int ltype,
687 const char *rvalue,
688 void *data,
689 void *userdata) {
5556b5fe 690
50299121 691 uint64_t *sz = data;
5556b5fe
LP
692 int r;
693
694 assert(filename);
695 assert(lvalue);
696 assert(rvalue);
697 assert(data);
698
50299121 699 r = parse_size(rvalue, 1000, sz);
d96edb2c
YW
700 if (r < 0)
701 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse size value '%s', ignoring: %m", rvalue);
5556b5fe 702
5556b5fe
LP
703 return 0;
704}
9ba1a159 705
78f3c4bc
LP
706int config_parse_iec_uint64(
707 const char* unit,
708 const char *filename,
709 unsigned line,
710 const char *section,
711 unsigned section_line,
712 const char *lvalue,
713 int ltype,
714 const char *rvalue,
715 void *data,
716 void *userdata) {
9ba1a159 717
59f448cf 718 uint64_t *bytes = data;
e8e581bf 719 int r;
9ba1a159
LP
720
721 assert(filename);
722 assert(lvalue);
723 assert(rvalue);
724 assert(data);
725
5556b5fe 726 r = parse_size(rvalue, 1024, bytes);
e8e581bf 727 if (r < 0)
d96edb2c 728 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue);
ed5bcfbe 729
ed5bcfbe
LP
730 return 0;
731}
732
6e8791a0
TB
733int config_parse_iec_uint64_infinity(
734 const char* unit,
735 const char *filename,
736 unsigned line,
737 const char *section,
738 unsigned section_line,
739 const char *lvalue,
740 int ltype,
741 const char *rvalue,
742 void *data,
743 void *userdata) {
744
745 uint64_t *bytes = data;
746
747 assert(rvalue);
748 assert(data);
749
750 if (streq(rvalue, "infinity")) {
751 *bytes = UINT64_MAX;
752 return 0;
753 }
754
755 return config_parse_iec_uint64(unit, filename, line, section, section_line, lvalue, ltype, rvalue, data, userdata);
756}
757
c2f781bc
YW
758int config_parse_bool(
759 const char* unit,
760 const char *filename,
761 unsigned line,
762 const char *section,
763 unsigned section_line,
764 const char *lvalue,
765 int ltype,
766 const char *rvalue,
767 void *data,
768 void *userdata) {
ed5bcfbe
LP
769
770 int k;
771 bool *b = data;
2c75fb73 772 bool fatal = ltype;
ed5bcfbe
LP
773
774 assert(filename);
775 assert(lvalue);
776 assert(rvalue);
777 assert(data);
778
e8e581bf
ZJS
779 k = parse_boolean(rvalue);
780 if (k < 0) {
d96edb2c 781 log_syntax(unit, fatal ? LOG_ERR : LOG_WARNING, filename, line, k,
2c75fb73
ZJS
782 "Failed to parse boolean value%s: %s",
783 fatal ? "" : ", ignoring", rvalue);
784 return fatal ? -ENOEXEC : 0;
ed5bcfbe
LP
785 }
786
5d904a6a 787 *b = k;
ed5bcfbe
LP
788 return 0;
789}
790
12963533
TH
791int config_parse_id128(
792 const char *unit,
793 const char *filename,
794 unsigned line,
795 const char *section,
796 unsigned section_line,
797 const char *lvalue,
798 int ltype,
799 const char *rvalue,
800 void *data,
801 void *userdata) {
802
803 sd_id128_t t, *result = data;
804 int r;
805
806 assert(filename);
807 assert(lvalue);
808 assert(rvalue);
809
810 r = sd_id128_from_string(rvalue, &t);
d96edb2c
YW
811 if (r < 0) {
812 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse 128bit ID/UUID, ignoring: %s", rvalue);
813 return 0;
814 }
815
816 if (sd_id128_is_null(t)) {
817 log_syntax(unit, LOG_WARNING, filename, line, 0, "128bit ID/UUID is all 0, ignoring: %s", rvalue);
818 return 0;
819 }
12963533
TH
820
821 *result = t;
822 return 0;
823}
824
f757855e
LP
825int config_parse_tristate(
826 const char* unit,
827 const char *filename,
828 unsigned line,
829 const char *section,
830 unsigned section_line,
831 const char *lvalue,
832 int ltype,
833 const char *rvalue,
834 void *data,
835 void *userdata) {
836
837 int k, *t = data;
838
839 assert(filename);
840 assert(lvalue);
841 assert(rvalue);
842 assert(data);
843
33f2de7b
YW
844 /* A tristate is pretty much a boolean, except that it can also take an empty string,
845 * indicating "uninitialized", much like NULL is for a pointer type. */
846
847 if (isempty(rvalue)) {
848 *t = -1;
849 return 0;
850 }
f757855e
LP
851
852 k = parse_boolean(rvalue);
853 if (k < 0) {
33f2de7b
YW
854 log_syntax(unit, LOG_WARNING, filename, line, k,
855 "Failed to parse boolean value for %s=, ignoring: %s", lvalue, rvalue);
f757855e
LP
856 return 0;
857 }
858
fec5929f 859 *t = k;
f757855e
LP
860 return 0;
861}
862
8f2665a4
LP
863int config_parse_string(
864 const char *unit,
865 const char *filename,
866 unsigned line,
867 const char *section,
868 unsigned section_line,
869 const char *lvalue,
870 int ltype,
871 const char *rvalue,
872 void *data,
873 void *userdata) {
874
5a4ff988 875 char **s = data;
ed5bcfbe
LP
876
877 assert(filename);
878 assert(lvalue);
879 assert(rvalue);
880 assert(data);
881
b3f9c17a 882 return free_and_strdup_warn(s, empty_to_null(rvalue));
ed5bcfbe 883}
57d42a5f 884
2d17d699
LP
885int config_parse_safe_string(
886 const char *unit,
887 const char *filename,
888 unsigned line,
889 const char *section,
890 unsigned section_line,
891 const char *lvalue,
892 int ltype,
893 const char *rvalue,
894 void *data,
895 void *userdata) {
896
897 char **s = data;
898
899 assert(filename);
900 assert(lvalue);
901 assert(rvalue);
902 assert(data);
903
904 if (!string_is_safe(rvalue)) {
905 log_syntax(unit, LOG_WARNING, filename, line, 0, "Specified string contains unsafe characters, ignoring: %s", rvalue);
906 return 0;
907 }
908
909 return free_and_strdup_warn(s, empty_to_null(rvalue));
910}
911
8f2665a4
LP
912int config_parse_path(
913 const char *unit,
914 const char *filename,
915 unsigned line,
916 const char *section,
917 unsigned section_line,
918 const char *lvalue,
919 int ltype,
920 const char *rvalue,
921 void *data,
922 void *userdata) {
034c6ed7 923
c0d72c43 924 _cleanup_free_ char *n = NULL;
2c75fb73 925 bool fatal = ltype;
c0d72c43 926 char **s = data;
cd4f53c5 927 int r;
034c6ed7
LP
928
929 assert(filename);
930 assert(lvalue);
931 assert(rvalue);
932 assert(data);
933
8e7b5bd0 934 if (isempty(rvalue))
0fe50629 935 goto finalize;
0fe50629 936
7f110ff9
LP
937 n = strdup(rvalue);
938 if (!n)
74051b9b 939 return log_oom();
034c6ed7 940
cd4f53c5
YW
941 r = path_simplify_and_warn(n, PATH_CHECK_ABSOLUTE | (fatal ? PATH_CHECK_FATAL : 0), unit, filename, line, lvalue);
942 if (r < 0)
943 return fatal ? -ENOEXEC : 0;
01f78473 944
0fe50629 945finalize:
8e7b5bd0 946 return free_and_replace(*s, n);
034c6ed7 947}
57d42a5f 948
8249bb72
LP
949int config_parse_strv(
950 const char *unit,
951 const char *filename,
952 unsigned line,
953 const char *section,
954 unsigned section_line,
955 const char *lvalue,
956 int ltype,
957 const char *rvalue,
958 void *data,
959 void *userdata) {
57d42a5f 960
a2a5291b 961 char ***sv = data;
00d0fd06 962 int r;
57d42a5f
LP
963
964 assert(filename);
965 assert(lvalue);
966 assert(rvalue);
967 assert(data);
968
74051b9b 969 if (isempty(rvalue)) {
8249bb72 970 *sv = strv_free(*sv);
853b8397 971 return 0;
74051b9b
LP
972 }
973
d96edb2c 974 for (const char *p = rvalue;;) {
34f253f0 975 char *word = NULL;
00d0fd06 976
d96edb2c 977 r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
34f253f0 978 if (r == 0)
d96edb2c 979 return 0;
34f253f0 980 if (r == -ENOMEM)
853b8397 981 return log_oom();
34f253f0 982 if (r < 0) {
d96edb2c
YW
983 log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
984 return 0;
34f253f0 985 }
853b8397 986
34f253f0 987 r = strv_consume(sv, word);
853b8397
LP
988 if (r < 0)
989 return log_oom();
7f110ff9 990 }
57d42a5f 991}
15ae422b 992
1e35c5ab
RP
993int config_parse_warn_compat(
994 const char *unit,
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) {
7ef7e15b 1004
1e35c5ab
RP
1005 Disabled reason = ltype;
1006
1007 switch(reason) {
7ef7e15b 1008
1e35c5ab
RP
1009 case DISABLED_CONFIGURATION:
1010 log_syntax(unit, LOG_DEBUG, filename, line, 0,
1011 "Support for option %s= has been disabled at compile time and it is ignored", lvalue);
1012 break;
7ef7e15b 1013
1e35c5ab
RP
1014 case DISABLED_LEGACY:
1015 log_syntax(unit, LOG_INFO, filename, line, 0,
1016 "Support for option %s= has been removed and it is ignored", lvalue);
1017 break;
7ef7e15b 1018
1e35c5ab
RP
1019 case DISABLED_EXPERIMENTAL:
1020 log_syntax(unit, LOG_INFO, filename, line, 0,
1021 "Support for option %s= has not yet been enabled and it is ignored", lvalue);
1022 break;
7ef7e15b 1023 }
1e35c5ab
RP
1024
1025 return 0;
1026}
1027
ca37242e
LP
1028int config_parse_log_facility(
1029 const char *unit,
1030 const char *filename,
1031 unsigned line,
1032 const char *section,
1033 unsigned section_line,
1034 const char *lvalue,
1035 int ltype,
1036 const char *rvalue,
1037 void *data,
1038 void *userdata) {
213ba152 1039
213ba152
LP
1040 int *o = data, x;
1041
1042 assert(filename);
1043 assert(lvalue);
1044 assert(rvalue);
1045 assert(data);
1046
1047 x = log_facility_unshifted_from_string(rvalue);
1048 if (x < 0) {
b98680b2 1049 log_syntax(unit, LOG_WARNING, filename, line, x, "Failed to parse log facility, ignoring: %s", rvalue);
213ba152
LP
1050 return 0;
1051 }
1052
1053 *o = (x << 3) | LOG_PRI(*o);
1054
1055 return 0;
1056}
1057
ca37242e
LP
1058int config_parse_log_level(
1059 const char *unit,
1060 const char *filename,
1061 unsigned line,
1062 const char *section,
1063 unsigned section_line,
1064 const char *lvalue,
1065 int ltype,
1066 const char *rvalue,
1067 void *data,
1068 void *userdata) {
213ba152 1069
213ba152
LP
1070 int *o = data, x;
1071
1072 assert(filename);
1073 assert(lvalue);
1074 assert(rvalue);
1075 assert(data);
1076
1077 x = log_level_from_string(rvalue);
1078 if (x < 0) {
b98680b2 1079 log_syntax(unit, LOG_WARNING, filename, line, x, "Failed to parse log level, ignoring: %s", rvalue);
213ba152
LP
1080 return 0;
1081 }
1082
d3070fbd
LP
1083 if (*o < 0) /* if it wasn't initialized so far, assume zero facility */
1084 *o = x;
1085 else
1086 *o = (*o & LOG_FACMASK) | x;
1087
213ba152
LP
1088 return 0;
1089}
f757855e
LP
1090
1091int config_parse_signal(
1092 const char *unit,
1093 const char *filename,
1094 unsigned line,
1095 const char *section,
1096 unsigned section_line,
1097 const char *lvalue,
1098 int ltype,
1099 const char *rvalue,
1100 void *data,
1101 void *userdata) {
1102
1103 int *sig = data, r;
1104
1105 assert(filename);
1106 assert(lvalue);
1107 assert(rvalue);
1108 assert(sig);
1109
29a3db75 1110 r = signal_from_string(rvalue);
f757855e 1111 if (r <= 0) {
b98680b2 1112 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse signal name, ignoring: %s", rvalue);
f757855e
LP
1113 return 0;
1114 }
1115
1116 *sig = r;
1117 return 0;
1118}
1119
1120int config_parse_personality(
1121 const char *unit,
1122 const char *filename,
1123 unsigned line,
1124 const char *section,
1125 unsigned section_line,
1126 const char *lvalue,
1127 int ltype,
1128 const char *rvalue,
1129 void *data,
1130 void *userdata) {
1131
1132 unsigned long *personality = data, p;
1133
1134 assert(filename);
1135 assert(lvalue);
1136 assert(rvalue);
1137 assert(personality);
1138
40fdd636
LP
1139 if (isempty(rvalue))
1140 p = PERSONALITY_INVALID;
1141 else {
1142 p = personality_from_string(rvalue);
1143 if (p == PERSONALITY_INVALID) {
d96edb2c 1144 log_syntax(unit, LOG_WARNING, filename, line, 0, "Failed to parse personality, ignoring: %s", rvalue);
40fdd636
LP
1145 return 0;
1146 }
f757855e
LP
1147 }
1148
1149 *personality = p;
1150 return 0;
1151}
d31645ad
LP
1152
1153int config_parse_ifname(
1154 const char *unit,
1155 const char *filename,
1156 unsigned line,
1157 const char *section,
1158 unsigned section_line,
1159 const char *lvalue,
1160 int ltype,
1161 const char *rvalue,
1162 void *data,
1163 void *userdata) {
1164
1165 char **s = data;
1166 int r;
1167
1168 assert(filename);
1169 assert(lvalue);
1170 assert(rvalue);
1171 assert(data);
1172
1173 if (isempty(rvalue)) {
1174 *s = mfree(*s);
1175 return 0;
1176 }
1177
1178 if (!ifname_valid(rvalue)) {
d96edb2c 1179 log_syntax(unit, LOG_WARNING, filename, line, 0, "Interface name is not valid or too long, ignoring assignment: %s", rvalue);
d31645ad
LP
1180 return 0;
1181 }
1182
1183 r = free_and_strdup(s, rvalue);
1184 if (r < 0)
1185 return log_oom();
1186
1187 return 0;
1188}
177d0b20 1189
a5053a15
YW
1190int config_parse_ifnames(
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
1202 _cleanup_strv_free_ char **names = NULL;
1203 char ***s = data;
a5053a15
YW
1204 int r;
1205
1206 assert(filename);
1207 assert(lvalue);
1208 assert(rvalue);
1209 assert(data);
1210
1211 if (isempty(rvalue)) {
1212 *s = strv_free(*s);
1213 return 0;
1214 }
1215
d96edb2c 1216 for (const char *p = rvalue;;) {
a5053a15
YW
1217 _cleanup_free_ char *word = NULL;
1218
1219 r = extract_first_word(&p, &word, NULL, 0);
d96edb2c
YW
1220 if (r == -ENOMEM)
1221 return log_oom();
a5053a15 1222 if (r < 0) {
d96edb2c 1223 log_syntax(unit, LOG_WARNING, filename, line, r,
a5053a15
YW
1224 "Failed to extract interface name, ignoring assignment: %s",
1225 rvalue);
1226 return 0;
1227 }
1228 if (r == 0)
1229 break;
1230
1231 if (!ifname_valid_full(word, ltype)) {
d96edb2c 1232 log_syntax(unit, LOG_WARNING, filename, line, 0,
a5053a15
YW
1233 "Interface name is not valid or too long, ignoring assignment: %s",
1234 word);
1235 continue;
1236 }
1237
1238 r = strv_consume(&names, TAKE_PTR(word));
1239 if (r < 0)
1240 return log_oom();
1241 }
1242
1243 r = strv_extend_strv(s, names, true);
1244 if (r < 0)
1245 return log_oom();
1246
1247 return 0;
1248}
1249
177d0b20
SS
1250int config_parse_ip_port(
1251 const char *unit,
1252 const char *filename,
1253 unsigned line,
1254 const char *section,
1255 unsigned section_line,
1256 const char *lvalue,
1257 int ltype,
1258 const char *rvalue,
1259 void *data,
1260 void *userdata) {
1261
1262 uint16_t *s = data;
1263 uint16_t port;
1264 int r;
1265
1266 assert(filename);
1267 assert(lvalue);
1268 assert(rvalue);
1269 assert(data);
1270
1271 if (isempty(rvalue)) {
1272 *s = 0;
1273 return 0;
1274 }
1275
1276 r = parse_ip_port(rvalue, &port);
1277 if (r < 0) {
d96edb2c 1278 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse port '%s'.", rvalue);
177d0b20
SS
1279 return 0;
1280 }
1281
1282 *s = port;
1283
1284 return 0;
1285}
9ecdba8c 1286
79138a38
LP
1287int config_parse_mtu(
1288 const char *unit,
1289 const char *filename,
1290 unsigned line,
1291 const char *section,
1292 unsigned section_line,
1293 const char *lvalue,
1294 int ltype,
1295 const char *rvalue,
1296 void *data,
1297 void *userdata) {
1298
1299 uint32_t *mtu = data;
1300 int r;
1301
1302 assert(rvalue);
1303 assert(mtu);
1304
1305 r = parse_mtu(ltype, rvalue, mtu);
1306 if (r == -ERANGE) {
d96edb2c 1307 log_syntax(unit, LOG_WARNING, filename, line, r,
79138a38
LP
1308 "Maximum transfer unit (MTU) value out of range. Permitted range is %" PRIu32 "…%" PRIu32 ", ignoring: %s",
1309 (uint32_t) (ltype == AF_INET6 ? IPV6_MIN_MTU : IPV4_MIN_MTU), (uint32_t) UINT32_MAX,
1310 rvalue);
1311 return 0;
1312 }
1313 if (r < 0) {
d96edb2c 1314 log_syntax(unit, LOG_WARNING, filename, line, r,
79138a38
LP
1315 "Failed to parse MTU value '%s', ignoring: %m", rvalue);
1316 return 0;
1317 }
1318
1319 return 0;
1320}
4f424df7
LP
1321
1322int config_parse_rlimit(
1323 const char *unit,
1324 const char *filename,
1325 unsigned line,
1326 const char *section,
1327 unsigned section_line,
1328 const char *lvalue,
1329 int ltype,
1330 const char *rvalue,
1331 void *data,
1332 void *userdata) {
1333
1334 struct rlimit **rl = data, d = {};
1335 int r;
1336
1337 assert(rvalue);
1338 assert(rl);
1339
1340 r = rlimit_parse(ltype, rvalue, &d);
1341 if (r == -EILSEQ) {
1342 log_syntax(unit, LOG_WARNING, filename, line, r, "Soft resource limit chosen higher than hard limit, ignoring: %s", rvalue);
1343 return 0;
1344 }
1345 if (r < 0) {
d96edb2c 1346 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue);
4f424df7
LP
1347 return 0;
1348 }
1349
1350 if (rl[ltype])
1351 *rl[ltype] = d;
1352 else {
1353 rl[ltype] = newdup(struct rlimit, &d, 1);
1354 if (!rl[ltype])
1355 return log_oom();
1356 }
1357
1358 return 0;
1359}
c07b23ca 1360
c2f781bc
YW
1361int config_parse_permille(
1362 const char* unit,
1363 const char *filename,
1364 unsigned line,
1365 const char *section,
1366 unsigned section_line,
1367 const char *lvalue,
1368 int ltype,
1369 const char *rvalue,
1370 void *data,
1371 void *userdata) {
c07b23ca
MKB
1372
1373 unsigned *permille = data;
1374 int r;
1375
1376 assert(filename);
1377 assert(lvalue);
1378 assert(rvalue);
1379 assert(permille);
1380
1381 r = parse_permille(rvalue);
1382 if (r < 0) {
d96edb2c 1383 log_syntax(unit, LOG_WARNING, filename, line, r,
c07b23ca
MKB
1384 "Failed to parse permille value, ignoring: %s", rvalue);
1385 return 0;
1386 }
1387
1388 *permille = (unsigned) r;
1389
1390 return 0;
1391}
4df4df5b 1392
c2f781bc
YW
1393int config_parse_vlanprotocol(
1394 const char* unit,
1395 const char *filename,
1396 unsigned line,
1397 const char *section,
1398 unsigned section_line,
1399 const char *lvalue,
1400 int ltype,
1401 const char *rvalue,
1402 void *data,
1403 void *userdata) {
1404
4df4df5b 1405 int *vlan_protocol = data;
c2f781bc 1406
4df4df5b
RF
1407 assert(filename);
1408 assert(lvalue);
1409
1410 if (isempty(rvalue)) {
1411 *vlan_protocol = -1;
1412 return 0;
1413 }
1414
1415 if (STR_IN_SET(rvalue, "802.1ad", "802.1AD"))
1416 *vlan_protocol = ETH_P_8021AD;
1417 else if (STR_IN_SET(rvalue, "802.1q", "802.1Q"))
1418 *vlan_protocol = ETH_P_8021Q;
1419 else {
d96edb2c 1420 log_syntax(unit, LOG_WARNING, filename, line, 0,
4df4df5b
RF
1421 "Failed to parse VLAN protocol value, ignoring: %s", rvalue);
1422 return 0;
1423 }
1424
1425 return 0;
1426}
9de5e321 1427
99628f36
YW
1428int config_parse_hw_addr(
1429 const char *unit,
1430 const char *filename,
1431 unsigned line,
1432 const char *section,
1433 unsigned section_line,
1434 const char *lvalue,
1435 int ltype,
1436 const char *rvalue,
1437 void *data,
1438 void *userdata) {
1439
1440 struct hw_addr_data a, *hwaddr = data;
1441 int r;
1442
1443 assert(filename);
1444 assert(lvalue);
1445 assert(rvalue);
1446 assert(data);
1447
1448 if (isempty(rvalue)) {
1449 *hwaddr = HW_ADDR_NULL;
1450 return 0;
1451 }
1452
1453 r = parse_hw_addr_full(rvalue, ltype, &a);
1454 if (r < 0) {
1455 log_syntax(unit, LOG_WARNING, filename, line, r,
1456 "Not a valid hardware address, ignoring assignment: %s", rvalue);
1457 return 0;
1458 }
1459
1460 *hwaddr = a;
1461 return 0;
1462}
1463
1464int config_parse_hw_addrs(
1465 const char *unit,
1466 const char *filename,
1467 unsigned line,
1468 const char *section,
1469 unsigned section_line,
1470 const char *lvalue,
1471 int ltype,
1472 const char *rvalue,
1473 void *data,
1474 void *userdata) {
1475
1476 Set **hwaddrs = data;
1477 int r;
1478
1479 assert(filename);
1480 assert(lvalue);
1481 assert(rvalue);
1482 assert(data);
1483
1484 if (isempty(rvalue)) {
1485 /* Empty assignment resets the list */
1486 *hwaddrs = set_free(*hwaddrs);
1487 return 0;
1488 }
1489
1490 for (const char *p = rvalue;;) {
1491 _cleanup_free_ char *word = NULL;
1492 _cleanup_free_ struct hw_addr_data *n = NULL;
1493
1494 r = extract_first_word(&p, &word, NULL, 0);
1495 if (r == 0)
1496 return 0;
1497 if (r == -ENOMEM)
1498 return log_oom();
1499 if (r < 0) {
1500 log_syntax(unit, LOG_WARNING, filename, line, r,
1501 "Invalid syntax, ignoring: %s", rvalue);
1502 return 0;
1503 }
1504
1505 n = new(struct hw_addr_data, 1);
1506 if (!n)
1507 return log_oom();
1508
1509 r = parse_hw_addr_full(word, ltype, n);
1510 if (r < 0) {
1511 log_syntax(unit, LOG_WARNING, filename, line, r,
1512 "Not a valid hardware address, ignoring: %s", word);
1513 continue;
1514 }
1515
1516 r = set_ensure_consume(hwaddrs, &hw_addr_hash_ops_free, TAKE_PTR(n));
1517 if (r < 0)
1518 return log_oom();
1519 }
1520}
1521
aa4f7653 1522int config_parse_ether_addr(
0ec2a7a1
YW
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
1534 _cleanup_free_ struct ether_addr *n = NULL;
1535 struct ether_addr **hwaddr = data;
1536 int r;
1537
1538 assert(filename);
1539 assert(lvalue);
1540 assert(rvalue);
1541 assert(data);
1542
1543 if (isempty(rvalue)) {
1544 *hwaddr = mfree(*hwaddr);
1545 return 0;
1546 }
1547
1548 n = new0(struct ether_addr, 1);
1549 if (!n)
1550 return log_oom();
1551
227e9ce2 1552 r = parse_ether_addr(rvalue, n);
0ec2a7a1
YW
1553 if (r < 0) {
1554 log_syntax(unit, LOG_WARNING, filename, line, r,
1555 "Not a valid MAC address, ignoring assignment: %s", rvalue);
1556 return 0;
1557 }
1558
1559 free_and_replace(*hwaddr, n);
1560
1561 return 0;
1562}
1563
aa4f7653 1564int config_parse_ether_addrs(
0ec2a7a1
YW
1565 const char *unit,
1566 const char *filename,
1567 unsigned line,
1568 const char *section,
1569 unsigned section_line,
1570 const char *lvalue,
1571 int ltype,
1572 const char *rvalue,
1573 void *data,
1574 void *userdata) {
1575
1576 Set **hwaddrs = data;
1577 int r;
1578
1579 assert(filename);
1580 assert(lvalue);
1581 assert(rvalue);
1582 assert(data);
1583
1584 if (isempty(rvalue)) {
1585 /* Empty assignment resets the list */
c6df73ca 1586 *hwaddrs = set_free(*hwaddrs);
0ec2a7a1
YW
1587 return 0;
1588 }
1589
1590 for (const char *p = rvalue;;) {
1591 _cleanup_free_ char *word = NULL;
1592 _cleanup_free_ struct ether_addr *n = NULL;
1593
1594 r = extract_first_word(&p, &word, NULL, 0);
1595 if (r == 0)
1596 return 0;
1597 if (r == -ENOMEM)
1598 return log_oom();
1599 if (r < 0) {
1600 log_syntax(unit, LOG_WARNING, filename, line, r,
1601 "Invalid syntax, ignoring: %s", rvalue);
1602 return 0;
1603 }
1604
1605 n = new(struct ether_addr, 1);
1606 if (!n)
1607 return log_oom();
1608
227e9ce2 1609 r = parse_ether_addr(word, n);
0ec2a7a1
YW
1610 if (r < 0) {
1611 log_syntax(unit, LOG_WARNING, filename, line, r,
1612 "Not a valid MAC address, ignoring: %s", word);
1613 continue;
1614 }
1615
c6df73ca 1616 r = set_ensure_consume(hwaddrs, &ether_addr_hash_ops_free, TAKE_PTR(n));
0ec2a7a1
YW
1617 if (r < 0)
1618 return log_oom();
0ec2a7a1
YW
1619 }
1620}
1621
cf074772
YW
1622int config_parse_in_addr_non_null(
1623 const char *unit,
1624 const char *filename,
1625 unsigned line,
1626 const char *section,
1627 unsigned section_line,
1628 const char *lvalue,
1629 int ltype,
1630 const char *rvalue,
1631 void *data,
1632 void *userdata) {
1633
1634 /* data must be a pointer to struct in_addr or in6_addr, and the type is determined by ltype. */
1635 struct in_addr *ipv4 = data;
1636 struct in6_addr *ipv6 = data;
1637 union in_addr_union a;
1638 int r;
1639
1640 assert(filename);
1641 assert(lvalue);
1642 assert(rvalue);
1643 assert(data);
1644 assert(IN_SET(ltype, AF_INET, AF_INET6));
1645
1646 if (isempty(rvalue)) {
1647 if (ltype == AF_INET)
1648 *ipv4 = (struct in_addr) {};
1649 else
1650 *ipv6 = (struct in6_addr) {};
1651 return 0;
1652 }
1653
1654 r = in_addr_from_string(ltype, rvalue, &a);
1655 if (r < 0) {
1656 log_syntax(unit, LOG_WARNING, filename, line, r,
1657 "Failed to parse %s=, ignoring assignment: %s", lvalue, rvalue);
1658 return 0;
1659 }
1660
1661 if (!in_addr_is_set(ltype, &a)) {
1662 log_syntax(unit, LOG_WARNING, filename, line, 0,
1663 "%s= cannot be the ANY address, ignoring: %s", lvalue, rvalue);
1664 return 0;
1665 }
1666
1667 if (ltype == AF_INET)
1668 *ipv4 = a.in;
1669 else
1670 *ipv6 = a.in6;
1671 return 0;
1672}
1673
9de5e321 1674DEFINE_CONFIG_PARSE(config_parse_percent, parse_percent, "Failed to parse percent value");
0a9f9344 1675DEFINE_CONFIG_PARSE(config_parse_permyriad, parse_permyriad, "Failed to parse permyriad value");