1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include <linux/ipv6.h>
8 #include "alloc-util.h"
9 #include "calendarspec.h"
11 #include "conf-files.h"
12 #include "conf-parser.h"
13 #include "constants.h"
14 #include "dns-domain.h"
16 #include "ether-addr-util.h"
17 #include "extract-word.h"
21 #include "hash-funcs.h"
22 #include "hostname-util.h"
23 #include "id128-util.h"
24 #include "in-addr-prefix-util.h"
25 #include "ip-protocol-list.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"
36 #include "signal-util.h"
37 #include "siphash24.h"
38 #include "socket-util.h"
39 #include "stat-util.h"
40 #include "string-util.h"
42 #include "syslog-util.h"
43 #include "time-util.h"
46 DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(config_file_hash_ops_fclose
,
47 char, path_hash_func
, path_compare
,
50 int config_item_table_lookup(
54 ConfigParserCallback
*ret_func
,
65 for (const ConfigTableItem
*t
= table
; t
->lvalue
; t
++) {
67 if (!streq(lvalue
, t
->lvalue
))
70 if (!streq_ptr(section
, t
->section
))
74 *ret_ltype
= t
->ltype
;
85 int config_item_perf_lookup(
89 ConfigParserCallback
*ret_func
,
94 ConfigPerfItemLookup lookup
= (ConfigPerfItemLookup
) table
;
95 const ConfigPerfItem
*p
;
106 key
= strjoina(section
, ".", lvalue
);
107 p
= lookup(key
, strlen(key
));
109 p
= lookup(lvalue
, strlen(lvalue
));
117 *ret_func
= p
->parse
;
118 *ret_ltype
= p
->ltype
;
119 *ret_data
= (uint8_t*) userdata
+ p
->offset
;
123 /* Run the user supplied parser for an assignment */
124 static int next_assignment(
126 const char *filename
,
128 ConfigItemLookup lookup
,
131 unsigned section_line
,
134 ConfigParseFlags flags
,
137 ConfigParserCallback func
= NULL
;
148 r
= lookup(table
, section
, lvalue
, &func
, <ype
, &data
, userdata
);
155 return func(unit
, filename
, line
, section
, section_line
,
156 lvalue
, ltype
, rvalue
, data
, userdata
);
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 '%s'%s%s%s, ignoring.",
164 section
? " in section [" : "",
171 /* Parse a single logical line */
172 static int parse_line(
174 const char *filename
,
176 const char *sections
,
177 ConfigItemLookup lookup
,
179 ConfigParseFlags flags
,
181 unsigned *section_line
,
182 bool *section_ignored
,
183 char *l
, /* is modified */
200 if (!utf8_is_valid(l
))
201 return log_syntax_invalid_utf8(unit
, LOG_WARNING
, filename
, line
, l
);
204 _cleanup_free_
char *n
= NULL
;
211 return log_syntax(unit
, LOG_ERR
, filename
, line
, SYNTHETIC_ERRNO(EBADMSG
), "Invalid section header '%s'", l
);
213 n
= strndup(l
+1, k
-2);
217 if (!string_is_safe(n
))
218 return log_syntax(unit
, LOG_ERR
, filename
, line
, SYNTHETIC_ERRNO(EBADMSG
), "Bad characters in section header '%s'", l
);
220 if (sections
&& !nulstr_contains(sections
, n
)) {
223 ignore
= (flags
& CONFIG_PARSE_RELAXED
) || startswith(n
, "X-");
226 NULSTR_FOREACH(t
, sections
)
227 if (streq_ptr(n
, startswith(t
, "-"))) { /* Ignore sections prefixed with "-" in valid section list */
233 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Unknown section '%s'. Ignoring.", n
);
235 *section
= mfree(*section
);
237 *section_ignored
= true;
239 free_and_replace(*section
, n
);
240 *section_line
= line
;
241 *section_ignored
= false;
247 if (sections
&& !*section
) {
248 if (!(flags
& CONFIG_PARSE_RELAXED
) && !*section_ignored
)
249 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Assignment outside of section. Ignoring.");
256 return log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
257 "Missing '=', ignoring line.");
259 return log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
260 "Missing key name before '=', ignoring line.");
265 return next_assignment(unit
,
278 /* Go through the file and parse each line */
281 const char *filename
,
283 const char *sections
,
284 ConfigItemLookup lookup
,
286 ConfigParseFlags flags
,
288 struct stat
*ret_stat
) {
290 _cleanup_free_
char *section
= NULL
, *continuation
= NULL
;
291 _cleanup_fclose_
FILE *ours
= NULL
;
292 unsigned line
= 0, section_line
= 0;
293 bool section_ignored
= false, bom_seen
= false;
301 f
= ours
= fopen(filename
, "re");
303 /* Only log on request, except for ENOENT,
304 * since we return 0 to the caller. */
305 if ((flags
& CONFIG_PARSE_WARN
) || errno
== ENOENT
)
306 log_full_errno(errno
== ENOENT
? LOG_DEBUG
: LOG_ERR
, errno
,
307 "Failed to open configuration file '%s': %m", filename
);
309 if (errno
== ENOENT
) {
311 *ret_stat
= (struct stat
) {};
321 if (fd
>= 0) { /* stream might not have an fd, let's be careful hence */
323 if (fstat(fd
, &st
) < 0)
324 return log_full_errno(FLAGS_SET(flags
, CONFIG_PARSE_WARN
) ? LOG_ERR
: LOG_DEBUG
, errno
,
325 "Failed to fstat(%s): %m", filename
);
327 (void) stat_warn_permissions(filename
, &st
);
329 st
= (struct stat
) {};
332 _cleanup_free_
char *buf
= NULL
;
333 bool escaped
= false;
336 r
= read_line(f
, LONG_LINE_MAX
, &buf
);
340 if (flags
& CONFIG_PARSE_WARN
)
341 log_error_errno(r
, "%s:%u: Line too long", filename
, line
);
346 if (FLAGS_SET(flags
, CONFIG_PARSE_WARN
))
347 log_error_errno(r
, "%s:%u: Error while reading configuration file: %m", filename
, line
);
354 l
= skip_leading_chars(buf
, WHITESPACE
);
355 if (*l
!= '\0' && strchr(COMMENTS
, *l
))
362 q
= startswith(buf
, UTF8_BYTE_ORDER_MARK
);
370 if (strlen(continuation
) + strlen(l
) > LONG_LINE_MAX
) {
371 if (flags
& CONFIG_PARSE_WARN
)
372 log_error("%s:%u: Continuation line too long", filename
, line
);
376 if (!strextend(&continuation
, l
)) {
377 if (flags
& CONFIG_PARSE_WARN
)
386 for (e
= p
; *e
; e
++) {
397 continuation
= strdup(l
);
399 if (flags
& CONFIG_PARSE_WARN
)
421 if (flags
& CONFIG_PARSE_WARN
)
422 log_warning_errno(r
, "%s:%u: Failed to parse file: %m", filename
, line
);
426 continuation
= mfree(continuation
);
443 if (flags
& CONFIG_PARSE_WARN
)
444 log_warning_errno(r
, "%s:%u: Failed to parse file: %m", filename
, line
);
455 int hashmap_put_stats_by_path(Hashmap
**stats_by_path
, const char *path
, const struct stat
*st
) {
456 _cleanup_free_
struct stat
*st_copy
= NULL
;
457 _cleanup_free_
char *path_copy
= NULL
;
460 assert(stats_by_path
);
464 st_copy
= newdup(struct stat
, st
, 1);
468 path_copy
= strdup(path
);
472 r
= hashmap_ensure_put(stats_by_path
, &path_hash_ops_free_free
, path_copy
, st_copy
);
482 static int config_parse_many_files(
484 const char* const* conf_files
,
486 const char *sections
,
487 ConfigItemLookup lookup
,
489 ConfigParseFlags flags
,
491 Hashmap
**ret_stats_by_path
) {
493 _cleanup_hashmap_free_ Hashmap
*stats_by_path
= NULL
;
494 _cleanup_ordered_hashmap_free_ OrderedHashmap
*dropins
= NULL
;
495 _cleanup_set_free_ Set
*inodes
= NULL
;
497 int r
, level
= FLAGS_SET(flags
, CONFIG_PARSE_WARN
) ? LOG_WARNING
: LOG_DEBUG
;
499 if (ret_stats_by_path
) {
500 stats_by_path
= hashmap_new(&path_hash_ops_free_free
);
502 return log_oom_full(level
);
505 STRV_FOREACH(fn
, files
) {
506 _cleanup_fclose_
FILE *f
= NULL
;
507 _cleanup_free_
char *fname
= NULL
;
509 r
= chase_and_fopen_unlocked(*fn
, root
, CHASE_AT_RESOLVE_IN_ROOT
, "re", &fname
, &f
);
513 return log_full_errno(level
, r
, "Failed to open %s: %m", *fn
);
517 r
= ordered_hashmap_ensure_put(&dropins
, &config_file_hash_ops_fclose
, *fn
, f
);
519 assert(r
== -ENOMEM
);
520 return log_oom_full(level
);
525 /* Get inodes for all drop-ins. Later we'll verify if main config is a symlink to or is
526 * symlinked as one of them. If so, we skip reading main config file directly. */
528 _cleanup_free_
struct stat
*st_dropin
= new(struct stat
, 1);
530 return log_oom_full(level
);
532 if (fstat(fd
, st_dropin
) < 0)
533 return log_full_errno(level
, errno
, "Failed to stat %s: %m", *fn
);
535 r
= set_ensure_consume(&inodes
, &inode_hash_ops
, TAKE_PTR(st_dropin
));
537 return log_oom_full(level
);
540 /* First read the first found main config file. */
541 STRV_FOREACH(fn
, conf_files
) {
542 _cleanup_fclose_
FILE *f
= NULL
;
544 r
= chase_and_fopen_unlocked(*fn
, root
, CHASE_AT_RESOLVE_IN_ROOT
, "re", NULL
, &f
);
548 return log_full_errno(level
, r
, "Failed to open %s: %m", *fn
);
551 if (fstat(fileno(f
), &st
) < 0)
552 return log_full_errno(level
, errno
, "Failed to stat %s: %m", *fn
);
554 if (set_contains(inodes
, &st
)) {
555 log_debug("%s: symlink to/symlinked as drop-in, will be read later.", *fn
);
560 r
= config_parse(/* unit= */ NULL
, *fn
, f
, sections
, lookup
, table
, flags
, userdata
, &st
);
562 return r
; /* config_parse() logs internally. */
565 if (ret_stats_by_path
) {
566 r
= hashmap_put_stats_by_path(&stats_by_path
, *fn
, &st
);
568 return log_full_errno(level
, r
, "Failed to save stats of %s: %m", *fn
);
574 /* Then read all the drop-ins. */
576 const char *path_dropin
;
578 ORDERED_HASHMAP_FOREACH_KEY(f_dropin
, path_dropin
, dropins
) {
579 r
= config_parse(/* unit= */ NULL
, path_dropin
, f_dropin
, sections
, lookup
, table
, flags
, userdata
, &st
);
581 return r
; /* config_parse() logs internally. */
584 if (ret_stats_by_path
) {
585 r
= hashmap_put_stats_by_path(&stats_by_path
, path_dropin
, &st
);
587 return log_full_errno(level
, r
, "Failed to save stats of %s: %m", path_dropin
);
591 if (ret_stats_by_path
)
592 *ret_stats_by_path
= TAKE_PTR(stats_by_path
);
597 /* Parse each config file in the directories specified as strv. */
598 int config_parse_many(
599 const char* const* conf_files
,
600 const char* const* conf_file_dirs
,
601 const char *dropin_dirname
,
603 const char *sections
,
604 ConfigItemLookup lookup
,
606 ConfigParseFlags flags
,
608 Hashmap
**ret_stats_by_path
,
609 char ***ret_dropin_files
) {
611 _cleanup_strv_free_
char **files
= NULL
;
614 assert(conf_file_dirs
);
615 assert(dropin_dirname
);
618 r
= conf_files_list_dropins(&files
, dropin_dirname
, root
, conf_file_dirs
);
620 return log_full_errno(FLAGS_SET(flags
, CONFIG_PARSE_WARN
) ? LOG_WARNING
: LOG_DEBUG
, r
,
621 "Failed to list up drop-in configs in %s: %m", dropin_dirname
);
623 r
= config_parse_many_files(root
, conf_files
, files
, sections
, lookup
, table
, flags
, userdata
, ret_stats_by_path
);
625 return r
; /* config_parse_many_files() logs internally. */
627 if (ret_dropin_files
)
628 *ret_dropin_files
= TAKE_PTR(files
);
633 int config_parse_standard_file_with_dropins_full(
635 const char *main_file
, /* A path like "systemd/frobnicator.conf" */
636 const char *sections
,
637 ConfigItemLookup lookup
,
639 ConfigParseFlags flags
,
641 Hashmap
**ret_stats_by_path
,
642 char ***ret_dropin_files
) {
644 const char* const *conf_paths
= (const char* const*) CONF_PATHS_STRV("");
645 _cleanup_strv_free_
char **configs
= NULL
;
646 int r
, level
= FLAGS_SET(flags
, CONFIG_PARSE_WARN
) ? LOG_WARNING
: LOG_DEBUG
;
648 /* Build the list of main config files */
649 r
= strv_extend_strv_biconcat(&configs
, root
, conf_paths
, main_file
);
651 return log_oom_full(level
);
653 _cleanup_free_
char *dropin_dirname
= strjoin(main_file
, ".d");
655 return log_oom_full(level
);
657 return config_parse_many(
658 (const char* const*) configs
,
671 static int dropins_get_stats_by_path(
672 const char* conf_file
,
673 const char* const* conf_file_dirs
,
674 Hashmap
**stats_by_path
) {
676 _cleanup_strv_free_
char **files
= NULL
;
677 _cleanup_free_
char *dropin_dirname
= NULL
;
681 assert(conf_file_dirs
);
682 assert(stats_by_path
);
684 r
= path_extract_filename(conf_file
, &dropin_dirname
);
687 if (r
== O_DIRECTORY
)
690 if (!strextend(&dropin_dirname
, ".d"))
693 r
= conf_files_list_dropins(&files
, dropin_dirname
, /* root = */ NULL
, conf_file_dirs
);
697 STRV_FOREACH(fn
, files
) {
700 if (stat(*fn
, &st
) < 0) {
707 r
= hashmap_put_stats_by_path(stats_by_path
, *fn
, &st
);
715 int config_get_stats_by_path(
719 const char* const* dirs
,
723 _cleanup_hashmap_free_ Hashmap
*stats_by_path
= NULL
;
724 _cleanup_strv_free_
char **files
= NULL
;
731 /* Unlike config_parse(), this does not support stream. */
733 r
= conf_files_list_strv(&files
, suffix
, root
, flags
, dirs
);
737 STRV_FOREACH(f
, files
) {
740 /* First read the main config file. */
741 if (stat(*f
, &st
) < 0) {
748 /* Skipping an empty file. */
749 if (null_or_empty(&st
))
752 r
= hashmap_put_stats_by_path(&stats_by_path
, *f
, &st
);
759 /* Then read all the drop-ins if requested. */
760 r
= dropins_get_stats_by_path(*f
, dirs
, &stats_by_path
);
765 *ret
= TAKE_PTR(stats_by_path
);
769 bool stats_by_path_equal(Hashmap
*a
, Hashmap
*b
) {
770 struct stat
*st_a
, *st_b
;
773 if (hashmap_size(a
) != hashmap_size(b
))
776 HASHMAP_FOREACH_KEY(st_a
, path
, a
) {
777 st_b
= hashmap_get(b
, path
);
781 if (!stat_inode_unmodified(st_a
, st_b
))
788 int config_section_parse(
789 const ConfigSectionParser
*parsers
,
792 const char *filename
,
795 unsigned section_line
,
802 assert(n_parsers
> 0);
804 assert((size_t) ltype
< n_parsers
);
807 const ConfigSectionParser
*e
= parsers
+ ltype
;
810 /* This is used when a object is dynamically allocated per [SECTION] in a config parser, e.g.
811 * [Address] for systemd.network. Takes the allocated object as 'userdata', then it is passed to
812 * config parsers in the table. The 'data' field points to an element of the passed object, where
813 * its offset is given by the table. */
815 return e
->parser(unit
, filename
, line
, section
, section_line
, lvalue
, e
->ltype
, rvalue
,
816 (uint8_t*) userdata
+ e
->offset
, userdata
);
819 void config_section_hash_func(const ConfigSection
*c
, struct siphash
*state
) {
820 siphash24_compress_string(c
->filename
, state
);
821 siphash24_compress_typesafe(c
->line
, state
);
824 int config_section_compare_func(const ConfigSection
*x
, const ConfigSection
*y
) {
827 r
= strcmp(x
->filename
, y
->filename
);
831 return CMP(x
->line
, y
->line
);
834 DEFINE_HASH_OPS(config_section_hash_ops
, ConfigSection
, config_section_hash_func
, config_section_compare_func
);
836 int config_section_new(const char *filename
, unsigned line
, ConfigSection
**ret
) {
843 cs
= malloc0(offsetof(ConfigSection
, filename
) + strlen(filename
) + 1);
847 strcpy(cs
->filename
, filename
);
854 static int _hashmap_by_section_find_unused_line(
855 HashmapBase
*entries_by_section
,
856 const char *filename
,
863 HASHMAP_BASE_FOREACH_KEY(entry
, cs
, entries_by_section
) {
864 if (filename
&& !streq(cs
->filename
, filename
))
866 n
= MAX(n
, cs
->line
);
877 int hashmap_by_section_find_unused_line(
878 Hashmap
*entries_by_section
,
879 const char *filename
,
882 return _hashmap_by_section_find_unused_line(HASHMAP_BASE(entries_by_section
), filename
, ret
);
885 int ordered_hashmap_by_section_find_unused_line(
886 OrderedHashmap
*entries_by_section
,
887 const char *filename
,
890 return _hashmap_by_section_find_unused_line(HASHMAP_BASE(entries_by_section
), filename
, ret
);
893 #define DEFINE_PARSER(type, vartype, conv_func) \
894 DEFINE_CONFIG_PARSE_PTR(config_parse_##type, conv_func, vartype)
896 DEFINE_PARSER(int, int, safe_atoi
);
897 DEFINE_PARSER(long, long, safe_atoli
);
898 DEFINE_PARSER(uint8
, uint8_t, safe_atou8
);
899 DEFINE_PARSER(uint16
, uint16_t, safe_atou16
);
900 DEFINE_PARSER(uint32
, uint32_t, safe_atou32
);
901 DEFINE_PARSER(int32
, int32_t, safe_atoi32
);
902 DEFINE_PARSER(uint64
, uint64_t, safe_atou64
);
903 DEFINE_PARSER(unsigned, unsigned, safe_atou
);
904 DEFINE_PARSER(double, double, safe_atod
);
905 DEFINE_PARSER(nsec
, nsec_t
, parse_nsec
);
906 DEFINE_PARSER(sec
, usec_t
, parse_sec
);
907 DEFINE_PARSER(sec_def_infinity
, usec_t
, parse_sec_def_infinity
);
908 DEFINE_PARSER(mode
, mode_t
, parse_mode
);
909 DEFINE_PARSER(pid
, pid_t
, parse_pid
);
911 int config_parse_iec_size(
913 const char *filename
,
916 unsigned section_line
,
923 size_t *sz
= ASSERT_PTR(data
);
931 r
= parse_size(rvalue
, 1024, &v
);
932 if (r
>= 0 && (uint64_t) (size_t) v
!= v
)
935 return log_syntax_parse_error(unit
, filename
, line
, r
, lvalue
, rvalue
);
941 int config_parse_si_uint64(
943 const char *filename
,
946 unsigned section_line
,
953 uint64_t *sz
= ASSERT_PTR(data
);
960 r
= parse_size(rvalue
, 1000, sz
);
962 return log_syntax_parse_error(unit
, filename
, line
, r
, lvalue
, rvalue
);
967 int config_parse_iec_uint64(
969 const char *filename
,
972 unsigned section_line
,
979 uint64_t *bytes
= ASSERT_PTR(data
);
986 r
= parse_size(rvalue
, 1024, bytes
);
988 return log_syntax_parse_error(unit
, filename
, line
, r
, lvalue
, rvalue
);
993 int config_parse_iec_uint64_infinity(
995 const char *filename
,
998 unsigned section_line
,
1005 uint64_t *bytes
= ASSERT_PTR(data
);
1009 if (streq(rvalue
, "infinity")) {
1010 *bytes
= UINT64_MAX
;
1014 return config_parse_iec_uint64(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, rvalue
, data
, userdata
);
1017 int config_parse_bool(
1019 const char *filename
,
1021 const char *section
,
1022 unsigned section_line
,
1029 bool *b
= ASSERT_PTR(data
);
1037 r
= parse_boolean(rvalue
);
1039 log_syntax_parse_error_full(unit
, filename
, line
, r
, fatal
, lvalue
, rvalue
);
1040 return fatal
? -ENOEXEC
: 0;
1047 int config_parse_uint32_flag(
1049 const char *filename
,
1051 const char *section
,
1052 unsigned section_line
,
1059 uint32_t *flags
= ASSERT_PTR(data
);
1064 r
= isempty(rvalue
) ? 0 : parse_boolean(rvalue
);
1066 return log_syntax_parse_error(unit
, filename
, line
, r
, lvalue
, rvalue
);
1068 SET_FLAG(*flags
, ltype
, r
);
1072 int config_parse_uint32_invert_flag(
1074 const char *filename
,
1076 const char *section
,
1077 unsigned section_line
,
1084 uint32_t *flags
= ASSERT_PTR(data
);
1089 r
= isempty(rvalue
) ? 0 : parse_boolean(rvalue
);
1091 return log_syntax_parse_error(unit
, filename
, line
, r
, lvalue
, rvalue
);
1093 SET_FLAG(*flags
, ltype
, !r
);
1097 int config_parse_id128(
1099 const char *filename
,
1101 const char *section
,
1102 unsigned section_line
,
1109 sd_id128_t
*result
= data
;
1116 r
= id128_from_string_nonzero(rvalue
, result
);
1118 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "128-bit ID/UUID is all 0, ignoring: %s", rvalue
);
1122 return log_syntax_parse_error(unit
, filename
, line
, r
, lvalue
, rvalue
);
1127 int config_parse_tristate(
1129 const char *filename
,
1131 const char *section
,
1132 unsigned section_line
,
1139 int r
, *t
= ASSERT_PTR(data
);
1145 /* A tristate is pretty much a boolean, except that it can also take an empty string,
1146 * indicating "uninitialized", much like NULL is for a pointer type. */
1148 if (isempty(rvalue
)) {
1153 r
= parse_tristate(rvalue
, t
);
1155 return log_syntax_parse_error(unit
, filename
, line
, r
, lvalue
, rvalue
);
1160 int config_parse_string(
1162 const char *filename
,
1164 const char *section
,
1165 unsigned section_line
,
1172 char **s
= ASSERT_PTR(data
);
1179 if (isempty(rvalue
)) {
1184 if (FLAGS_SET(ltype
, CONFIG_PARSE_STRING_SAFE
) && !string_is_safe(rvalue
)) {
1185 _cleanup_free_
char *escaped
= NULL
;
1187 escaped
= cescape(rvalue
);
1188 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1189 "Specified string contains unsafe characters, ignoring: %s", strna(escaped
));
1193 if (FLAGS_SET(ltype
, CONFIG_PARSE_STRING_ASCII
) && !ascii_is_valid(rvalue
)) {
1194 _cleanup_free_
char *escaped
= NULL
;
1196 escaped
= cescape(rvalue
);
1197 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1198 "Specified string contains invalid ASCII characters, ignoring: %s", strna(escaped
));
1202 r
= free_and_strdup_warn(s
, rvalue
);
1209 int config_parse_dns_name(
1211 const char *filename
,
1213 const char *section
,
1214 unsigned section_line
,
1221 char **hostname
= ASSERT_PTR(data
);
1228 if (isempty(rvalue
)) {
1229 *hostname
= mfree(*hostname
);
1233 r
= dns_name_is_valid(rvalue
);
1235 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1236 "Failed to check validity of DNS domain name '%s', ignoring assignment: %m", rvalue
);
1240 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1241 "Specified invalid DNS domain name, ignoring assignment: %s", rvalue
);
1245 r
= free_and_strdup_warn(hostname
, rvalue
);
1252 int config_parse_hostname(
1254 const char *filename
,
1256 const char *section
,
1257 unsigned section_line
,
1264 char **hostname
= ASSERT_PTR(data
);
1270 if (isempty(rvalue
)) {
1271 *hostname
= mfree(*hostname
);
1275 if (!hostname_is_valid(rvalue
, 0)) {
1276 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1277 "Specified invalid hostname, ignoring assignment: %s", rvalue
);
1281 return config_parse_dns_name(unit
, filename
, line
, section
, section_line
,
1282 lvalue
, ltype
, rvalue
, data
, userdata
);
1285 int config_parse_path(
1287 const char *filename
,
1289 const char *section
,
1290 unsigned section_line
,
1297 _cleanup_free_
char *n
= NULL
;
1299 char **s
= ASSERT_PTR(data
);
1306 if (isempty(rvalue
)) {
1315 r
= path_simplify_and_warn(n
, PATH_CHECK_ABSOLUTE
| (fatal
? PATH_CHECK_FATAL
: 0), unit
, filename
, line
, lvalue
);
1317 return fatal
? -ENOEXEC
: 0;
1319 free_and_replace(*s
, n
);
1323 int config_parse_strv(
1325 const char *filename
,
1327 const char *section
,
1328 unsigned section_line
,
1330 int ltype
, /* When true, duplicated entries will be filtered. */
1335 char ***sv
= ASSERT_PTR(data
);
1342 if (isempty(rvalue
)) {
1343 *sv
= strv_free(*sv
);
1347 _cleanup_strv_free_
char **strv
= NULL
;
1348 for (const char *p
= rvalue
;;) {
1351 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_UNQUOTE
|EXTRACT_RETAIN_ESCAPE
);
1353 return log_syntax_parse_error(unit
, filename
, line
, r
, lvalue
, rvalue
);
1357 r
= strv_consume(&strv
, word
);
1362 r
= strv_extend_strv_consume(sv
, TAKE_PTR(strv
), /* filter_duplicates = */ ltype
);
1369 int config_parse_warn_compat(
1371 const char *filename
,
1373 const char *section
,
1374 unsigned section_line
,
1381 Disabled reason
= ltype
;
1385 case DISABLED_CONFIGURATION
:
1386 log_syntax(unit
, LOG_DEBUG
, filename
, line
, 0,
1387 "Support for option %s= has been disabled at compile time and it is ignored", lvalue
);
1390 case DISABLED_LEGACY
:
1391 log_syntax(unit
, LOG_INFO
, filename
, line
, 0,
1392 "Support for option %s= has been removed and it is ignored", lvalue
);
1395 case DISABLED_EXPERIMENTAL
:
1396 log_syntax(unit
, LOG_INFO
, filename
, line
, 0,
1397 "Support for option %s= has not yet been enabled and it is ignored", lvalue
);
1404 int config_parse_log_facility(
1406 const char *filename
,
1408 const char *section
,
1409 unsigned section_line
,
1423 x
= log_facility_unshifted_from_string(rvalue
);
1425 return log_syntax_parse_error(unit
, filename
, line
, x
, lvalue
, rvalue
);
1427 *o
= (x
<< 3) | LOG_PRI(*o
);
1432 int config_parse_log_level(
1434 const char *filename
,
1436 const char *section
,
1437 unsigned section_line
,
1451 x
= log_level_from_string(rvalue
);
1453 return log_syntax_parse_error(unit
, filename
, line
, x
, lvalue
, rvalue
);
1455 if (*o
< 0) /* if it wasn't initialized so far, assume zero facility */
1458 *o
= (*o
& LOG_FACMASK
) | x
;
1463 int config_parse_signal(
1465 const char *filename
,
1467 const char *section
,
1468 unsigned section_line
,
1482 r
= signal_from_string(rvalue
);
1484 return log_syntax_parse_error(unit
, filename
, line
, r
, lvalue
, rvalue
);
1490 int config_parse_personality(
1492 const char *filename
,
1494 const char *section
,
1495 unsigned section_line
,
1502 unsigned long *personality
= data
, p
;
1507 assert(personality
);
1509 if (isempty(rvalue
)) {
1510 *personality
= PERSONALITY_INVALID
;
1514 p
= personality_from_string(rvalue
);
1515 if (p
== PERSONALITY_INVALID
)
1516 return log_syntax_parse_error(unit
, filename
, line
, 0, lvalue
, rvalue
);
1522 int config_parse_ifname(
1524 const char *filename
,
1526 const char *section
,
1527 unsigned section_line
,
1534 char **s
= ASSERT_PTR(data
);
1541 if (isempty(rvalue
)) {
1546 if (!ifname_valid(rvalue
)) {
1547 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Interface name is not valid or too long, ignoring assignment: %s", rvalue
);
1551 r
= free_and_strdup_warn(s
, rvalue
);
1558 int config_parse_ifnames(
1560 const char *filename
,
1562 const char *section
,
1563 unsigned section_line
,
1570 _cleanup_strv_free_
char **names
= NULL
;
1571 char ***s
= ASSERT_PTR(data
);
1578 if (isempty(rvalue
)) {
1583 for (const char *p
= rvalue
;;) {
1584 _cleanup_free_
char *word
= NULL
;
1586 r
= extract_first_word(&p
, &word
, NULL
, 0);
1588 return log_syntax_parse_error(unit
, filename
, line
, r
, lvalue
, rvalue
);
1592 if (!ifname_valid_full(word
, ltype
)) {
1593 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1594 "Interface name is not valid or too long, ignoring assignment: %s",
1599 r
= strv_consume(&names
, TAKE_PTR(word
));
1604 r
= strv_extend_strv(s
, names
, true);
1611 int config_parse_ip_port(
1613 const char *filename
,
1615 const char *section
,
1616 unsigned section_line
,
1623 uint16_t *s
= ASSERT_PTR(data
);
1631 if (isempty(rvalue
)) {
1636 r
= parse_ip_port(rvalue
, &port
);
1638 return log_syntax_parse_error(unit
, filename
, line
, r
, lvalue
, rvalue
);
1644 int config_parse_mtu(
1646 const char *filename
,
1648 const char *section
,
1649 unsigned section_line
,
1656 uint32_t *mtu
= ASSERT_PTR(data
);
1661 r
= parse_mtu(ltype
, rvalue
, mtu
);
1663 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1664 "Maximum transfer unit (MTU) value out of range. Permitted range is %" PRIu32
"…%" PRIu32
", ignoring: %s",
1665 (uint32_t) (ltype
== AF_INET6
? IPV6_MIN_MTU
: IPV4_MIN_MTU
), (uint32_t) UINT32_MAX
,
1670 return log_syntax_parse_error(unit
, filename
, line
, r
, lvalue
, rvalue
);
1675 int config_parse_rlimit(
1677 const char *filename
,
1679 const char *section
,
1680 unsigned section_line
,
1687 struct rlimit
**rl
= data
, d
= {};
1693 r
= rlimit_parse(ltype
, rvalue
, &d
);
1695 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Soft resource limit chosen higher than hard limit, ignoring: %s", rvalue
);
1699 return log_syntax_parse_error(unit
, filename
, line
, r
, lvalue
, rvalue
);
1704 rl
[ltype
] = newdup(struct rlimit
, &d
, 1);
1712 int config_parse_permille(
1714 const char *filename
,
1716 const char *section
,
1717 unsigned section_line
,
1724 unsigned *permille
= ASSERT_PTR(data
);
1731 r
= parse_permille(rvalue
);
1733 return log_syntax_parse_error(unit
, filename
, line
, r
, lvalue
, rvalue
);
1735 *permille
= (unsigned) r
;
1739 int config_parse_vlanprotocol(
1741 const char *filename
,
1743 const char *section
,
1744 unsigned section_line
,
1751 int *vlan_protocol
= data
;
1756 if (isempty(rvalue
)) {
1757 *vlan_protocol
= -1;
1761 if (STR_IN_SET(rvalue
, "802.1ad", "802.1AD"))
1762 *vlan_protocol
= ETH_P_8021AD
;
1763 else if (STR_IN_SET(rvalue
, "802.1q", "802.1Q"))
1764 *vlan_protocol
= ETH_P_8021Q
;
1766 return log_syntax_parse_error(unit
, filename
, line
, 0, lvalue
, rvalue
);
1771 int config_parse_hw_addr(
1773 const char *filename
,
1775 const char *section
,
1776 unsigned section_line
,
1783 struct hw_addr_data
*hwaddr
= ASSERT_PTR(data
);
1790 if (isempty(rvalue
)) {
1791 *hwaddr
= HW_ADDR_NULL
;
1795 r
= parse_hw_addr_full(rvalue
, ltype
, hwaddr
);
1797 return log_syntax_parse_error(unit
, filename
, line
, r
, lvalue
, rvalue
);
1802 int config_parse_hw_addrs(
1804 const char *filename
,
1806 const char *section
,
1807 unsigned section_line
,
1814 Set
**hwaddrs
= ASSERT_PTR(data
);
1821 if (isempty(rvalue
)) {
1822 /* Empty assignment resets the list */
1823 *hwaddrs
= set_free(*hwaddrs
);
1827 for (const char *p
= rvalue
;;) {
1828 _cleanup_free_
char *word
= NULL
;
1829 _cleanup_free_
struct hw_addr_data
*n
= NULL
;
1831 r
= extract_first_word(&p
, &word
, NULL
, 0);
1833 return log_syntax_parse_error(unit
, filename
, line
, r
, lvalue
, rvalue
);
1837 n
= new(struct hw_addr_data
, 1);
1841 r
= parse_hw_addr_full(word
, ltype
, n
);
1843 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1844 "Not a valid hardware address, ignoring: %s", word
);
1848 r
= set_ensure_consume(hwaddrs
, &hw_addr_hash_ops_free
, TAKE_PTR(n
));
1854 int config_parse_ether_addr(
1856 const char *filename
,
1858 const char *section
,
1859 unsigned section_line
,
1866 _cleanup_free_
struct ether_addr
*n
= NULL
;
1867 struct ether_addr
**hwaddr
= ASSERT_PTR(data
);
1874 if (isempty(rvalue
)) {
1875 *hwaddr
= mfree(*hwaddr
);
1879 n
= new0(struct ether_addr
, 1);
1883 r
= parse_ether_addr(rvalue
, n
);
1885 return log_syntax_parse_error(unit
, filename
, line
, r
, lvalue
, rvalue
);
1887 free_and_replace(*hwaddr
, n
);
1891 int config_parse_ether_addrs(
1893 const char *filename
,
1895 const char *section
,
1896 unsigned section_line
,
1903 Set
**hwaddrs
= ASSERT_PTR(data
);
1910 if (isempty(rvalue
)) {
1911 /* Empty assignment resets the list */
1912 *hwaddrs
= set_free(*hwaddrs
);
1916 for (const char *p
= rvalue
;;) {
1917 _cleanup_free_
char *word
= NULL
;
1918 _cleanup_free_
struct ether_addr
*n
= NULL
;
1920 r
= extract_first_word(&p
, &word
, NULL
, 0);
1922 return log_syntax_parse_error(unit
, filename
, line
, r
, lvalue
, rvalue
);
1926 n
= new(struct ether_addr
, 1);
1930 r
= parse_ether_addr(word
, n
);
1932 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1933 "Not a valid MAC address, ignoring: %s", word
);
1937 r
= set_ensure_consume(hwaddrs
, ðer_addr_hash_ops_free
, TAKE_PTR(n
));
1943 int config_parse_in_addr_non_null(
1945 const char *filename
,
1947 const char *section
,
1948 unsigned section_line
,
1955 /* data must be a pointer to struct in_addr or in6_addr, and the type is determined by ltype. */
1956 struct in_addr
*ipv4
= ASSERT_PTR(data
);
1957 struct in6_addr
*ipv6
= ASSERT_PTR(data
);
1958 union in_addr_union a
;
1964 assert(IN_SET(ltype
, AF_INET
, AF_INET6
));
1966 if (isempty(rvalue
)) {
1967 if (ltype
== AF_INET
)
1968 *ipv4
= (struct in_addr
) {};
1970 *ipv6
= (struct in6_addr
) {};
1974 r
= in_addr_from_string(ltype
, rvalue
, &a
);
1976 return log_syntax_parse_error(unit
, filename
, line
, r
, lvalue
, rvalue
);
1978 if (!in_addr_is_set(ltype
, &a
)) {
1979 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1980 "%s= cannot be the ANY address, ignoring: %s", lvalue
, rvalue
);
1984 if (ltype
== AF_INET
)
1991 int config_parse_in_addr_data(
1993 const char *filename
,
1995 const char *section
,
1996 unsigned section_line
,
2003 struct in_addr_data
*p
= ASSERT_PTR(data
);
2009 if (isempty(rvalue
)) {
2010 *p
= (struct in_addr_data
) {};
2014 r
= in_addr_from_string_auto(rvalue
, &p
->family
, &p
->address
);
2016 return log_syntax_parse_error(unit
, filename
, line
, r
, lvalue
, rvalue
);
2021 int config_parse_in_addr_prefix(
2023 const char *filename
,
2025 const char *section
,
2026 unsigned section_line
,
2028 int ltype
, /* takes boolean, whether we warn about missing prefixlen */
2033 struct in_addr_prefix
*p
= ASSERT_PTR(data
);
2039 if (isempty(rvalue
)) {
2040 *p
= (struct in_addr_prefix
) {};
2044 r
= in_addr_prefix_from_string_auto_full(rvalue
, ltype
? PREFIXLEN_REFUSE
: PREFIXLEN_FULL
, &p
->family
, &p
->address
, &p
->prefixlen
);
2046 r
= in_addr_prefix_from_string_auto(rvalue
, &p
->family
, &p
->address
, &p
->prefixlen
);
2048 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2049 "%s=%s is specified without prefix length. Assuming the prefix length is %u. "
2050 "Please specify the prefix length explicitly.", lvalue
, rvalue
, p
->prefixlen
);
2053 return log_syntax_parse_error(unit
, filename
, line
, r
, lvalue
, rvalue
);
2058 int config_parse_unsigned_bounded(
2060 const char *filename
,
2062 const char *section
,
2063 unsigned section_line
,
2078 r
= safe_atou_bounded(rvalue
, min
, max
, ret
);
2080 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2081 "Invalid '%s=%s', allowed range is %u..%u%s.",
2082 lvalue
, rvalue
, min
, max
, ignoring
? ", ignoring" : "");
2083 return ignoring
? 0 : r
;
2086 return log_syntax_parse_error_full(unit
, filename
, line
, r
, /* critical = */ !ignoring
, lvalue
, rvalue
);
2088 return 1; /* Return 1 if something was set */
2091 int config_parse_calendar(
2093 const char *filename
,
2095 const char *section
,
2096 unsigned section_line
,
2103 CalendarSpec
**cr
= data
;
2104 _cleanup_(calendar_spec_freep
) CalendarSpec
*c
= NULL
;
2112 if (isempty(rvalue
)) {
2113 *cr
= calendar_spec_free(*cr
);
2117 r
= calendar_spec_from_string(rvalue
, &c
);
2119 return log_syntax_parse_error(unit
, filename
, line
, r
, lvalue
, rvalue
);
2121 free_and_replace_full(*cr
, c
, calendar_spec_free
);
2125 DEFINE_CONFIG_PARSE(config_parse_percent
, parse_percent
);
2126 DEFINE_CONFIG_PARSE(config_parse_permyriad
, parse_permyriad
);
2127 DEFINE_CONFIG_PARSE_PTR(config_parse_sec_fix_0
, parse_sec_fix_0
, usec_t
);
2129 int config_parse_timezone(
2131 const char *filename
,
2133 const char *section
,
2134 unsigned section_line
,
2141 char **tz
= ASSERT_PTR(data
);
2148 if (isempty(rvalue
)) {
2153 r
= verify_timezone(rvalue
, LOG_WARNING
);
2155 return log_syntax_parse_error(unit
, filename
, line
, r
, lvalue
, rvalue
);
2157 r
= free_and_strdup_warn(tz
, rvalue
);
2164 int config_parse_ip_protocol(
2166 const char *filename
,
2168 const char *section
,
2169 unsigned section_line
,
2176 uint8_t *proto
= ASSERT_PTR(data
);
2179 r
= isempty(rvalue
) ? 0 : parse_ip_protocol_full(rvalue
, /* relaxed= */ ltype
);
2181 return log_syntax_parse_error(unit
, filename
, line
, r
, lvalue
, rvalue
);
2183 if (r
> UINT8_MAX
) {
2184 /* linux/fib_rules.h and linux/fou.h define the netlink field as one byte, so we need to
2185 * reject protocols numbers that don't fit in one byte. */
2186 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2187 "Invalid '%s=%s', allowed range is 0..255, ignoring.",
2193 return 1; /* done. */
2196 int config_parse_loadavg(
2198 const char *filename
,
2200 const char *section
,
2201 unsigned section_line
,
2208 loadavg_t
*i
= ASSERT_PTR(data
);
2213 r
= parse_permyriad(rvalue
);
2215 return log_syntax_parse_error(unit
, filename
, line
, r
, lvalue
, rvalue
);
2217 r
= store_loadavg_fixed_point(r
/ 100, r
% 100, i
);
2219 return log_syntax_parse_error(unit
, filename
, line
, r
, lvalue
, rvalue
);
2221 return 1; /* done. */