]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/conf-parser.c
TEST-35-LOGIN: enable FileDescriptorStorePreserve= for coldplug test
[thirdparty/systemd.git] / src / shared / conf-parser.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <errno.h>
4 #include <limits.h>
5 #include <stdint.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <sys/types.h>
9
10 #include "alloc-util.h"
11 #include "conf-files.h"
12 #include "conf-parser.h"
13 #include "constants.h"
14 #include "dns-domain.h"
15 #include "escape.h"
16 #include "ether-addr-util.h"
17 #include "extract-word.h"
18 #include "fd-util.h"
19 #include "fileio.h"
20 #include "fs-util.h"
21 #include "hash-funcs.h"
22 #include "hostname-util.h"
23 #include "id128-util.h"
24 #include "in-addr-util.h"
25 #include "log.h"
26 #include "macro.h"
27 #include "missing_network.h"
28 #include "nulstr-util.h"
29 #include "parse-helpers.h"
30 #include "parse-util.h"
31 #include "path-util.h"
32 #include "percent-util.h"
33 #include "process-util.h"
34 #include "rlimit-util.h"
35 #include "sd-id128.h"
36 #include "set.h"
37 #include "signal-util.h"
38 #include "socket-util.h"
39 #include "stat-util.h"
40 #include "string-util.h"
41 #include "strv.h"
42 #include "syslog-util.h"
43 #include "time-util.h"
44 #include "utf8.h"
45
46 DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(config_file_hash_ops_fclose,
47 char, path_hash_func, path_compare,
48 FILE, safe_fclose);
49
50 int config_item_table_lookup(
51 const void *table,
52 const char *section,
53 const char *lvalue,
54 ConfigParserCallback *ret_func,
55 int *ret_ltype,
56 void **ret_data,
57 void *userdata) {
58
59 assert(table);
60 assert(lvalue);
61 assert(ret_func);
62 assert(ret_ltype);
63 assert(ret_data);
64
65 for (const ConfigTableItem *t = table; t->lvalue; t++) {
66
67 if (!streq(lvalue, t->lvalue))
68 continue;
69
70 if (!streq_ptr(section, t->section))
71 continue;
72
73 *ret_func = t->parse;
74 *ret_ltype = t->ltype;
75 *ret_data = t->data;
76 return 1;
77 }
78
79 *ret_func = NULL;
80 *ret_ltype = 0;
81 *ret_data = NULL;
82 return 0;
83 }
84
85 int config_item_perf_lookup(
86 const void *table,
87 const char *section,
88 const char *lvalue,
89 ConfigParserCallback *ret_func,
90 int *ret_ltype,
91 void **ret_data,
92 void *userdata) {
93
94 ConfigPerfItemLookup lookup = (ConfigPerfItemLookup) table;
95 const ConfigPerfItem *p;
96
97 assert(table);
98 assert(lvalue);
99 assert(ret_func);
100 assert(ret_ltype);
101 assert(ret_data);
102
103 if (section) {
104 const char *key;
105
106 key = strjoina(section, ".", lvalue);
107 p = lookup(key, strlen(key));
108 } else
109 p = lookup(lvalue, strlen(lvalue));
110 if (!p) {
111 *ret_func = NULL;
112 *ret_ltype = 0;
113 *ret_data = NULL;
114 return 0;
115 }
116
117 *ret_func = p->parse;
118 *ret_ltype = p->ltype;
119 *ret_data = (uint8_t*) userdata + p->offset;
120 return 1;
121 }
122
123 /* Run the user supplied parser for an assignment */
124 static 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) {
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;
151 if (r > 0) {
152 if (!func)
153 return 0;
154
155 return func(unit, filename, line, section, section_line,
156 lvalue, ltype, rvalue, data, userdata);
157 }
158
159 /* Warn about unknown non-extension fields. */
160 if (!(flags & CONFIG_PARSE_RELAXED) && !startswith(lvalue, "X-"))
161 log_syntax(unit, LOG_WARNING, filename, line, 0,
162 "Unknown key name '%s' in section '%s', ignoring.", lvalue, section);
163
164 return 0;
165 }
166
167 /* Parse a single logical line */
168 static int parse_line(
169 const char* unit,
170 const char *filename,
171 unsigned line,
172 const char *sections,
173 ConfigItemLookup lookup,
174 const void *table,
175 ConfigParseFlags flags,
176 char **section,
177 unsigned *section_line,
178 bool *section_ignored,
179 char *l, /* is modified */
180 void *userdata) {
181
182 char *e;
183
184 assert(filename);
185 assert(line > 0);
186 assert(lookup);
187 assert(l);
188
189 l = strstrip(l);
190 if (isempty(l))
191 return 0;
192
193 if (l[0] == '\n')
194 return 0;
195
196 if (!utf8_is_valid(l))
197 return log_syntax_invalid_utf8(unit, LOG_WARNING, filename, line, l);
198
199 if (l[0] == '[') {
200 _cleanup_free_ char *n = NULL;
201 size_t k;
202
203 k = strlen(l);
204 assert(k > 0);
205
206 if (l[k-1] != ']')
207 return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EBADMSG), "Invalid section header '%s'", l);
208
209 n = strndup(l+1, k-2);
210 if (!n)
211 return log_oom();
212
213 if (!string_is_safe(n))
214 return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EBADMSG), "Bad characters in section header '%s'", l);
215
216 if (sections && !nulstr_contains(sections, n)) {
217 bool ignore;
218
219 ignore = (flags & CONFIG_PARSE_RELAXED) || startswith(n, "X-");
220
221 if (!ignore)
222 NULSTR_FOREACH(t, sections)
223 if (streq_ptr(n, startswith(t, "-"))) { /* Ignore sections prefixed with "-" in valid section list */
224 ignore = true;
225 break;
226 }
227
228 if (!ignore)
229 log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown section '%s'. Ignoring.", n);
230
231 *section = mfree(*section);
232 *section_line = 0;
233 *section_ignored = true;
234 } else {
235 free_and_replace(*section, n);
236 *section_line = line;
237 *section_ignored = false;
238 }
239
240 return 0;
241 }
242
243 if (sections && !*section) {
244 if (!(flags & CONFIG_PARSE_RELAXED) && !*section_ignored)
245 log_syntax(unit, LOG_WARNING, filename, line, 0, "Assignment outside of section. Ignoring.");
246
247 return 0;
248 }
249
250 e = strchr(l, '=');
251 if (!e)
252 return log_syntax(unit, LOG_WARNING, filename, line, 0,
253 "Missing '=', ignoring line.");
254 if (e == l)
255 return log_syntax(unit, LOG_WARNING, filename, line, 0,
256 "Missing key name before '=', ignoring line.");
257
258 *e = 0;
259 e++;
260
261 return next_assignment(unit,
262 filename,
263 line,
264 lookup,
265 table,
266 *section,
267 *section_line,
268 strstrip(l),
269 strstrip(e),
270 flags,
271 userdata);
272 }
273
274 /* Go through the file and parse each line */
275 int config_parse(
276 const char *unit,
277 const char *filename,
278 FILE *f,
279 const char *sections,
280 ConfigItemLookup lookup,
281 const void *table,
282 ConfigParseFlags flags,
283 void *userdata,
284 struct stat *ret_stat) {
285
286 _cleanup_free_ char *section = NULL, *continuation = NULL;
287 _cleanup_fclose_ FILE *ours = NULL;
288 unsigned line = 0, section_line = 0;
289 bool section_ignored = false, bom_seen = false;
290 struct stat st;
291 int r, fd;
292
293 assert(filename);
294 assert(lookup);
295
296 if (!f) {
297 f = ours = fopen(filename, "re");
298 if (!f) {
299 /* Only log on request, except for ENOENT,
300 * since we return 0 to the caller. */
301 if ((flags & CONFIG_PARSE_WARN) || errno == ENOENT)
302 log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_ERR, errno,
303 "Failed to open configuration file '%s': %m", filename);
304
305 if (errno == ENOENT) {
306 if (ret_stat)
307 *ret_stat = (struct stat) {};
308
309 return 0;
310 }
311
312 return -errno;
313 }
314 }
315
316 fd = fileno(f);
317 if (fd >= 0) { /* stream might not have an fd, let's be careful hence */
318
319 if (fstat(fd, &st) < 0)
320 return log_full_errno(FLAGS_SET(flags, CONFIG_PARSE_WARN) ? LOG_ERR : LOG_DEBUG, errno,
321 "Failed to fstat(%s): %m", filename);
322
323 (void) stat_warn_permissions(filename, &st);
324 } else
325 st = (struct stat) {};
326
327 for (;;) {
328 _cleanup_free_ char *buf = NULL;
329 bool escaped = false;
330 char *l, *p, *e;
331
332 r = read_line(f, LONG_LINE_MAX, &buf);
333 if (r == 0)
334 break;
335 if (r == -ENOBUFS) {
336 if (flags & CONFIG_PARSE_WARN)
337 log_error_errno(r, "%s:%u: Line too long", filename, line);
338
339 return r;
340 }
341 if (r < 0) {
342 if (FLAGS_SET(flags, CONFIG_PARSE_WARN))
343 log_error_errno(r, "%s:%u: Error while reading configuration file: %m", filename, line);
344
345 return r;
346 }
347
348 line++;
349
350 l = skip_leading_chars(buf, WHITESPACE);
351 if (*l != '\0' && strchr(COMMENTS, *l))
352 continue;
353
354 l = buf;
355 if (!bom_seen) {
356 char *q;
357
358 q = startswith(buf, UTF8_BYTE_ORDER_MARK);
359 if (q) {
360 l = q;
361 bom_seen = true;
362 }
363 }
364
365 if (continuation) {
366 if (strlen(continuation) + strlen(l) > LONG_LINE_MAX) {
367 if (flags & CONFIG_PARSE_WARN)
368 log_error("%s:%u: Continuation line too long", filename, line);
369 return -ENOBUFS;
370 }
371
372 if (!strextend(&continuation, l)) {
373 if (flags & CONFIG_PARSE_WARN)
374 log_oom();
375 return -ENOMEM;
376 }
377
378 p = continuation;
379 } else
380 p = l;
381
382 for (e = p; *e; e++) {
383 if (escaped)
384 escaped = false;
385 else if (*e == '\\')
386 escaped = true;
387 }
388
389 if (escaped) {
390 *(e-1) = ' ';
391
392 if (!continuation) {
393 continuation = strdup(l);
394 if (!continuation) {
395 if (flags & CONFIG_PARSE_WARN)
396 log_oom();
397 return -ENOMEM;
398 }
399 }
400
401 continue;
402 }
403
404 r = parse_line(unit,
405 filename,
406 line,
407 sections,
408 lookup,
409 table,
410 flags,
411 &section,
412 &section_line,
413 &section_ignored,
414 p,
415 userdata);
416 if (r < 0) {
417 if (flags & CONFIG_PARSE_WARN)
418 log_warning_errno(r, "%s:%u: Failed to parse file: %m", filename, line);
419 return r;
420 }
421
422 continuation = mfree(continuation);
423 }
424
425 if (continuation) {
426 r = parse_line(unit,
427 filename,
428 ++line,
429 sections,
430 lookup,
431 table,
432 flags,
433 &section,
434 &section_line,
435 &section_ignored,
436 continuation,
437 userdata);
438 if (r < 0) {
439 if (flags & CONFIG_PARSE_WARN)
440 log_warning_errno(r, "%s:%u: Failed to parse file: %m", filename, line);
441 return r;
442 }
443 }
444
445 if (ret_stat)
446 *ret_stat = st;
447
448 return 1;
449 }
450
451 int hashmap_put_stats_by_path(Hashmap **stats_by_path, const char *path, const struct stat *st) {
452 _cleanup_free_ struct stat *st_copy = NULL;
453 _cleanup_free_ char *path_copy = NULL;
454 int r;
455
456 assert(stats_by_path);
457 assert(path);
458 assert(st);
459
460 r = hashmap_ensure_allocated(stats_by_path, &path_hash_ops_free_free);
461 if (r < 0)
462 return r;
463
464 st_copy = newdup(struct stat, st, 1);
465 if (!st_copy)
466 return -ENOMEM;
467
468 path_copy = strdup(path);
469 if (!path)
470 return -ENOMEM;
471
472 r = hashmap_put(*stats_by_path, path_copy, st_copy);
473 if (r < 0)
474 return r;
475
476 assert(r > 0);
477 TAKE_PTR(path_copy);
478 TAKE_PTR(st_copy);
479 return 0;
480 }
481
482 static int config_parse_many_files(
483 const char* const* conf_files,
484 char **files,
485 const char *sections,
486 ConfigItemLookup lookup,
487 const void *table,
488 ConfigParseFlags flags,
489 void *userdata,
490 Hashmap **ret_stats_by_path) {
491
492 _cleanup_hashmap_free_ Hashmap *stats_by_path = NULL;
493 _cleanup_ordered_hashmap_free_ OrderedHashmap *dropins = NULL;
494 _cleanup_set_free_ Set *inodes = NULL;
495 struct stat st;
496 int r;
497
498 if (ret_stats_by_path) {
499 stats_by_path = hashmap_new(&path_hash_ops_free_free);
500 if (!stats_by_path)
501 return -ENOMEM;
502 }
503
504 STRV_FOREACH(fn, files) {
505 _cleanup_free_ struct stat *st_dropin = NULL;
506 _cleanup_fclose_ FILE *f = NULL;
507 int fd;
508
509 f = fopen(*fn, "re");
510 if (!f) {
511 if (errno == ENOENT)
512 continue;
513
514 return -errno;
515 }
516
517 fd = fileno(f);
518
519 r = ordered_hashmap_ensure_put(&dropins, &config_file_hash_ops_fclose, *fn, f);
520 if (r < 0) {
521 assert(r != -EEXIST);
522 return r;
523 }
524 assert(r > 0);
525 TAKE_PTR(f);
526
527 /* Get inodes for all drop-ins. Later we'll verify if main config is a symlink to or is
528 * symlinked as one of them. If so, we skip reading main config file directly. */
529
530 st_dropin = new(struct stat, 1);
531 if (!st_dropin)
532 return -ENOMEM;
533
534 if (fstat(fd, st_dropin) < 0)
535 return -errno;
536
537 r = set_ensure_consume(&inodes, &inode_hash_ops, TAKE_PTR(st_dropin));
538 if (r < 0)
539 return r;
540 }
541
542 /* First read the first found main config file. */
543 STRV_FOREACH(fn, conf_files) {
544 _cleanup_fclose_ FILE *f = NULL;
545
546 f = fopen(*fn, "re");
547 if (!f) {
548 if (errno == ENOENT)
549 continue;
550
551 return -errno;
552 }
553
554 if (inodes) {
555 if (fstat(fileno(f), &st) < 0)
556 return -errno;
557
558 if (set_contains(inodes, &st)) {
559 log_debug("%s: symlink to/symlinked as drop-in, will be read later.", *fn);
560 break;
561 }
562 }
563
564 r = config_parse(NULL, *fn, f, sections, lookup, table, flags, userdata, &st);
565 if (r < 0)
566 return r;
567 assert(r > 0);
568
569 if (ret_stats_by_path) {
570 r = hashmap_put_stats_by_path(&stats_by_path, *fn, &st);
571 if (r < 0)
572 return r;
573 }
574
575 break;
576 }
577
578 /* Then read all the drop-ins. */
579
580 const char *path_dropin;
581 FILE *f_dropin;
582 ORDERED_HASHMAP_FOREACH_KEY(f_dropin, path_dropin, dropins) {
583 r = config_parse(NULL, path_dropin, f_dropin, sections, lookup, table, flags, userdata, &st);
584 if (r < 0)
585 return r;
586 assert(r > 0);
587
588 if (ret_stats_by_path) {
589 r = hashmap_put_stats_by_path(&stats_by_path, path_dropin, &st);
590 if (r < 0)
591 return r;
592 }
593 }
594
595 if (ret_stats_by_path)
596 *ret_stats_by_path = TAKE_PTR(stats_by_path);
597
598 return 0;
599 }
600
601 /* Parse one main config file located in /etc/systemd and its drop-ins, which is what all systemd daemons
602 * do. */
603 int config_parse_config_file(
604 const char *conf_file,
605 const char *sections,
606 ConfigItemLookup lookup,
607 const void *table,
608 ConfigParseFlags flags,
609 void *userdata) {
610
611 _cleanup_strv_free_ char **dropins = NULL, **dropin_dirs = NULL;
612 char **conf_paths = CONF_PATHS_STRV("");
613 int r;
614
615 assert(conf_file);
616
617 /* build the dropin dir list */
618 dropin_dirs = new0(char*, strv_length(conf_paths) + 1);
619 if (!dropin_dirs) {
620 if (flags & CONFIG_PARSE_WARN)
621 return log_oom();
622 return -ENOMEM;
623 }
624
625 size_t i = 0;
626 STRV_FOREACH(p, conf_paths) {
627 char *d;
628
629 d = strjoin(*p, "systemd/", conf_file, ".d");
630 if (!d) {
631 if (flags & CONFIG_PARSE_WARN)
632 return log_oom();
633 return -ENOMEM;
634 }
635
636 dropin_dirs[i++] = d;
637 }
638
639 r = conf_files_list_strv(&dropins, ".conf", NULL, 0, (const char**) dropin_dirs);
640 if (r < 0)
641 return r;
642
643 const char *sysconf_file = strjoina(PKGSYSCONFDIR, "/", conf_file);
644
645 return config_parse_many_files(STRV_MAKE_CONST(sysconf_file), dropins,
646 sections, lookup, table, flags, userdata, NULL);
647 }
648
649 /* Parse each config file in the directories specified as strv. */
650 int config_parse_many(
651 const char* const* conf_files,
652 const char* const* conf_file_dirs,
653 const char *dropin_dirname,
654 const char *root,
655 const char *sections,
656 ConfigItemLookup lookup,
657 const void *table,
658 ConfigParseFlags flags,
659 void *userdata,
660 Hashmap **ret_stats_by_path,
661 char ***ret_dropin_files) {
662
663 _cleanup_strv_free_ char **files = NULL;
664 int r;
665
666 assert(conf_file_dirs);
667 assert(dropin_dirname);
668 assert(sections);
669 assert(table);
670
671 r = conf_files_list_dropins(&files, dropin_dirname, root, conf_file_dirs);
672 if (r < 0)
673 return r;
674
675 r = config_parse_many_files(conf_files, files, sections, lookup, table, flags, userdata, ret_stats_by_path);
676 if (r < 0)
677 return r;
678
679 if (ret_dropin_files)
680 *ret_dropin_files = TAKE_PTR(files);
681
682 return 0;
683 }
684
685 static int dropins_get_stats_by_path(
686 const char* conf_file,
687 const char* const* conf_file_dirs,
688 Hashmap **stats_by_path) {
689
690 _cleanup_strv_free_ char **files = NULL;
691 _cleanup_free_ char *dropin_dirname = NULL;
692 int r;
693
694 assert(conf_file);
695 assert(conf_file_dirs);
696 assert(stats_by_path);
697
698 r = path_extract_filename(conf_file, &dropin_dirname);
699 if (r < 0)
700 return r;
701 if (r == O_DIRECTORY)
702 return -EINVAL;
703
704 if (!strextend(&dropin_dirname, ".d"))
705 return -ENOMEM;
706
707 r = conf_files_list_dropins(&files, dropin_dirname, /* root = */ NULL, conf_file_dirs);
708 if (r < 0)
709 return r;
710
711 STRV_FOREACH(fn, files) {
712 struct stat st;
713
714 if (stat(*fn, &st) < 0) {
715 if (errno == ENOENT)
716 continue;
717
718 return -errno;
719 }
720
721 r = hashmap_put_stats_by_path(stats_by_path, *fn, &st);
722 if (r < 0)
723 return r;
724 }
725
726 return 0;
727 }
728
729 int config_get_stats_by_path(
730 const char *suffix,
731 const char *root,
732 unsigned flags,
733 const char* const* dirs,
734 bool check_dropins,
735 Hashmap **ret) {
736
737 _cleanup_hashmap_free_ Hashmap *stats_by_path = NULL;
738 _cleanup_strv_free_ char **files = NULL;
739 int r;
740
741 assert(suffix);
742 assert(dirs);
743 assert(ret);
744
745 /* Unlike config_parse(), this does not support stream. */
746
747 r = conf_files_list_strv(&files, suffix, root, flags, dirs);
748 if (r < 0)
749 return r;
750
751 STRV_FOREACH(f, files) {
752 struct stat st;
753
754 /* First read the main config file. */
755 if (stat(*f, &st) < 0) {
756 if (errno == ENOENT)
757 continue;
758
759 return -errno;
760 }
761
762 r = hashmap_put_stats_by_path(&stats_by_path, *f, &st);
763 if (r < 0)
764 return r;
765
766 if (!check_dropins)
767 continue;
768
769 /* Then read all the drop-ins if requested. */
770 r = dropins_get_stats_by_path(*f, dirs, &stats_by_path);
771 if (r < 0)
772 return r;
773 }
774
775 *ret = TAKE_PTR(stats_by_path);
776 return 0;
777 }
778
779 bool stats_by_path_equal(Hashmap *a, Hashmap *b) {
780 struct stat *st_a, *st_b;
781 const char *path;
782
783 if (hashmap_size(a) != hashmap_size(b))
784 return false;
785
786 HASHMAP_FOREACH_KEY(st_a, path, a) {
787 st_b = hashmap_get(b, path);
788 if (!st_b)
789 return false;
790
791 if (!stat_inode_unmodified(st_a, st_b))
792 return false;
793 }
794
795 return true;
796 }
797
798 static void config_section_hash_func(const ConfigSection *c, struct siphash *state) {
799 siphash24_compress_string(c->filename, state);
800 siphash24_compress_typesafe(c->line, state);
801 }
802
803 static int config_section_compare_func(const ConfigSection *x, const ConfigSection *y) {
804 int r;
805
806 r = strcmp(x->filename, y->filename);
807 if (r != 0)
808 return r;
809
810 return CMP(x->line, y->line);
811 }
812
813 DEFINE_HASH_OPS(config_section_hash_ops, ConfigSection, config_section_hash_func, config_section_compare_func);
814
815 int config_section_new(const char *filename, unsigned line, ConfigSection **ret) {
816 ConfigSection *cs;
817
818 assert(filename);
819 assert(line > 0);
820 assert(ret);
821
822 cs = malloc0(offsetof(ConfigSection, filename) + strlen(filename) + 1);
823 if (!cs)
824 return -ENOMEM;
825
826 strcpy(cs->filename, filename);
827 cs->line = line;
828
829 *ret = TAKE_PTR(cs);
830 return 0;
831 }
832
833 int _hashmap_by_section_find_unused_line(
834 HashmapBase *entries_by_section,
835 const char *filename,
836 unsigned *ret) {
837
838 ConfigSection *cs;
839 unsigned n = 0;
840 void *entry;
841
842 HASHMAP_BASE_FOREACH_KEY(entry, cs, entries_by_section) {
843 if (filename && !streq(cs->filename, filename))
844 continue;
845 n = MAX(n, cs->line);
846 }
847
848 /* overflow? */
849 if (n >= UINT_MAX)
850 return -EFBIG;
851
852 *ret = n + 1;
853 return 0;
854 }
855
856 #define DEFINE_PARSER(type, vartype, conv_func) \
857 DEFINE_CONFIG_PARSE_PTR(config_parse_##type, conv_func, vartype, "Failed to parse " #type " value")
858
859 DEFINE_PARSER(int, int, safe_atoi);
860 DEFINE_PARSER(long, long, safe_atoli);
861 DEFINE_PARSER(uint8, uint8_t, safe_atou8);
862 DEFINE_PARSER(uint16, uint16_t, safe_atou16);
863 DEFINE_PARSER(uint32, uint32_t, safe_atou32);
864 DEFINE_PARSER(int32, int32_t, safe_atoi32);
865 DEFINE_PARSER(uint64, uint64_t, safe_atou64);
866 DEFINE_PARSER(unsigned, unsigned, safe_atou);
867 DEFINE_PARSER(double, double, safe_atod);
868 DEFINE_PARSER(nsec, nsec_t, parse_nsec);
869 DEFINE_PARSER(sec, usec_t, parse_sec);
870 DEFINE_PARSER(sec_def_infinity, usec_t, parse_sec_def_infinity);
871 DEFINE_PARSER(mode, mode_t, parse_mode);
872 DEFINE_PARSER(pid, pid_t, parse_pid);
873
874 int config_parse_iec_size(
875 const char* unit,
876 const char *filename,
877 unsigned line,
878 const char *section,
879 unsigned section_line,
880 const char *lvalue,
881 int ltype,
882 const char *rvalue,
883 void *data,
884 void *userdata) {
885
886 size_t *sz = ASSERT_PTR(data);
887 uint64_t v;
888 int r;
889
890 assert(filename);
891 assert(lvalue);
892 assert(rvalue);
893
894 r = parse_size(rvalue, 1024, &v);
895 if (r >= 0 && (uint64_t) (size_t) v != v)
896 r = -ERANGE;
897 if (r < 0) {
898 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse size value '%s', ignoring: %m", rvalue);
899 return 0;
900 }
901
902 *sz = (size_t) v;
903 return 0;
904 }
905
906 int config_parse_si_uint64(
907 const char* unit,
908 const char *filename,
909 unsigned line,
910 const char *section,
911 unsigned section_line,
912 const char *lvalue,
913 int ltype,
914 const char *rvalue,
915 void *data,
916 void *userdata) {
917
918 uint64_t *sz = ASSERT_PTR(data);
919 int r;
920
921 assert(filename);
922 assert(lvalue);
923 assert(rvalue);
924
925 r = parse_size(rvalue, 1000, sz);
926 if (r < 0)
927 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse size value '%s', ignoring: %m", rvalue);
928
929 return 0;
930 }
931
932 int config_parse_iec_uint64(
933 const char* unit,
934 const char *filename,
935 unsigned line,
936 const char *section,
937 unsigned section_line,
938 const char *lvalue,
939 int ltype,
940 const char *rvalue,
941 void *data,
942 void *userdata) {
943
944 uint64_t *bytes = ASSERT_PTR(data);
945 int r;
946
947 assert(filename);
948 assert(lvalue);
949 assert(rvalue);
950
951 r = parse_size(rvalue, 1024, bytes);
952 if (r < 0)
953 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue);
954
955 return 0;
956 }
957
958 int config_parse_iec_uint64_infinity(
959 const char* unit,
960 const char *filename,
961 unsigned line,
962 const char *section,
963 unsigned section_line,
964 const char *lvalue,
965 int ltype,
966 const char *rvalue,
967 void *data,
968 void *userdata) {
969
970 uint64_t *bytes = ASSERT_PTR(data);
971
972 assert(rvalue);
973
974 if (streq(rvalue, "infinity")) {
975 *bytes = UINT64_MAX;
976 return 0;
977 }
978
979 return config_parse_iec_uint64(unit, filename, line, section, section_line, lvalue, ltype, rvalue, data, userdata);
980 }
981
982 int config_parse_bool(
983 const char* unit,
984 const char *filename,
985 unsigned line,
986 const char *section,
987 unsigned section_line,
988 const char *lvalue,
989 int ltype,
990 const char *rvalue,
991 void *data,
992 void *userdata) {
993
994 int k;
995 bool *b = ASSERT_PTR(data);
996 bool fatal = ltype;
997
998 assert(filename);
999 assert(lvalue);
1000 assert(rvalue);
1001
1002 k = parse_boolean(rvalue);
1003 if (k < 0) {
1004 log_syntax(unit, fatal ? LOG_ERR : LOG_WARNING, filename, line, k,
1005 "Failed to parse boolean value%s: %s",
1006 fatal ? "" : ", ignoring", rvalue);
1007 return fatal ? -ENOEXEC : 0;
1008 }
1009
1010 *b = k;
1011 return 0;
1012 }
1013
1014 int config_parse_id128(
1015 const char *unit,
1016 const char *filename,
1017 unsigned line,
1018 const char *section,
1019 unsigned section_line,
1020 const char *lvalue,
1021 int ltype,
1022 const char *rvalue,
1023 void *data,
1024 void *userdata) {
1025
1026 sd_id128_t *result = data;
1027 int r;
1028
1029 assert(filename);
1030 assert(lvalue);
1031 assert(rvalue);
1032
1033 r = id128_from_string_nonzero(rvalue, result);
1034 if (r == -ENXIO)
1035 log_syntax(unit, LOG_WARNING, filename, line, r, "128-bit ID/UUID is all 0, ignoring: %s", rvalue);
1036 else if (r < 0)
1037 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse 128-bit ID/UUID, ignoring: %s", rvalue);
1038
1039 return 0;
1040 }
1041
1042 int config_parse_tristate(
1043 const char* unit,
1044 const char *filename,
1045 unsigned line,
1046 const char *section,
1047 unsigned section_line,
1048 const char *lvalue,
1049 int ltype,
1050 const char *rvalue,
1051 void *data,
1052 void *userdata) {
1053
1054 int r, *t = ASSERT_PTR(data);
1055
1056 assert(filename);
1057 assert(lvalue);
1058 assert(rvalue);
1059
1060 /* A tristate is pretty much a boolean, except that it can also take an empty string,
1061 * indicating "uninitialized", much like NULL is for a pointer type. */
1062
1063 if (isempty(rvalue)) {
1064 *t = -1;
1065 return 0;
1066 }
1067
1068 r = parse_tristate(rvalue, t);
1069 if (r < 0) {
1070 log_syntax(unit, LOG_WARNING, filename, line, r,
1071 "Failed to parse boolean value for %s=, ignoring: %s", lvalue, rvalue);
1072 return 0;
1073 }
1074
1075 return 0;
1076 }
1077
1078 int config_parse_string(
1079 const char *unit,
1080 const char *filename,
1081 unsigned line,
1082 const char *section,
1083 unsigned section_line,
1084 const char *lvalue,
1085 int ltype,
1086 const char *rvalue,
1087 void *data,
1088 void *userdata) {
1089
1090 char **s = ASSERT_PTR(data);
1091
1092 assert(filename);
1093 assert(lvalue);
1094 assert(rvalue);
1095
1096 if (isempty(rvalue)) {
1097 *s = mfree(*s);
1098 return 0;
1099 }
1100
1101 if (FLAGS_SET(ltype, CONFIG_PARSE_STRING_SAFE) && !string_is_safe(rvalue)) {
1102 _cleanup_free_ char *escaped = NULL;
1103
1104 escaped = cescape(rvalue);
1105 log_syntax(unit, LOG_WARNING, filename, line, 0,
1106 "Specified string contains unsafe characters, ignoring: %s", strna(escaped));
1107 return 0;
1108 }
1109
1110 if (FLAGS_SET(ltype, CONFIG_PARSE_STRING_ASCII) && !ascii_is_valid(rvalue)) {
1111 _cleanup_free_ char *escaped = NULL;
1112
1113 escaped = cescape(rvalue);
1114 log_syntax(unit, LOG_WARNING, filename, line, 0,
1115 "Specified string contains invalid ASCII characters, ignoring: %s", strna(escaped));
1116 return 0;
1117 }
1118
1119 return free_and_strdup_warn(s, empty_to_null(rvalue));
1120 }
1121
1122 int config_parse_dns_name(
1123 const char *unit,
1124 const char *filename,
1125 unsigned line,
1126 const char *section,
1127 unsigned section_line,
1128 const char *lvalue,
1129 int ltype,
1130 const char *rvalue,
1131 void *data,
1132 void *userdata) {
1133
1134 char **hostname = ASSERT_PTR(data);
1135 int r;
1136
1137 assert(filename);
1138 assert(lvalue);
1139 assert(rvalue);
1140
1141 if (isempty(rvalue)) {
1142 *hostname = mfree(*hostname);
1143 return 0;
1144 }
1145
1146 r = dns_name_is_valid(rvalue);
1147 if (r < 0) {
1148 log_syntax(unit, LOG_WARNING, filename, line, r,
1149 "Failed to check validity of DNS domain name '%s', ignoring assignment: %m", rvalue);
1150 return 0;
1151 }
1152 if (r == 0) {
1153 log_syntax(unit, LOG_WARNING, filename, line, 0,
1154 "Specified invalid DNS domain name, ignoring assignment: %s", rvalue);
1155 return 0;
1156 }
1157
1158 return free_and_strdup_warn(hostname, rvalue);
1159 }
1160
1161 int config_parse_hostname(
1162 const char *unit,
1163 const char *filename,
1164 unsigned line,
1165 const char *section,
1166 unsigned section_line,
1167 const char *lvalue,
1168 int ltype,
1169 const char *rvalue,
1170 void *data,
1171 void *userdata) {
1172
1173 char **hostname = ASSERT_PTR(data);
1174
1175 assert(filename);
1176 assert(lvalue);
1177 assert(rvalue);
1178
1179 if (isempty(rvalue)) {
1180 *hostname = mfree(*hostname);
1181 return 0;
1182 }
1183
1184 if (!hostname_is_valid(rvalue, 0)) {
1185 log_syntax(unit, LOG_WARNING, filename, line, 0,
1186 "Specified invalid hostname, ignoring assignment: %s", rvalue);
1187 return 0;
1188 }
1189
1190 return config_parse_dns_name(unit, filename, line, section, section_line,
1191 lvalue, ltype, rvalue, data, userdata);
1192 }
1193
1194 int config_parse_path(
1195 const char *unit,
1196 const char *filename,
1197 unsigned line,
1198 const char *section,
1199 unsigned section_line,
1200 const char *lvalue,
1201 int ltype,
1202 const char *rvalue,
1203 void *data,
1204 void *userdata) {
1205
1206 _cleanup_free_ char *n = NULL;
1207 bool fatal = ltype;
1208 char **s = ASSERT_PTR(data);
1209 int r;
1210
1211 assert(filename);
1212 assert(lvalue);
1213 assert(rvalue);
1214
1215 if (isempty(rvalue))
1216 goto finalize;
1217
1218 n = strdup(rvalue);
1219 if (!n)
1220 return log_oom();
1221
1222 r = path_simplify_and_warn(n, PATH_CHECK_ABSOLUTE | (fatal ? PATH_CHECK_FATAL : 0), unit, filename, line, lvalue);
1223 if (r < 0)
1224 return fatal ? -ENOEXEC : 0;
1225
1226 finalize:
1227 return free_and_replace(*s, n);
1228 }
1229
1230 int config_parse_strv(
1231 const char *unit,
1232 const char *filename,
1233 unsigned line,
1234 const char *section,
1235 unsigned section_line,
1236 const char *lvalue,
1237 int ltype,
1238 const char *rvalue,
1239 void *data,
1240 void *userdata) {
1241
1242 char ***sv = ASSERT_PTR(data);
1243 int r;
1244
1245 assert(filename);
1246 assert(lvalue);
1247 assert(rvalue);
1248
1249 if (isempty(rvalue)) {
1250 *sv = strv_free(*sv);
1251 return 0;
1252 }
1253
1254 for (const char *p = rvalue;;) {
1255 char *word = NULL;
1256
1257 r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
1258 if (r == 0)
1259 return 0;
1260 if (r == -ENOMEM)
1261 return log_oom();
1262 if (r < 0) {
1263 log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
1264 return 0;
1265 }
1266
1267 r = strv_consume(sv, word);
1268 if (r < 0)
1269 return log_oom();
1270 }
1271 }
1272
1273 int config_parse_warn_compat(
1274 const char *unit,
1275 const char *filename,
1276 unsigned line,
1277 const char *section,
1278 unsigned section_line,
1279 const char *lvalue,
1280 int ltype,
1281 const char *rvalue,
1282 void *data,
1283 void *userdata) {
1284
1285 Disabled reason = ltype;
1286
1287 switch (reason) {
1288
1289 case DISABLED_CONFIGURATION:
1290 log_syntax(unit, LOG_DEBUG, filename, line, 0,
1291 "Support for option %s= has been disabled at compile time and it is ignored", lvalue);
1292 break;
1293
1294 case DISABLED_LEGACY:
1295 log_syntax(unit, LOG_INFO, filename, line, 0,
1296 "Support for option %s= has been removed and it is ignored", lvalue);
1297 break;
1298
1299 case DISABLED_EXPERIMENTAL:
1300 log_syntax(unit, LOG_INFO, filename, line, 0,
1301 "Support for option %s= has not yet been enabled and it is ignored", lvalue);
1302 break;
1303 }
1304
1305 return 0;
1306 }
1307
1308 int config_parse_log_facility(
1309 const char *unit,
1310 const char *filename,
1311 unsigned line,
1312 const char *section,
1313 unsigned section_line,
1314 const char *lvalue,
1315 int ltype,
1316 const char *rvalue,
1317 void *data,
1318 void *userdata) {
1319
1320 int *o = data, x;
1321
1322 assert(filename);
1323 assert(lvalue);
1324 assert(rvalue);
1325 assert(data);
1326
1327 x = log_facility_unshifted_from_string(rvalue);
1328 if (x < 0) {
1329 log_syntax(unit, LOG_WARNING, filename, line, x, "Failed to parse log facility, ignoring: %s", rvalue);
1330 return 0;
1331 }
1332
1333 *o = (x << 3) | LOG_PRI(*o);
1334
1335 return 0;
1336 }
1337
1338 int config_parse_log_level(
1339 const char *unit,
1340 const char *filename,
1341 unsigned line,
1342 const char *section,
1343 unsigned section_line,
1344 const char *lvalue,
1345 int ltype,
1346 const char *rvalue,
1347 void *data,
1348 void *userdata) {
1349
1350 int *o = data, x;
1351
1352 assert(filename);
1353 assert(lvalue);
1354 assert(rvalue);
1355 assert(data);
1356
1357 x = log_level_from_string(rvalue);
1358 if (x < 0) {
1359 log_syntax(unit, LOG_WARNING, filename, line, x, "Failed to parse log level, ignoring: %s", rvalue);
1360 return 0;
1361 }
1362
1363 if (*o < 0) /* if it wasn't initialized so far, assume zero facility */
1364 *o = x;
1365 else
1366 *o = (*o & LOG_FACMASK) | x;
1367
1368 return 0;
1369 }
1370
1371 int config_parse_signal(
1372 const char *unit,
1373 const char *filename,
1374 unsigned line,
1375 const char *section,
1376 unsigned section_line,
1377 const char *lvalue,
1378 int ltype,
1379 const char *rvalue,
1380 void *data,
1381 void *userdata) {
1382
1383 int *sig = data, r;
1384
1385 assert(filename);
1386 assert(lvalue);
1387 assert(rvalue);
1388 assert(sig);
1389
1390 r = signal_from_string(rvalue);
1391 if (r <= 0) {
1392 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse signal name, ignoring: %s", rvalue);
1393 return 0;
1394 }
1395
1396 *sig = r;
1397 return 0;
1398 }
1399
1400 int config_parse_personality(
1401 const char *unit,
1402 const char *filename,
1403 unsigned line,
1404 const char *section,
1405 unsigned section_line,
1406 const char *lvalue,
1407 int ltype,
1408 const char *rvalue,
1409 void *data,
1410 void *userdata) {
1411
1412 unsigned long *personality = data, p;
1413
1414 assert(filename);
1415 assert(lvalue);
1416 assert(rvalue);
1417 assert(personality);
1418
1419 if (isempty(rvalue))
1420 p = PERSONALITY_INVALID;
1421 else {
1422 p = personality_from_string(rvalue);
1423 if (p == PERSONALITY_INVALID) {
1424 log_syntax(unit, LOG_WARNING, filename, line, 0, "Failed to parse personality, ignoring: %s", rvalue);
1425 return 0;
1426 }
1427 }
1428
1429 *personality = p;
1430 return 0;
1431 }
1432
1433 int config_parse_ifname(
1434 const char *unit,
1435 const char *filename,
1436 unsigned line,
1437 const char *section,
1438 unsigned section_line,
1439 const char *lvalue,
1440 int ltype,
1441 const char *rvalue,
1442 void *data,
1443 void *userdata) {
1444
1445 char **s = ASSERT_PTR(data);
1446 int r;
1447
1448 assert(filename);
1449 assert(lvalue);
1450 assert(rvalue);
1451
1452 if (isempty(rvalue)) {
1453 *s = mfree(*s);
1454 return 0;
1455 }
1456
1457 if (!ifname_valid(rvalue)) {
1458 log_syntax(unit, LOG_WARNING, filename, line, 0, "Interface name is not valid or too long, ignoring assignment: %s", rvalue);
1459 return 0;
1460 }
1461
1462 r = free_and_strdup(s, rvalue);
1463 if (r < 0)
1464 return log_oom();
1465
1466 return 0;
1467 }
1468
1469 int config_parse_ifnames(
1470 const char *unit,
1471 const char *filename,
1472 unsigned line,
1473 const char *section,
1474 unsigned section_line,
1475 const char *lvalue,
1476 int ltype,
1477 const char *rvalue,
1478 void *data,
1479 void *userdata) {
1480
1481 _cleanup_strv_free_ char **names = NULL;
1482 char ***s = ASSERT_PTR(data);
1483 int r;
1484
1485 assert(filename);
1486 assert(lvalue);
1487 assert(rvalue);
1488
1489 if (isempty(rvalue)) {
1490 *s = strv_free(*s);
1491 return 0;
1492 }
1493
1494 for (const char *p = rvalue;;) {
1495 _cleanup_free_ char *word = NULL;
1496
1497 r = extract_first_word(&p, &word, NULL, 0);
1498 if (r == -ENOMEM)
1499 return log_oom();
1500 if (r < 0) {
1501 log_syntax(unit, LOG_WARNING, filename, line, r,
1502 "Failed to extract interface name, ignoring assignment: %s",
1503 rvalue);
1504 return 0;
1505 }
1506 if (r == 0)
1507 break;
1508
1509 if (!ifname_valid_full(word, ltype)) {
1510 log_syntax(unit, LOG_WARNING, filename, line, 0,
1511 "Interface name is not valid or too long, ignoring assignment: %s",
1512 word);
1513 continue;
1514 }
1515
1516 r = strv_consume(&names, TAKE_PTR(word));
1517 if (r < 0)
1518 return log_oom();
1519 }
1520
1521 r = strv_extend_strv(s, names, true);
1522 if (r < 0)
1523 return log_oom();
1524
1525 return 0;
1526 }
1527
1528 int config_parse_ip_port(
1529 const char *unit,
1530 const char *filename,
1531 unsigned line,
1532 const char *section,
1533 unsigned section_line,
1534 const char *lvalue,
1535 int ltype,
1536 const char *rvalue,
1537 void *data,
1538 void *userdata) {
1539
1540 uint16_t *s = ASSERT_PTR(data);
1541 uint16_t port;
1542 int r;
1543
1544 assert(filename);
1545 assert(lvalue);
1546 assert(rvalue);
1547
1548 if (isempty(rvalue)) {
1549 *s = 0;
1550 return 0;
1551 }
1552
1553 r = parse_ip_port(rvalue, &port);
1554 if (r < 0) {
1555 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse port '%s'.", rvalue);
1556 return 0;
1557 }
1558
1559 *s = port;
1560
1561 return 0;
1562 }
1563
1564 int config_parse_mtu(
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 uint32_t *mtu = ASSERT_PTR(data);
1577 int r;
1578
1579 assert(rvalue);
1580
1581 r = parse_mtu(ltype, rvalue, mtu);
1582 if (r == -ERANGE) {
1583 log_syntax(unit, LOG_WARNING, filename, line, r,
1584 "Maximum transfer unit (MTU) value out of range. Permitted range is %" PRIu32 "…%" PRIu32 ", ignoring: %s",
1585 (uint32_t) (ltype == AF_INET6 ? IPV6_MIN_MTU : IPV4_MIN_MTU), (uint32_t) UINT32_MAX,
1586 rvalue);
1587 return 0;
1588 }
1589 if (r < 0) {
1590 log_syntax(unit, LOG_WARNING, filename, line, r,
1591 "Failed to parse MTU value '%s', ignoring: %m", rvalue);
1592 return 0;
1593 }
1594
1595 return 0;
1596 }
1597
1598 int config_parse_rlimit(
1599 const char *unit,
1600 const char *filename,
1601 unsigned line,
1602 const char *section,
1603 unsigned section_line,
1604 const char *lvalue,
1605 int ltype,
1606 const char *rvalue,
1607 void *data,
1608 void *userdata) {
1609
1610 struct rlimit **rl = data, d = {};
1611 int r;
1612
1613 assert(rvalue);
1614 assert(rl);
1615
1616 r = rlimit_parse(ltype, rvalue, &d);
1617 if (r == -EILSEQ) {
1618 log_syntax(unit, LOG_WARNING, filename, line, r, "Soft resource limit chosen higher than hard limit, ignoring: %s", rvalue);
1619 return 0;
1620 }
1621 if (r < 0) {
1622 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue);
1623 return 0;
1624 }
1625
1626 if (rl[ltype])
1627 *rl[ltype] = d;
1628 else {
1629 rl[ltype] = newdup(struct rlimit, &d, 1);
1630 if (!rl[ltype])
1631 return log_oom();
1632 }
1633
1634 return 0;
1635 }
1636
1637 int config_parse_permille(
1638 const char* unit,
1639 const char *filename,
1640 unsigned line,
1641 const char *section,
1642 unsigned section_line,
1643 const char *lvalue,
1644 int ltype,
1645 const char *rvalue,
1646 void *data,
1647 void *userdata) {
1648
1649 unsigned *permille = ASSERT_PTR(data);
1650 int r;
1651
1652 assert(filename);
1653 assert(lvalue);
1654 assert(rvalue);
1655
1656 r = parse_permille(rvalue);
1657 if (r < 0) {
1658 log_syntax(unit, LOG_WARNING, filename, line, r,
1659 "Failed to parse permille value, ignoring: %s", rvalue);
1660 return 0;
1661 }
1662
1663 *permille = (unsigned) r;
1664
1665 return 0;
1666 }
1667
1668 int config_parse_vlanprotocol(
1669 const char* unit,
1670 const char *filename,
1671 unsigned line,
1672 const char *section,
1673 unsigned section_line,
1674 const char *lvalue,
1675 int ltype,
1676 const char *rvalue,
1677 void *data,
1678 void *userdata) {
1679
1680 int *vlan_protocol = data;
1681
1682 assert(filename);
1683 assert(lvalue);
1684
1685 if (isempty(rvalue)) {
1686 *vlan_protocol = -1;
1687 return 0;
1688 }
1689
1690 if (STR_IN_SET(rvalue, "802.1ad", "802.1AD"))
1691 *vlan_protocol = ETH_P_8021AD;
1692 else if (STR_IN_SET(rvalue, "802.1q", "802.1Q"))
1693 *vlan_protocol = ETH_P_8021Q;
1694 else {
1695 log_syntax(unit, LOG_WARNING, filename, line, 0,
1696 "Failed to parse VLAN protocol value, ignoring: %s", rvalue);
1697 return 0;
1698 }
1699
1700 return 0;
1701 }
1702
1703 int config_parse_hw_addr(
1704 const char *unit,
1705 const char *filename,
1706 unsigned line,
1707 const char *section,
1708 unsigned section_line,
1709 const char *lvalue,
1710 int ltype,
1711 const char *rvalue,
1712 void *data,
1713 void *userdata) {
1714
1715 struct hw_addr_data a, *hwaddr = ASSERT_PTR(data);
1716 int r;
1717
1718 assert(filename);
1719 assert(lvalue);
1720 assert(rvalue);
1721
1722 if (isempty(rvalue)) {
1723 *hwaddr = HW_ADDR_NULL;
1724 return 0;
1725 }
1726
1727 r = parse_hw_addr_full(rvalue, ltype, &a);
1728 if (r < 0) {
1729 log_syntax(unit, LOG_WARNING, filename, line, r,
1730 "Not a valid hardware address, ignoring assignment: %s", rvalue);
1731 return 0;
1732 }
1733
1734 *hwaddr = a;
1735 return 0;
1736 }
1737
1738 int config_parse_hw_addrs(
1739 const char *unit,
1740 const char *filename,
1741 unsigned line,
1742 const char *section,
1743 unsigned section_line,
1744 const char *lvalue,
1745 int ltype,
1746 const char *rvalue,
1747 void *data,
1748 void *userdata) {
1749
1750 Set **hwaddrs = ASSERT_PTR(data);
1751 int r;
1752
1753 assert(filename);
1754 assert(lvalue);
1755 assert(rvalue);
1756
1757 if (isempty(rvalue)) {
1758 /* Empty assignment resets the list */
1759 *hwaddrs = set_free(*hwaddrs);
1760 return 0;
1761 }
1762
1763 for (const char *p = rvalue;;) {
1764 _cleanup_free_ char *word = NULL;
1765 _cleanup_free_ struct hw_addr_data *n = NULL;
1766
1767 r = extract_first_word(&p, &word, NULL, 0);
1768 if (r == 0)
1769 return 0;
1770 if (r == -ENOMEM)
1771 return log_oom();
1772 if (r < 0) {
1773 log_syntax(unit, LOG_WARNING, filename, line, r,
1774 "Invalid syntax, ignoring: %s", rvalue);
1775 return 0;
1776 }
1777
1778 n = new(struct hw_addr_data, 1);
1779 if (!n)
1780 return log_oom();
1781
1782 r = parse_hw_addr_full(word, ltype, n);
1783 if (r < 0) {
1784 log_syntax(unit, LOG_WARNING, filename, line, r,
1785 "Not a valid hardware address, ignoring: %s", word);
1786 continue;
1787 }
1788
1789 r = set_ensure_consume(hwaddrs, &hw_addr_hash_ops_free, TAKE_PTR(n));
1790 if (r < 0)
1791 return log_oom();
1792 }
1793 }
1794
1795 int config_parse_ether_addr(
1796 const char *unit,
1797 const char *filename,
1798 unsigned line,
1799 const char *section,
1800 unsigned section_line,
1801 const char *lvalue,
1802 int ltype,
1803 const char *rvalue,
1804 void *data,
1805 void *userdata) {
1806
1807 _cleanup_free_ struct ether_addr *n = NULL;
1808 struct ether_addr **hwaddr = ASSERT_PTR(data);
1809 int r;
1810
1811 assert(filename);
1812 assert(lvalue);
1813 assert(rvalue);
1814
1815 if (isempty(rvalue)) {
1816 *hwaddr = mfree(*hwaddr);
1817 return 0;
1818 }
1819
1820 n = new0(struct ether_addr, 1);
1821 if (!n)
1822 return log_oom();
1823
1824 r = parse_ether_addr(rvalue, n);
1825 if (r < 0) {
1826 log_syntax(unit, LOG_WARNING, filename, line, r,
1827 "Not a valid MAC address, ignoring assignment: %s", rvalue);
1828 return 0;
1829 }
1830
1831 free_and_replace(*hwaddr, n);
1832
1833 return 0;
1834 }
1835
1836 int config_parse_ether_addrs(
1837 const char *unit,
1838 const char *filename,
1839 unsigned line,
1840 const char *section,
1841 unsigned section_line,
1842 const char *lvalue,
1843 int ltype,
1844 const char *rvalue,
1845 void *data,
1846 void *userdata) {
1847
1848 Set **hwaddrs = ASSERT_PTR(data);
1849 int r;
1850
1851 assert(filename);
1852 assert(lvalue);
1853 assert(rvalue);
1854
1855 if (isempty(rvalue)) {
1856 /* Empty assignment resets the list */
1857 *hwaddrs = set_free(*hwaddrs);
1858 return 0;
1859 }
1860
1861 for (const char *p = rvalue;;) {
1862 _cleanup_free_ char *word = NULL;
1863 _cleanup_free_ struct ether_addr *n = NULL;
1864
1865 r = extract_first_word(&p, &word, NULL, 0);
1866 if (r == 0)
1867 return 0;
1868 if (r == -ENOMEM)
1869 return log_oom();
1870 if (r < 0) {
1871 log_syntax(unit, LOG_WARNING, filename, line, r,
1872 "Invalid syntax, ignoring: %s", rvalue);
1873 return 0;
1874 }
1875
1876 n = new(struct ether_addr, 1);
1877 if (!n)
1878 return log_oom();
1879
1880 r = parse_ether_addr(word, n);
1881 if (r < 0) {
1882 log_syntax(unit, LOG_WARNING, filename, line, r,
1883 "Not a valid MAC address, ignoring: %s", word);
1884 continue;
1885 }
1886
1887 r = set_ensure_consume(hwaddrs, &ether_addr_hash_ops_free, TAKE_PTR(n));
1888 if (r < 0)
1889 return log_oom();
1890 }
1891 }
1892
1893 int config_parse_in_addr_non_null(
1894 const char *unit,
1895 const char *filename,
1896 unsigned line,
1897 const char *section,
1898 unsigned section_line,
1899 const char *lvalue,
1900 int ltype,
1901 const char *rvalue,
1902 void *data,
1903 void *userdata) {
1904
1905 /* data must be a pointer to struct in_addr or in6_addr, and the type is determined by ltype. */
1906 struct in_addr *ipv4 = ASSERT_PTR(data);
1907 struct in6_addr *ipv6 = ASSERT_PTR(data);
1908 union in_addr_union a;
1909 int r;
1910
1911 assert(filename);
1912 assert(lvalue);
1913 assert(rvalue);
1914 assert(IN_SET(ltype, AF_INET, AF_INET6));
1915
1916 if (isempty(rvalue)) {
1917 if (ltype == AF_INET)
1918 *ipv4 = (struct in_addr) {};
1919 else
1920 *ipv6 = (struct in6_addr) {};
1921 return 0;
1922 }
1923
1924 r = in_addr_from_string(ltype, rvalue, &a);
1925 if (r < 0) {
1926 log_syntax(unit, LOG_WARNING, filename, line, r,
1927 "Failed to parse %s=, ignoring assignment: %s", lvalue, rvalue);
1928 return 0;
1929 }
1930
1931 if (!in_addr_is_set(ltype, &a)) {
1932 log_syntax(unit, LOG_WARNING, filename, line, 0,
1933 "%s= cannot be the ANY address, ignoring: %s", lvalue, rvalue);
1934 return 0;
1935 }
1936
1937 if (ltype == AF_INET)
1938 *ipv4 = a.in;
1939 else
1940 *ipv6 = a.in6;
1941 return 0;
1942 }
1943
1944 int config_parse_unsigned_bounded(
1945 const char *unit,
1946 const char *filename,
1947 unsigned line,
1948 const char *section,
1949 unsigned section_line,
1950 const char *name,
1951 const char *value,
1952 unsigned min,
1953 unsigned max,
1954 bool ignoring,
1955 unsigned *ret) {
1956
1957 int r;
1958
1959 assert(filename);
1960 assert(name);
1961 assert(value);
1962 assert(ret);
1963
1964 r = safe_atou_bounded(value, min, max, ret);
1965 if (r == -ERANGE)
1966 log_syntax(unit, LOG_WARNING, filename, line, r,
1967 "Invalid '%s=%s', allowed range is %u..%u%s.",
1968 name, value, min, max, ignoring ? ", ignoring" : "");
1969 else if (r < 0)
1970 log_syntax(unit, LOG_WARNING, filename, line, r,
1971 "Failed to parse '%s=%s'%s: %m",
1972 name, value, ignoring ? ", ignoring" : "");
1973
1974 if (r >= 0)
1975 return 1; /* Return 1 if something was set */
1976 else if (ignoring)
1977 return 0;
1978 else
1979 return r;
1980 }
1981
1982 DEFINE_CONFIG_PARSE(config_parse_percent, parse_percent, "Failed to parse percent value");
1983 DEFINE_CONFIG_PARSE(config_parse_permyriad, parse_permyriad, "Failed to parse permyriad value");
1984 DEFINE_CONFIG_PARSE_PTR(config_parse_sec_fix_0, parse_sec_fix_0, usec_t, "Failed to parse time value");