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-helpers.h"
28 #include "parse-util.h"
29 #include "path-util.h"
30 #include "percent-util.h"
31 #include "process-util.h"
32 #include "rlimit-util.h"
35 #include "signal-util.h"
36 #include "socket-util.h"
37 #include "stat-util.h"
38 #include "string-util.h"
40 #include "syslog-util.h"
41 #include "time-util.h"
44 int config_item_table_lookup(
48 ConfigParserCallback
*ret_func
,
53 const ConfigTableItem
*t
;
61 for (t
= table
; t
->lvalue
; t
++) {
63 if (!streq(lvalue
, t
->lvalue
))
66 if (!streq_ptr(section
, t
->section
))
70 *ret_ltype
= t
->ltype
;
81 int config_item_perf_lookup(
85 ConfigParserCallback
*ret_func
,
90 ConfigPerfItemLookup lookup
= (ConfigPerfItemLookup
) table
;
91 const ConfigPerfItem
*p
;
102 key
= strjoina(section
, ".", lvalue
);
103 p
= lookup(key
, strlen(key
));
105 p
= lookup(lvalue
, strlen(lvalue
));
113 *ret_func
= p
->parse
;
114 *ret_ltype
= p
->ltype
;
115 *ret_data
= (uint8_t*) userdata
+ p
->offset
;
119 /* Run the user supplied parser for an assignment */
120 static int next_assignment(
122 const char *filename
,
124 ConfigItemLookup lookup
,
127 unsigned section_line
,
130 ConfigParseFlags flags
,
133 ConfigParserCallback func
= NULL
;
144 r
= lookup(table
, section
, lvalue
, &func
, <ype
, &data
, userdata
);
151 return func(unit
, filename
, line
, section
, section_line
,
152 lvalue
, ltype
, rvalue
, data
, userdata
);
155 /* Warn about unknown non-extension fields. */
156 if (!(flags
& CONFIG_PARSE_RELAXED
) && !startswith(lvalue
, "X-"))
157 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
158 "Unknown key name '%s' in section '%s', ignoring.", lvalue
, section
);
163 /* Parse a single logical line */
164 static int parse_line(
166 const char *filename
,
168 const char *sections
,
169 ConfigItemLookup lookup
,
171 ConfigParseFlags flags
,
173 unsigned *section_line
,
174 bool *section_ignored
,
175 char *l
, /* is modified */
192 if (!utf8_is_valid(l
))
193 return log_syntax_invalid_utf8(unit
, LOG_WARNING
, filename
, line
, l
);
196 _cleanup_free_
char *n
= NULL
;
203 return log_syntax(unit
, LOG_ERR
, filename
, line
, SYNTHETIC_ERRNO(EBADMSG
), "Invalid section header '%s'", l
);
205 n
= strndup(l
+1, k
-2);
209 if (!string_is_safe(n
))
210 return log_syntax(unit
, LOG_ERR
, filename
, line
, SYNTHETIC_ERRNO(EBADMSG
), "Bad characters in section header '%s'", l
);
212 if (sections
&& !nulstr_contains(sections
, n
)) {
216 ignore
= (flags
& CONFIG_PARSE_RELAXED
) || startswith(n
, "X-");
219 NULSTR_FOREACH(t
, sections
)
220 if (streq_ptr(n
, startswith(t
, "-"))) { /* Ignore sections prefixed with "-" in valid section list */
226 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Unknown section '%s'. Ignoring.", n
);
228 *section
= mfree(*section
);
230 *section_ignored
= true;
232 free_and_replace(*section
, n
);
233 *section_line
= line
;
234 *section_ignored
= false;
240 if (sections
&& !*section
) {
241 if (!(flags
& CONFIG_PARSE_RELAXED
) && !*section_ignored
)
242 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Assignment outside of section. Ignoring.");
249 return log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
250 "Missing '=', ignoring line.");
252 return log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
253 "Missing key name before '=', ignoring line.");
258 return next_assignment(unit
,
271 /* Go through the file and parse each line */
274 const char *filename
,
276 const char *sections
,
277 ConfigItemLookup lookup
,
279 ConfigParseFlags flags
,
281 struct stat
*ret_stat
) {
283 _cleanup_free_
char *section
= NULL
, *continuation
= NULL
;
284 _cleanup_fclose_
FILE *ours
= NULL
;
285 unsigned line
= 0, section_line
= 0;
286 bool section_ignored
= false, bom_seen
= false;
294 f
= ours
= fopen(filename
, "re");
296 /* Only log on request, except for ENOENT,
297 * since we return 0 to the caller. */
298 if ((flags
& CONFIG_PARSE_WARN
) || errno
== ENOENT
)
299 log_full_errno(errno
== ENOENT
? LOG_DEBUG
: LOG_ERR
, errno
,
300 "Failed to open configuration file '%s': %m", filename
);
302 if (errno
== ENOENT
) {
304 *ret_stat
= (struct stat
) {};
314 if (fd
>= 0) { /* stream might not have an fd, let's be careful hence */
316 if (fstat(fd
, &st
) < 0)
317 return log_full_errno(FLAGS_SET(flags
, CONFIG_PARSE_WARN
) ? LOG_ERR
: LOG_DEBUG
, errno
,
318 "Failed to fstat(%s): %m", filename
);
320 (void) stat_warn_permissions(filename
, &st
);
322 st
= (struct stat
) {};
325 _cleanup_free_
char *buf
= NULL
;
326 bool escaped
= false;
329 r
= read_line(f
, LONG_LINE_MAX
, &buf
);
333 if (flags
& CONFIG_PARSE_WARN
)
334 log_error_errno(r
, "%s:%u: Line too long", filename
, line
);
339 if (FLAGS_SET(flags
, CONFIG_PARSE_WARN
))
340 log_error_errno(r
, "%s:%u: Error while reading configuration file: %m", filename
, line
);
347 l
= skip_leading_chars(buf
, WHITESPACE
);
348 if (*l
!= '\0' && strchr(COMMENTS
, *l
))
355 q
= startswith(buf
, UTF8_BYTE_ORDER_MARK
);
363 if (strlen(continuation
) + strlen(l
) > LONG_LINE_MAX
) {
364 if (flags
& CONFIG_PARSE_WARN
)
365 log_error("%s:%u: Continuation line too long", filename
, line
);
369 if (!strextend(&continuation
, l
)) {
370 if (flags
& CONFIG_PARSE_WARN
)
379 for (e
= p
; *e
; e
++) {
390 continuation
= strdup(l
);
392 if (flags
& CONFIG_PARSE_WARN
)
414 if (flags
& CONFIG_PARSE_WARN
)
415 log_warning_errno(r
, "%s:%u: Failed to parse file: %m", filename
, line
);
419 continuation
= mfree(continuation
);
436 if (flags
& CONFIG_PARSE_WARN
)
437 log_warning_errno(r
, "%s:%u: Failed to parse file: %m", filename
, line
);
448 int hashmap_put_stats_by_path(Hashmap
**stats_by_path
, const char *path
, const struct stat
*st
) {
449 _cleanup_free_
struct stat
*st_copy
= NULL
;
450 _cleanup_free_
char *path_copy
= NULL
;
453 assert(stats_by_path
);
457 r
= hashmap_ensure_allocated(stats_by_path
, &path_hash_ops_free_free
);
461 st_copy
= newdup(struct stat
, st
, 1);
465 path_copy
= strdup(path
);
469 r
= hashmap_put(*stats_by_path
, path_copy
, st_copy
);
479 static int config_parse_many_files(
480 const char* const* conf_files
,
482 const char *sections
,
483 ConfigItemLookup lookup
,
485 ConfigParseFlags flags
,
487 Hashmap
**ret_stats_by_path
) {
489 _cleanup_hashmap_free_ Hashmap
*stats_by_path
= NULL
;
493 if (ret_stats_by_path
) {
494 stats_by_path
= hashmap_new(&path_hash_ops_free_free
);
499 /* First read the first found main config file. */
500 STRV_FOREACH(fn
, conf_files
) {
501 r
= config_parse(NULL
, *fn
, NULL
, sections
, lookup
, table
, flags
, userdata
, &st
);
507 if (ret_stats_by_path
) {
508 r
= hashmap_put_stats_by_path(&stats_by_path
, *fn
, &st
);
516 /* Then read all the drop-ins. */
517 STRV_FOREACH(fn
, files
) {
518 r
= config_parse(NULL
, *fn
, NULL
, sections
, lookup
, table
, flags
, userdata
, &st
);
524 if (ret_stats_by_path
) {
525 r
= hashmap_put_stats_by_path(&stats_by_path
, *fn
, &st
);
531 if (ret_stats_by_path
)
532 *ret_stats_by_path
= TAKE_PTR(stats_by_path
);
537 /* Parse each config file in the directories specified as nulstr. */
538 int config_parse_many_nulstr(
539 const char *conf_file
,
540 const char *conf_file_dirs
,
541 const char *sections
,
542 ConfigItemLookup lookup
,
544 ConfigParseFlags flags
,
546 Hashmap
**ret_stats_by_path
) {
548 _cleanup_strv_free_
char **files
= NULL
;
551 r
= conf_files_list_nulstr(&files
, ".conf", NULL
, 0, conf_file_dirs
);
555 return config_parse_many_files(STRV_MAKE_CONST(conf_file
),
556 files
, sections
, lookup
, table
, flags
, userdata
,
560 static int config_get_dropin_files(
561 const char* const* conf_file_dirs
,
562 const char *dropin_dirname
,
565 _cleanup_strv_free_
char **dropin_dirs
= NULL
;
569 assert(conf_file_dirs
);
570 assert(dropin_dirname
);
573 suffix
= strjoina("/", dropin_dirname
);
574 r
= strv_extend_strv_concat(&dropin_dirs
, (char**) conf_file_dirs
, suffix
);
578 return conf_files_list_strv(ret
, ".conf", NULL
, 0, (const char* const*) dropin_dirs
);
581 /* Parse each config file in the directories specified as strv. */
582 int config_parse_many(
583 const char* const* conf_files
,
584 const char* const* conf_file_dirs
,
585 const char *dropin_dirname
,
586 const char *sections
,
587 ConfigItemLookup lookup
,
589 ConfigParseFlags flags
,
591 Hashmap
**ret_stats_by_path
,
592 char ***ret_dropin_files
) {
594 _cleanup_strv_free_
char **files
= NULL
;
597 assert(conf_file_dirs
);
598 assert(dropin_dirname
);
602 r
= config_get_dropin_files(conf_file_dirs
, dropin_dirname
, &files
);
606 r
= config_parse_many_files(conf_files
, files
, sections
, lookup
, table
, flags
, userdata
, ret_stats_by_path
);
610 if (ret_dropin_files
)
611 *ret_dropin_files
= TAKE_PTR(files
);
616 static int dropins_get_stats_by_path(
617 const char* conf_file
,
618 const char* const* conf_file_dirs
,
619 Hashmap
**stats_by_path
) {
621 _cleanup_strv_free_
char **files
= NULL
;
622 _cleanup_free_
char *dropin_dirname
= NULL
;
626 assert(conf_file_dirs
);
627 assert(stats_by_path
);
629 r
= path_extract_filename(conf_file
, &dropin_dirname
);
632 if (r
== O_DIRECTORY
)
635 if (!strextend(&dropin_dirname
, ".d"))
638 r
= config_get_dropin_files(conf_file_dirs
, dropin_dirname
, &files
);
642 STRV_FOREACH(fn
, files
) {
645 if (stat(*fn
, &st
) < 0) {
652 r
= hashmap_put_stats_by_path(stats_by_path
, *fn
, &st
);
660 int config_get_stats_by_path(
664 const char* const* dirs
,
668 _cleanup_hashmap_free_ Hashmap
*stats_by_path
= NULL
;
669 _cleanup_strv_free_
char **files
= NULL
;
676 /* Unlike config_parse(), this does not support stream. */
678 r
= conf_files_list_strv(&files
, suffix
, root
, flags
, dirs
);
682 STRV_FOREACH(f
, files
) {
685 /* First read the main config file. */
686 if (stat(*f
, &st
) < 0) {
693 r
= hashmap_put_stats_by_path(&stats_by_path
, *f
, &st
);
700 /* Then read all the drop-ins if requested. */
701 r
= dropins_get_stats_by_path(*f
, dirs
, &stats_by_path
);
706 *ret
= TAKE_PTR(stats_by_path
);
710 bool stats_by_path_equal(Hashmap
*a
, Hashmap
*b
) {
711 struct stat
*st_a
, *st_b
;
714 if (hashmap_size(a
) != hashmap_size(b
))
717 HASHMAP_FOREACH_KEY(st_a
, path
, a
) {
718 st_b
= hashmap_get(b
, path
);
722 if (!stat_inode_unmodified(st_a
, st_b
))
729 static void config_section_hash_func(const ConfigSection
*c
, struct siphash
*state
) {
730 siphash24_compress_string(c
->filename
, state
);
731 siphash24_compress(&c
->line
, sizeof(c
->line
), state
);
734 static int config_section_compare_func(const ConfigSection
*x
, const ConfigSection
*y
) {
737 r
= strcmp(x
->filename
, y
->filename
);
741 return CMP(x
->line
, y
->line
);
744 DEFINE_HASH_OPS(config_section_hash_ops
, ConfigSection
, config_section_hash_func
, config_section_compare_func
);
746 int config_section_new(const char *filename
, unsigned line
, ConfigSection
**s
) {
749 cs
= malloc0(offsetof(ConfigSection
, filename
) + strlen(filename
) + 1);
753 strcpy(cs
->filename
, filename
);
761 unsigned hashmap_find_free_section_line(Hashmap
*hashmap
) {
766 HASHMAP_FOREACH_KEY(entry
, cs
, hashmap
)
773 #define DEFINE_PARSER(type, vartype, conv_func) \
774 DEFINE_CONFIG_PARSE_PTR(config_parse_##type, conv_func, vartype, "Failed to parse " #type " value")
776 DEFINE_PARSER(int, int, safe_atoi
);
777 DEFINE_PARSER(long, long, safe_atoli
);
778 DEFINE_PARSER(uint8
, uint8_t, safe_atou8
);
779 DEFINE_PARSER(uint16
, uint16_t, safe_atou16
);
780 DEFINE_PARSER(uint32
, uint32_t, safe_atou32
);
781 DEFINE_PARSER(int32
, int32_t, safe_atoi32
);
782 DEFINE_PARSER(uint64
, uint64_t, safe_atou64
);
783 DEFINE_PARSER(unsigned, unsigned, safe_atou
);
784 DEFINE_PARSER(double, double, safe_atod
);
785 DEFINE_PARSER(nsec
, nsec_t
, parse_nsec
);
786 DEFINE_PARSER(sec
, usec_t
, parse_sec
);
787 DEFINE_PARSER(sec_def_infinity
, usec_t
, parse_sec_def_infinity
);
788 DEFINE_PARSER(mode
, mode_t
, parse_mode
);
789 DEFINE_PARSER(pid
, pid_t
, parse_pid
);
791 int config_parse_iec_size(
793 const char *filename
,
796 unsigned section_line
,
812 r
= parse_size(rvalue
, 1024, &v
);
813 if (r
>= 0 && (uint64_t) (size_t) v
!= v
)
816 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to parse size value '%s', ignoring: %m", rvalue
);
824 int config_parse_si_uint64(
826 const char *filename
,
829 unsigned section_line
,
844 r
= parse_size(rvalue
, 1000, sz
);
846 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to parse size value '%s', ignoring: %m", rvalue
);
851 int config_parse_iec_uint64(
853 const char *filename
,
856 unsigned section_line
,
863 uint64_t *bytes
= data
;
871 r
= parse_size(rvalue
, 1024, bytes
);
873 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to parse size value, ignoring: %s", rvalue
);
878 int config_parse_iec_uint64_infinity(
880 const char *filename
,
883 unsigned section_line
,
890 uint64_t *bytes
= data
;
895 if (streq(rvalue
, "infinity")) {
900 return config_parse_iec_uint64(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, rvalue
, data
, userdata
);
903 int config_parse_bool(
905 const char *filename
,
908 unsigned section_line
,
924 k
= parse_boolean(rvalue
);
926 log_syntax(unit
, fatal
? LOG_ERR
: LOG_WARNING
, filename
, line
, k
,
927 "Failed to parse boolean value%s: %s",
928 fatal
? "" : ", ignoring", rvalue
);
929 return fatal
? -ENOEXEC
: 0;
936 int config_parse_id128(
938 const char *filename
,
941 unsigned section_line
,
948 sd_id128_t t
, *result
= data
;
955 r
= sd_id128_from_string(rvalue
, &t
);
957 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to parse 128bit ID/UUID, ignoring: %s", rvalue
);
961 if (sd_id128_is_null(t
)) {
962 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "128bit ID/UUID is all 0, ignoring: %s", rvalue
);
970 int config_parse_tristate(
972 const char *filename
,
975 unsigned section_line
,
989 /* A tristate is pretty much a boolean, except that it can also take an empty string,
990 * indicating "uninitialized", much like NULL is for a pointer type. */
992 if (isempty(rvalue
)) {
997 k
= parse_boolean(rvalue
);
999 log_syntax(unit
, LOG_WARNING
, filename
, line
, k
,
1000 "Failed to parse boolean value for %s=, ignoring: %s", lvalue
, rvalue
);
1008 int config_parse_string(
1010 const char *filename
,
1012 const char *section
,
1013 unsigned section_line
,
1020 char **s
= ASSERT_PTR(data
);
1026 if (isempty(rvalue
)) {
1031 if (FLAGS_SET(ltype
, CONFIG_PARSE_STRING_SAFE
) && !string_is_safe(rvalue
)) {
1032 _cleanup_free_
char *escaped
= NULL
;
1034 escaped
= cescape(rvalue
);
1035 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1036 "Specified string contains unsafe characters, ignoring: %s", strna(escaped
));
1040 if (FLAGS_SET(ltype
, CONFIG_PARSE_STRING_ASCII
) && !ascii_is_valid(rvalue
)) {
1041 _cleanup_free_
char *escaped
= NULL
;
1043 escaped
= cescape(rvalue
);
1044 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1045 "Specified string contains invalid ASCII characters, ignoring: %s", strna(escaped
));
1049 return free_and_strdup_warn(s
, empty_to_null(rvalue
));
1052 int config_parse_dns_name(
1054 const char *filename
,
1056 const char *section
,
1057 unsigned section_line
,
1064 char **hostname
= ASSERT_PTR(data
);
1071 if (isempty(rvalue
)) {
1072 *hostname
= mfree(*hostname
);
1076 r
= dns_name_is_valid(rvalue
);
1078 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1079 "Failed to check validity of DNS domain name '%s', ignoring assignment: %m", rvalue
);
1083 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1084 "Specified invalid DNS domain name, ignoring assignment: %s", rvalue
);
1088 return free_and_strdup_warn(hostname
, rvalue
);
1091 int config_parse_hostname(
1093 const char *filename
,
1095 const char *section
,
1096 unsigned section_line
,
1103 char **hostname
= ASSERT_PTR(data
);
1109 if (isempty(rvalue
)) {
1110 *hostname
= mfree(*hostname
);
1114 if (!hostname_is_valid(rvalue
, 0)) {
1115 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1116 "Specified invalid hostname, ignoring assignment: %s", rvalue
);
1120 return config_parse_dns_name(unit
, filename
, line
, section
, section_line
,
1121 lvalue
, ltype
, rvalue
, data
, userdata
);
1124 int config_parse_path(
1126 const char *filename
,
1128 const char *section
,
1129 unsigned section_line
,
1136 _cleanup_free_
char *n
= NULL
;
1146 if (isempty(rvalue
))
1153 r
= path_simplify_and_warn(n
, PATH_CHECK_ABSOLUTE
| (fatal
? PATH_CHECK_FATAL
: 0), unit
, filename
, line
, lvalue
);
1155 return fatal
? -ENOEXEC
: 0;
1158 return free_and_replace(*s
, n
);
1161 int config_parse_strv(
1163 const char *filename
,
1165 const char *section
,
1166 unsigned section_line
,
1181 if (isempty(rvalue
)) {
1182 *sv
= strv_free(*sv
);
1186 for (const char *p
= rvalue
;;) {
1189 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_UNQUOTE
|EXTRACT_RETAIN_ESCAPE
);
1195 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Invalid syntax, ignoring: %s", rvalue
);
1199 r
= strv_consume(sv
, word
);
1205 int config_parse_warn_compat(
1207 const char *filename
,
1209 const char *section
,
1210 unsigned section_line
,
1217 Disabled reason
= ltype
;
1221 case DISABLED_CONFIGURATION
:
1222 log_syntax(unit
, LOG_DEBUG
, filename
, line
, 0,
1223 "Support for option %s= has been disabled at compile time and it is ignored", lvalue
);
1226 case DISABLED_LEGACY
:
1227 log_syntax(unit
, LOG_INFO
, filename
, line
, 0,
1228 "Support for option %s= has been removed and it is ignored", lvalue
);
1231 case DISABLED_EXPERIMENTAL
:
1232 log_syntax(unit
, LOG_INFO
, filename
, line
, 0,
1233 "Support for option %s= has not yet been enabled and it is ignored", lvalue
);
1240 int config_parse_log_facility(
1242 const char *filename
,
1244 const char *section
,
1245 unsigned section_line
,
1259 x
= log_facility_unshifted_from_string(rvalue
);
1261 log_syntax(unit
, LOG_WARNING
, filename
, line
, x
, "Failed to parse log facility, ignoring: %s", rvalue
);
1265 *o
= (x
<< 3) | LOG_PRI(*o
);
1270 int config_parse_log_level(
1272 const char *filename
,
1274 const char *section
,
1275 unsigned section_line
,
1289 x
= log_level_from_string(rvalue
);
1291 log_syntax(unit
, LOG_WARNING
, filename
, line
, x
, "Failed to parse log level, ignoring: %s", rvalue
);
1295 if (*o
< 0) /* if it wasn't initialized so far, assume zero facility */
1298 *o
= (*o
& LOG_FACMASK
) | x
;
1303 int config_parse_signal(
1305 const char *filename
,
1307 const char *section
,
1308 unsigned section_line
,
1322 r
= signal_from_string(rvalue
);
1324 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to parse signal name, ignoring: %s", rvalue
);
1332 int config_parse_personality(
1334 const char *filename
,
1336 const char *section
,
1337 unsigned section_line
,
1344 unsigned long *personality
= data
, p
;
1349 assert(personality
);
1351 if (isempty(rvalue
))
1352 p
= PERSONALITY_INVALID
;
1354 p
= personality_from_string(rvalue
);
1355 if (p
== PERSONALITY_INVALID
) {
1356 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Failed to parse personality, ignoring: %s", rvalue
);
1365 int config_parse_ifname(
1367 const char *filename
,
1369 const char *section
,
1370 unsigned section_line
,
1385 if (isempty(rvalue
)) {
1390 if (!ifname_valid(rvalue
)) {
1391 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Interface name is not valid or too long, ignoring assignment: %s", rvalue
);
1395 r
= free_and_strdup(s
, rvalue
);
1402 int config_parse_ifnames(
1404 const char *filename
,
1406 const char *section
,
1407 unsigned section_line
,
1414 _cleanup_strv_free_
char **names
= NULL
;
1423 if (isempty(rvalue
)) {
1428 for (const char *p
= rvalue
;;) {
1429 _cleanup_free_
char *word
= NULL
;
1431 r
= extract_first_word(&p
, &word
, NULL
, 0);
1435 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1436 "Failed to extract interface name, ignoring assignment: %s",
1443 if (!ifname_valid_full(word
, ltype
)) {
1444 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1445 "Interface name is not valid or too long, ignoring assignment: %s",
1450 r
= strv_consume(&names
, TAKE_PTR(word
));
1455 r
= strv_extend_strv(s
, names
, true);
1462 int config_parse_ip_port(
1464 const char *filename
,
1466 const char *section
,
1467 unsigned section_line
,
1483 if (isempty(rvalue
)) {
1488 r
= parse_ip_port(rvalue
, &port
);
1490 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to parse port '%s'.", rvalue
);
1499 int config_parse_mtu(
1501 const char *filename
,
1503 const char *section
,
1504 unsigned section_line
,
1511 uint32_t *mtu
= data
;
1517 r
= parse_mtu(ltype
, rvalue
, mtu
);
1519 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1520 "Maximum transfer unit (MTU) value out of range. Permitted range is %" PRIu32
"…%" PRIu32
", ignoring: %s",
1521 (uint32_t) (ltype
== AF_INET6
? IPV6_MIN_MTU
: IPV4_MIN_MTU
), (uint32_t) UINT32_MAX
,
1526 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1527 "Failed to parse MTU value '%s', ignoring: %m", rvalue
);
1534 int config_parse_rlimit(
1536 const char *filename
,
1538 const char *section
,
1539 unsigned section_line
,
1546 struct rlimit
**rl
= data
, d
= {};
1552 r
= rlimit_parse(ltype
, rvalue
, &d
);
1554 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Soft resource limit chosen higher than hard limit, ignoring: %s", rvalue
);
1558 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to parse resource value, ignoring: %s", rvalue
);
1565 rl
[ltype
] = newdup(struct rlimit
, &d
, 1);
1573 int config_parse_permille(
1575 const char *filename
,
1577 const char *section
,
1578 unsigned section_line
,
1585 unsigned *permille
= data
;
1593 r
= parse_permille(rvalue
);
1595 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1596 "Failed to parse permille value, ignoring: %s", rvalue
);
1600 *permille
= (unsigned) r
;
1605 int config_parse_vlanprotocol(
1607 const char *filename
,
1609 const char *section
,
1610 unsigned section_line
,
1617 int *vlan_protocol
= data
;
1622 if (isempty(rvalue
)) {
1623 *vlan_protocol
= -1;
1627 if (STR_IN_SET(rvalue
, "802.1ad", "802.1AD"))
1628 *vlan_protocol
= ETH_P_8021AD
;
1629 else if (STR_IN_SET(rvalue
, "802.1q", "802.1Q"))
1630 *vlan_protocol
= ETH_P_8021Q
;
1632 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1633 "Failed to parse VLAN protocol value, ignoring: %s", rvalue
);
1640 int config_parse_hw_addr(
1642 const char *filename
,
1644 const char *section
,
1645 unsigned section_line
,
1652 struct hw_addr_data a
, *hwaddr
= data
;
1660 if (isempty(rvalue
)) {
1661 *hwaddr
= HW_ADDR_NULL
;
1665 r
= parse_hw_addr_full(rvalue
, ltype
, &a
);
1667 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1668 "Not a valid hardware address, ignoring assignment: %s", rvalue
);
1676 int config_parse_hw_addrs(
1678 const char *filename
,
1680 const char *section
,
1681 unsigned section_line
,
1688 Set
**hwaddrs
= data
;
1696 if (isempty(rvalue
)) {
1697 /* Empty assignment resets the list */
1698 *hwaddrs
= set_free(*hwaddrs
);
1702 for (const char *p
= rvalue
;;) {
1703 _cleanup_free_
char *word
= NULL
;
1704 _cleanup_free_
struct hw_addr_data
*n
= NULL
;
1706 r
= extract_first_word(&p
, &word
, NULL
, 0);
1712 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1713 "Invalid syntax, ignoring: %s", rvalue
);
1717 n
= new(struct hw_addr_data
, 1);
1721 r
= parse_hw_addr_full(word
, ltype
, n
);
1723 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1724 "Not a valid hardware address, ignoring: %s", word
);
1728 r
= set_ensure_consume(hwaddrs
, &hw_addr_hash_ops_free
, TAKE_PTR(n
));
1734 int config_parse_ether_addr(
1736 const char *filename
,
1738 const char *section
,
1739 unsigned section_line
,
1746 _cleanup_free_
struct ether_addr
*n
= NULL
;
1747 struct ether_addr
**hwaddr
= data
;
1755 if (isempty(rvalue
)) {
1756 *hwaddr
= mfree(*hwaddr
);
1760 n
= new0(struct ether_addr
, 1);
1764 r
= parse_ether_addr(rvalue
, n
);
1766 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1767 "Not a valid MAC address, ignoring assignment: %s", rvalue
);
1771 free_and_replace(*hwaddr
, n
);
1776 int config_parse_ether_addrs(
1778 const char *filename
,
1780 const char *section
,
1781 unsigned section_line
,
1788 Set
**hwaddrs
= data
;
1796 if (isempty(rvalue
)) {
1797 /* Empty assignment resets the list */
1798 *hwaddrs
= set_free(*hwaddrs
);
1802 for (const char *p
= rvalue
;;) {
1803 _cleanup_free_
char *word
= NULL
;
1804 _cleanup_free_
struct ether_addr
*n
= NULL
;
1806 r
= extract_first_word(&p
, &word
, NULL
, 0);
1812 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1813 "Invalid syntax, ignoring: %s", rvalue
);
1817 n
= new(struct ether_addr
, 1);
1821 r
= parse_ether_addr(word
, n
);
1823 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1824 "Not a valid MAC address, ignoring: %s", word
);
1828 r
= set_ensure_consume(hwaddrs
, ðer_addr_hash_ops_free
, TAKE_PTR(n
));
1834 int config_parse_in_addr_non_null(
1836 const char *filename
,
1838 const char *section
,
1839 unsigned section_line
,
1846 /* data must be a pointer to struct in_addr or in6_addr, and the type is determined by ltype. */
1847 struct in_addr
*ipv4
= data
;
1848 struct in6_addr
*ipv6
= data
;
1849 union in_addr_union a
;
1856 assert(IN_SET(ltype
, AF_INET
, AF_INET6
));
1858 if (isempty(rvalue
)) {
1859 if (ltype
== AF_INET
)
1860 *ipv4
= (struct in_addr
) {};
1862 *ipv6
= (struct in6_addr
) {};
1866 r
= in_addr_from_string(ltype
, rvalue
, &a
);
1868 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1869 "Failed to parse %s=, ignoring assignment: %s", lvalue
, rvalue
);
1873 if (!in_addr_is_set(ltype
, &a
)) {
1874 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1875 "%s= cannot be the ANY address, ignoring: %s", lvalue
, rvalue
);
1879 if (ltype
== AF_INET
)
1886 DEFINE_CONFIG_PARSE(config_parse_percent
, parse_percent
, "Failed to parse percent value");
1887 DEFINE_CONFIG_PARSE(config_parse_permyriad
, parse_permyriad
, "Failed to parse permyriad value");