1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
10 #include "alloc-util.h"
11 #include "conf-files.h"
12 #include "conf-parser.h"
14 #include "dns-domain.h"
16 #include "ether-addr-util.h"
17 #include "extract-word.h"
21 #include "hostname-util.h"
22 #include "in-addr-util.h"
25 #include "missing_network.h"
26 #include "nulstr-util.h"
27 #include "parse-util.h"
28 #include "path-util.h"
29 #include "percent-util.h"
30 #include "process-util.h"
31 #include "rlimit-util.h"
34 #include "signal-util.h"
35 #include "socket-util.h"
36 #include "string-util.h"
38 #include "syslog-util.h"
39 #include "time-util.h"
42 int config_item_table_lookup(
46 ConfigParserCallback
*ret_func
,
51 const ConfigTableItem
*t
;
59 for (t
= table
; t
->lvalue
; t
++) {
61 if (!streq(lvalue
, t
->lvalue
))
64 if (!streq_ptr(section
, t
->section
))
68 *ret_ltype
= t
->ltype
;
79 int config_item_perf_lookup(
83 ConfigParserCallback
*ret_func
,
88 ConfigPerfItemLookup lookup
= (ConfigPerfItemLookup
) table
;
89 const ConfigPerfItem
*p
;
100 key
= strjoina(section
, ".", lvalue
);
101 p
= lookup(key
, strlen(key
));
103 p
= lookup(lvalue
, strlen(lvalue
));
111 *ret_func
= p
->parse
;
112 *ret_ltype
= p
->ltype
;
113 *ret_data
= (uint8_t*) userdata
+ p
->offset
;
117 /* Run the user supplied parser for an assignment */
118 static int next_assignment(
120 const char *filename
,
122 ConfigItemLookup lookup
,
125 unsigned section_line
,
128 ConfigParseFlags flags
,
131 ConfigParserCallback func
= NULL
;
142 r
= lookup(table
, section
, lvalue
, &func
, <ype
, &data
, userdata
);
149 return func(unit
, filename
, line
, section
, section_line
,
150 lvalue
, ltype
, rvalue
, data
, userdata
);
153 /* Warn about unknown non-extension fields. */
154 if (!(flags
& CONFIG_PARSE_RELAXED
) && !startswith(lvalue
, "X-"))
155 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
156 "Unknown key name '%s' in section '%s', ignoring.", lvalue
, section
);
161 /* Parse a single logical line */
162 static int parse_line(
164 const char *filename
,
166 const char *sections
,
167 ConfigItemLookup lookup
,
169 ConfigParseFlags flags
,
171 unsigned *section_line
,
172 bool *section_ignored
,
173 char *l
, /* is modified */
190 if (!utf8_is_valid(l
))
191 return log_syntax_invalid_utf8(unit
, LOG_WARNING
, filename
, line
, l
);
194 _cleanup_free_
char *n
= NULL
;
201 return log_syntax(unit
, LOG_ERR
, filename
, line
, SYNTHETIC_ERRNO(EBADMSG
), "Invalid section header '%s'", l
);
203 n
= strndup(l
+1, k
-2);
207 if (!string_is_safe(n
))
208 return log_syntax(unit
, LOG_ERR
, filename
, line
, SYNTHETIC_ERRNO(EBADMSG
), "Bad characters in section header '%s'", l
);
210 if (sections
&& !nulstr_contains(sections
, n
)) {
214 ignore
= (flags
& CONFIG_PARSE_RELAXED
) || startswith(n
, "X-");
217 NULSTR_FOREACH(t
, sections
)
218 if (streq_ptr(n
, startswith(t
, "-"))) { /* Ignore sections prefixed with "-" in valid section list */
224 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Unknown section '%s'. Ignoring.", n
);
226 *section
= mfree(*section
);
228 *section_ignored
= true;
230 free_and_replace(*section
, n
);
231 *section_line
= line
;
232 *section_ignored
= false;
238 if (sections
&& !*section
) {
239 if (!(flags
& CONFIG_PARSE_RELAXED
) && !*section_ignored
)
240 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Assignment outside of section. Ignoring.");
247 return log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
248 "Missing '=', ignoring line.");
250 return log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
251 "Missing key name before '=', ignoring line.");
256 return next_assignment(unit
,
269 /* Go through the file and parse each line */
272 const char *filename
,
274 const char *sections
,
275 ConfigItemLookup lookup
,
277 ConfigParseFlags flags
,
279 struct stat
*ret_stat
) {
281 _cleanup_free_
char *section
= NULL
, *continuation
= NULL
;
282 _cleanup_fclose_
FILE *ours
= NULL
;
283 unsigned line
= 0, section_line
= 0;
284 bool section_ignored
= false, bom_seen
= false;
292 f
= ours
= fopen(filename
, "re");
294 /* Only log on request, except for ENOENT,
295 * since we return 0 to the caller. */
296 if ((flags
& CONFIG_PARSE_WARN
) || errno
== ENOENT
)
297 log_full_errno(errno
== ENOENT
? LOG_DEBUG
: LOG_ERR
, errno
,
298 "Failed to open configuration file '%s': %m", filename
);
300 if (errno
== ENOENT
) {
302 *ret_stat
= (struct stat
) {};
312 if (fd
>= 0) { /* stream might not have an fd, let's be careful hence */
314 if (fstat(fd
, &st
) < 0)
315 return log_full_errno(FLAGS_SET(flags
, CONFIG_PARSE_WARN
) ? LOG_ERR
: LOG_DEBUG
, errno
,
316 "Failed to fstat(%s): %m", filename
);
318 (void) stat_warn_permissions(filename
, &st
);
320 st
= (struct stat
) {};
323 _cleanup_free_
char *buf
= NULL
;
324 bool escaped
= false;
327 r
= read_line(f
, LONG_LINE_MAX
, &buf
);
331 if (flags
& CONFIG_PARSE_WARN
)
332 log_error_errno(r
, "%s:%u: Line too long", filename
, line
);
337 if (FLAGS_SET(flags
, CONFIG_PARSE_WARN
))
338 log_error_errno(r
, "%s:%u: Error while reading configuration file: %m", filename
, line
);
345 l
= skip_leading_chars(buf
, WHITESPACE
);
346 if (*l
!= '\0' && strchr(COMMENTS
, *l
))
353 q
= startswith(buf
, UTF8_BYTE_ORDER_MARK
);
361 if (strlen(continuation
) + strlen(l
) > LONG_LINE_MAX
) {
362 if (flags
& CONFIG_PARSE_WARN
)
363 log_error("%s:%u: Continuation line too long", filename
, line
);
367 if (!strextend(&continuation
, l
)) {
368 if (flags
& CONFIG_PARSE_WARN
)
377 for (e
= p
; *e
; e
++) {
388 continuation
= strdup(l
);
390 if (flags
& CONFIG_PARSE_WARN
)
412 if (flags
& CONFIG_PARSE_WARN
)
413 log_warning_errno(r
, "%s:%u: Failed to parse file: %m", filename
, line
);
417 continuation
= mfree(continuation
);
434 if (flags
& CONFIG_PARSE_WARN
)
435 log_warning_errno(r
, "%s:%u: Failed to parse file: %m", filename
, line
);
446 static int hashmap_put_stats_by_path(Hashmap
**stats_by_path
, const char *path
, const struct stat
*st
) {
447 _cleanup_free_
struct stat
*st_copy
= NULL
;
448 _cleanup_free_
char *path_copy
= NULL
;
451 assert(stats_by_path
);
455 r
= hashmap_ensure_allocated(stats_by_path
, &path_hash_ops_free_free
);
459 st_copy
= newdup(struct stat
, st
, 1);
463 path_copy
= strdup(path
);
467 r
= hashmap_put(*stats_by_path
, path_copy
, st_copy
);
477 static int config_parse_many_files(
478 const char* const* conf_files
,
480 const char *sections
,
481 ConfigItemLookup lookup
,
483 ConfigParseFlags flags
,
485 Hashmap
**ret_stats_by_path
) {
487 _cleanup_hashmap_free_ Hashmap
*stats_by_path
= NULL
;
492 if (ret_stats_by_path
) {
493 stats_by_path
= hashmap_new(&path_hash_ops_free_free
);
498 /* First read the first found main config file. */
499 STRV_FOREACH(fn
, (char**) conf_files
) {
500 r
= config_parse(NULL
, *fn
, NULL
, sections
, lookup
, table
, flags
, userdata
, &st
);
506 if (ret_stats_by_path
) {
507 r
= hashmap_put_stats_by_path(&stats_by_path
, *fn
, &st
);
515 /* Then read all the drop-ins. */
516 STRV_FOREACH(fn
, files
) {
517 r
= config_parse(NULL
, *fn
, NULL
, sections
, lookup
, table
, flags
, userdata
, &st
);
523 if (ret_stats_by_path
) {
524 r
= hashmap_put_stats_by_path(&stats_by_path
, *fn
, &st
);
530 if (ret_stats_by_path
)
531 *ret_stats_by_path
= TAKE_PTR(stats_by_path
);
536 /* Parse each config file in the directories specified as nulstr. */
537 int config_parse_many_nulstr(
538 const char *conf_file
,
539 const char *conf_file_dirs
,
540 const char *sections
,
541 ConfigItemLookup lookup
,
543 ConfigParseFlags flags
,
545 Hashmap
**ret_stats_by_path
) {
547 _cleanup_strv_free_
char **files
= NULL
;
550 r
= conf_files_list_nulstr(&files
, ".conf", NULL
, 0, conf_file_dirs
);
554 return config_parse_many_files(STRV_MAKE_CONST(conf_file
),
555 files
, sections
, lookup
, table
, flags
, userdata
,
559 /* Parse each config file in the directories specified as strv. */
560 int config_parse_many(
561 const char* const* conf_files
,
562 const char* const* conf_file_dirs
,
563 const char *dropin_dirname
,
564 const char *sections
,
565 ConfigItemLookup lookup
,
567 ConfigParseFlags flags
,
569 Hashmap
**ret_stats_by_path
) {
571 _cleanup_strv_free_
char **dropin_dirs
= NULL
;
572 _cleanup_strv_free_
char **files
= NULL
;
576 suffix
= strjoina("/", dropin_dirname
);
577 r
= strv_extend_strv_concat(&dropin_dirs
, (char**) conf_file_dirs
, suffix
);
581 r
= conf_files_list_strv(&files
, ".conf", NULL
, 0, (const char* const*) dropin_dirs
);
585 return config_parse_many_files(conf_files
, files
, sections
, lookup
, table
, flags
, userdata
, ret_stats_by_path
);
588 static void config_section_hash_func(const ConfigSection
*c
, struct siphash
*state
) {
589 siphash24_compress_string(c
->filename
, state
);
590 siphash24_compress(&c
->line
, sizeof(c
->line
), state
);
593 static int config_section_compare_func(const ConfigSection
*x
, const ConfigSection
*y
) {
596 r
= strcmp(x
->filename
, y
->filename
);
600 return CMP(x
->line
, y
->line
);
603 DEFINE_HASH_OPS(config_section_hash_ops
, ConfigSection
, config_section_hash_func
, config_section_compare_func
);
605 int config_section_new(const char *filename
, unsigned line
, ConfigSection
**s
) {
608 cs
= malloc0(offsetof(ConfigSection
, filename
) + strlen(filename
) + 1);
612 strcpy(cs
->filename
, filename
);
620 unsigned hashmap_find_free_section_line(Hashmap
*hashmap
) {
625 HASHMAP_FOREACH_KEY(entry
, cs
, hashmap
)
632 #define DEFINE_PARSER(type, vartype, conv_func) \
633 DEFINE_CONFIG_PARSE_PTR(config_parse_##type, conv_func, vartype, "Failed to parse " #type " value")
635 DEFINE_PARSER(int, int, safe_atoi
);
636 DEFINE_PARSER(long, long, safe_atoli
);
637 DEFINE_PARSER(uint8
, uint8_t, safe_atou8
);
638 DEFINE_PARSER(uint16
, uint16_t, safe_atou16
);
639 DEFINE_PARSER(uint32
, uint32_t, safe_atou32
);
640 DEFINE_PARSER(int32
, int32_t, safe_atoi32
);
641 DEFINE_PARSER(uint64
, uint64_t, safe_atou64
);
642 DEFINE_PARSER(unsigned, unsigned, safe_atou
);
643 DEFINE_PARSER(double, double, safe_atod
);
644 DEFINE_PARSER(nsec
, nsec_t
, parse_nsec
);
645 DEFINE_PARSER(sec
, usec_t
, parse_sec
);
646 DEFINE_PARSER(sec_def_infinity
, usec_t
, parse_sec_def_infinity
);
647 DEFINE_PARSER(mode
, mode_t
, parse_mode
);
648 DEFINE_PARSER(pid
, pid_t
, parse_pid
);
650 int config_parse_iec_size(
652 const char *filename
,
655 unsigned section_line
,
671 r
= parse_size(rvalue
, 1024, &v
);
672 if (r
>= 0 && (uint64_t) (size_t) v
!= v
)
675 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to parse size value '%s', ignoring: %m", rvalue
);
683 int config_parse_si_uint64(
685 const char *filename
,
688 unsigned section_line
,
703 r
= parse_size(rvalue
, 1000, sz
);
705 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to parse size value '%s', ignoring: %m", rvalue
);
710 int config_parse_iec_uint64(
712 const char *filename
,
715 unsigned section_line
,
722 uint64_t *bytes
= data
;
730 r
= parse_size(rvalue
, 1024, bytes
);
732 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to parse size value, ignoring: %s", rvalue
);
737 int config_parse_iec_uint64_infinity(
739 const char *filename
,
742 unsigned section_line
,
749 uint64_t *bytes
= data
;
754 if (streq(rvalue
, "infinity")) {
759 return config_parse_iec_uint64(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, rvalue
, data
, userdata
);
762 int config_parse_bool(
764 const char *filename
,
767 unsigned section_line
,
783 k
= parse_boolean(rvalue
);
785 log_syntax(unit
, fatal
? LOG_ERR
: LOG_WARNING
, filename
, line
, k
,
786 "Failed to parse boolean value%s: %s",
787 fatal
? "" : ", ignoring", rvalue
);
788 return fatal
? -ENOEXEC
: 0;
795 int config_parse_id128(
797 const char *filename
,
800 unsigned section_line
,
807 sd_id128_t t
, *result
= data
;
814 r
= sd_id128_from_string(rvalue
, &t
);
816 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to parse 128bit ID/UUID, ignoring: %s", rvalue
);
820 if (sd_id128_is_null(t
)) {
821 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "128bit ID/UUID is all 0, ignoring: %s", rvalue
);
829 int config_parse_tristate(
831 const char *filename
,
834 unsigned section_line
,
848 /* A tristate is pretty much a boolean, except that it can also take an empty string,
849 * indicating "uninitialized", much like NULL is for a pointer type. */
851 if (isempty(rvalue
)) {
856 k
= parse_boolean(rvalue
);
858 log_syntax(unit
, LOG_WARNING
, filename
, line
, k
,
859 "Failed to parse boolean value for %s=, ignoring: %s", lvalue
, rvalue
);
867 int config_parse_string(
869 const char *filename
,
872 unsigned section_line
,
879 char **s
= ASSERT_PTR(data
);
885 if (isempty(rvalue
)) {
890 if (FLAGS_SET(ltype
, CONFIG_PARSE_STRING_SAFE
) && !string_is_safe(rvalue
)) {
891 _cleanup_free_
char *escaped
= NULL
;
893 escaped
= cescape(rvalue
);
894 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
895 "Specified string contains unsafe characters, ignoring: %s", strna(escaped
));
899 if (FLAGS_SET(ltype
, CONFIG_PARSE_STRING_ASCII
) && !ascii_is_valid(rvalue
)) {
900 _cleanup_free_
char *escaped
= NULL
;
902 escaped
= cescape(rvalue
);
903 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
904 "Specified string contains invalid ASCII characters, ignoring: %s", strna(escaped
));
908 return free_and_strdup_warn(s
, empty_to_null(rvalue
));
911 int config_parse_dns_name(
913 const char *filename
,
916 unsigned section_line
,
923 char **hostname
= ASSERT_PTR(data
);
930 if (isempty(rvalue
)) {
931 *hostname
= mfree(*hostname
);
935 r
= dns_name_is_valid(rvalue
);
937 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
938 "Failed to check validity of DNS domain name '%s', ignoring assignment: %m", rvalue
);
942 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
943 "Specified invalid DNS domain name, ignoring assignment: %s", rvalue
);
947 return free_and_strdup_warn(hostname
, rvalue
);
950 int config_parse_hostname(
952 const char *filename
,
955 unsigned section_line
,
962 char **hostname
= ASSERT_PTR(data
);
968 if (isempty(rvalue
)) {
969 *hostname
= mfree(*hostname
);
973 if (!hostname_is_valid(rvalue
, 0)) {
974 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
975 "Specified invalid hostname, ignoring assignment: %s", rvalue
);
979 return config_parse_dns_name(unit
, filename
, line
, section
, section_line
,
980 lvalue
, ltype
, rvalue
, data
, userdata
);
983 int config_parse_path(
985 const char *filename
,
988 unsigned section_line
,
995 _cleanup_free_
char *n
= NULL
;
1005 if (isempty(rvalue
))
1012 r
= path_simplify_and_warn(n
, PATH_CHECK_ABSOLUTE
| (fatal
? PATH_CHECK_FATAL
: 0), unit
, filename
, line
, lvalue
);
1014 return fatal
? -ENOEXEC
: 0;
1017 return free_and_replace(*s
, n
);
1020 int config_parse_strv(
1022 const char *filename
,
1024 const char *section
,
1025 unsigned section_line
,
1040 if (isempty(rvalue
)) {
1041 *sv
= strv_free(*sv
);
1045 for (const char *p
= rvalue
;;) {
1048 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_UNQUOTE
|EXTRACT_RETAIN_ESCAPE
);
1054 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Invalid syntax, ignoring: %s", rvalue
);
1058 r
= strv_consume(sv
, word
);
1064 int config_parse_warn_compat(
1066 const char *filename
,
1068 const char *section
,
1069 unsigned section_line
,
1076 Disabled reason
= ltype
;
1080 case DISABLED_CONFIGURATION
:
1081 log_syntax(unit
, LOG_DEBUG
, filename
, line
, 0,
1082 "Support for option %s= has been disabled at compile time and it is ignored", lvalue
);
1085 case DISABLED_LEGACY
:
1086 log_syntax(unit
, LOG_INFO
, filename
, line
, 0,
1087 "Support for option %s= has been removed and it is ignored", lvalue
);
1090 case DISABLED_EXPERIMENTAL
:
1091 log_syntax(unit
, LOG_INFO
, filename
, line
, 0,
1092 "Support for option %s= has not yet been enabled and it is ignored", lvalue
);
1099 int config_parse_log_facility(
1101 const char *filename
,
1103 const char *section
,
1104 unsigned section_line
,
1118 x
= log_facility_unshifted_from_string(rvalue
);
1120 log_syntax(unit
, LOG_WARNING
, filename
, line
, x
, "Failed to parse log facility, ignoring: %s", rvalue
);
1124 *o
= (x
<< 3) | LOG_PRI(*o
);
1129 int config_parse_log_level(
1131 const char *filename
,
1133 const char *section
,
1134 unsigned section_line
,
1148 x
= log_level_from_string(rvalue
);
1150 log_syntax(unit
, LOG_WARNING
, filename
, line
, x
, "Failed to parse log level, ignoring: %s", rvalue
);
1154 if (*o
< 0) /* if it wasn't initialized so far, assume zero facility */
1157 *o
= (*o
& LOG_FACMASK
) | x
;
1162 int config_parse_signal(
1164 const char *filename
,
1166 const char *section
,
1167 unsigned section_line
,
1181 r
= signal_from_string(rvalue
);
1183 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to parse signal name, ignoring: %s", rvalue
);
1191 int config_parse_personality(
1193 const char *filename
,
1195 const char *section
,
1196 unsigned section_line
,
1203 unsigned long *personality
= data
, p
;
1208 assert(personality
);
1210 if (isempty(rvalue
))
1211 p
= PERSONALITY_INVALID
;
1213 p
= personality_from_string(rvalue
);
1214 if (p
== PERSONALITY_INVALID
) {
1215 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Failed to parse personality, ignoring: %s", rvalue
);
1224 int config_parse_ifname(
1226 const char *filename
,
1228 const char *section
,
1229 unsigned section_line
,
1244 if (isempty(rvalue
)) {
1249 if (!ifname_valid(rvalue
)) {
1250 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Interface name is not valid or too long, ignoring assignment: %s", rvalue
);
1254 r
= free_and_strdup(s
, rvalue
);
1261 int config_parse_ifnames(
1263 const char *filename
,
1265 const char *section
,
1266 unsigned section_line
,
1273 _cleanup_strv_free_
char **names
= NULL
;
1282 if (isempty(rvalue
)) {
1287 for (const char *p
= rvalue
;;) {
1288 _cleanup_free_
char *word
= NULL
;
1290 r
= extract_first_word(&p
, &word
, NULL
, 0);
1294 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1295 "Failed to extract interface name, ignoring assignment: %s",
1302 if (!ifname_valid_full(word
, ltype
)) {
1303 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1304 "Interface name is not valid or too long, ignoring assignment: %s",
1309 r
= strv_consume(&names
, TAKE_PTR(word
));
1314 r
= strv_extend_strv(s
, names
, true);
1321 int config_parse_ip_port(
1323 const char *filename
,
1325 const char *section
,
1326 unsigned section_line
,
1342 if (isempty(rvalue
)) {
1347 r
= parse_ip_port(rvalue
, &port
);
1349 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to parse port '%s'.", rvalue
);
1358 int config_parse_mtu(
1360 const char *filename
,
1362 const char *section
,
1363 unsigned section_line
,
1370 uint32_t *mtu
= data
;
1376 r
= parse_mtu(ltype
, rvalue
, mtu
);
1378 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1379 "Maximum transfer unit (MTU) value out of range. Permitted range is %" PRIu32
"…%" PRIu32
", ignoring: %s",
1380 (uint32_t) (ltype
== AF_INET6
? IPV6_MIN_MTU
: IPV4_MIN_MTU
), (uint32_t) UINT32_MAX
,
1385 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1386 "Failed to parse MTU value '%s', ignoring: %m", rvalue
);
1393 int config_parse_rlimit(
1395 const char *filename
,
1397 const char *section
,
1398 unsigned section_line
,
1405 struct rlimit
**rl
= data
, d
= {};
1411 r
= rlimit_parse(ltype
, rvalue
, &d
);
1413 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Soft resource limit chosen higher than hard limit, ignoring: %s", rvalue
);
1417 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to parse resource value, ignoring: %s", rvalue
);
1424 rl
[ltype
] = newdup(struct rlimit
, &d
, 1);
1432 int config_parse_permille(
1434 const char *filename
,
1436 const char *section
,
1437 unsigned section_line
,
1444 unsigned *permille
= data
;
1452 r
= parse_permille(rvalue
);
1454 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1455 "Failed to parse permille value, ignoring: %s", rvalue
);
1459 *permille
= (unsigned) r
;
1464 int config_parse_vlanprotocol(
1466 const char *filename
,
1468 const char *section
,
1469 unsigned section_line
,
1476 int *vlan_protocol
= data
;
1481 if (isempty(rvalue
)) {
1482 *vlan_protocol
= -1;
1486 if (STR_IN_SET(rvalue
, "802.1ad", "802.1AD"))
1487 *vlan_protocol
= ETH_P_8021AD
;
1488 else if (STR_IN_SET(rvalue
, "802.1q", "802.1Q"))
1489 *vlan_protocol
= ETH_P_8021Q
;
1491 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1492 "Failed to parse VLAN protocol value, ignoring: %s", rvalue
);
1499 int config_parse_hw_addr(
1501 const char *filename
,
1503 const char *section
,
1504 unsigned section_line
,
1511 struct hw_addr_data a
, *hwaddr
= data
;
1519 if (isempty(rvalue
)) {
1520 *hwaddr
= HW_ADDR_NULL
;
1524 r
= parse_hw_addr_full(rvalue
, ltype
, &a
);
1526 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1527 "Not a valid hardware address, ignoring assignment: %s", rvalue
);
1535 int config_parse_hw_addrs(
1537 const char *filename
,
1539 const char *section
,
1540 unsigned section_line
,
1547 Set
**hwaddrs
= data
;
1555 if (isempty(rvalue
)) {
1556 /* Empty assignment resets the list */
1557 *hwaddrs
= set_free(*hwaddrs
);
1561 for (const char *p
= rvalue
;;) {
1562 _cleanup_free_
char *word
= NULL
;
1563 _cleanup_free_
struct hw_addr_data
*n
= NULL
;
1565 r
= extract_first_word(&p
, &word
, NULL
, 0);
1571 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1572 "Invalid syntax, ignoring: %s", rvalue
);
1576 n
= new(struct hw_addr_data
, 1);
1580 r
= parse_hw_addr_full(word
, ltype
, n
);
1582 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1583 "Not a valid hardware address, ignoring: %s", word
);
1587 r
= set_ensure_consume(hwaddrs
, &hw_addr_hash_ops_free
, TAKE_PTR(n
));
1593 int config_parse_ether_addr(
1595 const char *filename
,
1597 const char *section
,
1598 unsigned section_line
,
1605 _cleanup_free_
struct ether_addr
*n
= NULL
;
1606 struct ether_addr
**hwaddr
= data
;
1614 if (isempty(rvalue
)) {
1615 *hwaddr
= mfree(*hwaddr
);
1619 n
= new0(struct ether_addr
, 1);
1623 r
= parse_ether_addr(rvalue
, n
);
1625 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1626 "Not a valid MAC address, ignoring assignment: %s", rvalue
);
1630 free_and_replace(*hwaddr
, n
);
1635 int config_parse_ether_addrs(
1637 const char *filename
,
1639 const char *section
,
1640 unsigned section_line
,
1647 Set
**hwaddrs
= data
;
1655 if (isempty(rvalue
)) {
1656 /* Empty assignment resets the list */
1657 *hwaddrs
= set_free(*hwaddrs
);
1661 for (const char *p
= rvalue
;;) {
1662 _cleanup_free_
char *word
= NULL
;
1663 _cleanup_free_
struct ether_addr
*n
= NULL
;
1665 r
= extract_first_word(&p
, &word
, NULL
, 0);
1671 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1672 "Invalid syntax, ignoring: %s", rvalue
);
1676 n
= new(struct ether_addr
, 1);
1680 r
= parse_ether_addr(word
, n
);
1682 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1683 "Not a valid MAC address, ignoring: %s", word
);
1687 r
= set_ensure_consume(hwaddrs
, ðer_addr_hash_ops_free
, TAKE_PTR(n
));
1693 int config_parse_in_addr_non_null(
1695 const char *filename
,
1697 const char *section
,
1698 unsigned section_line
,
1705 /* data must be a pointer to struct in_addr or in6_addr, and the type is determined by ltype. */
1706 struct in_addr
*ipv4
= data
;
1707 struct in6_addr
*ipv6
= data
;
1708 union in_addr_union a
;
1715 assert(IN_SET(ltype
, AF_INET
, AF_INET6
));
1717 if (isempty(rvalue
)) {
1718 if (ltype
== AF_INET
)
1719 *ipv4
= (struct in_addr
) {};
1721 *ipv6
= (struct in6_addr
) {};
1725 r
= in_addr_from_string(ltype
, rvalue
, &a
);
1727 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1728 "Failed to parse %s=, ignoring assignment: %s", lvalue
, rvalue
);
1732 if (!in_addr_is_set(ltype
, &a
)) {
1733 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1734 "%s= cannot be the ANY address, ignoring: %s", lvalue
, rvalue
);
1738 if (ltype
== AF_INET
)
1745 DEFINE_CONFIG_PARSE(config_parse_percent
, parse_percent
, "Failed to parse percent value");
1746 DEFINE_CONFIG_PARSE(config_parse_permyriad
, parse_permyriad
, "Failed to parse permyriad value");