1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
10 #include "alloc-util.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-util.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"
37 #include "signal-util.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 name '%s' in section '%s', ignoring.", lvalue
, section
);
167 /* Parse a single logical line */
168 static int parse_line(
170 const char *filename
,
172 const char *sections
,
173 ConfigItemLookup lookup
,
175 ConfigParseFlags flags
,
177 unsigned *section_line
,
178 bool *section_ignored
,
179 char *l
, /* is modified */
196 if (!utf8_is_valid(l
))
197 return log_syntax_invalid_utf8(unit
, LOG_WARNING
, filename
, line
, l
);
200 _cleanup_free_
char *n
= NULL
;
207 return log_syntax(unit
, LOG_ERR
, filename
, line
, SYNTHETIC_ERRNO(EBADMSG
), "Invalid section header '%s'", l
);
209 n
= strndup(l
+1, k
-2);
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
);
216 if (sections
&& !nulstr_contains(sections
, n
)) {
219 ignore
= (flags
& CONFIG_PARSE_RELAXED
) || startswith(n
, "X-");
222 NULSTR_FOREACH(t
, sections
)
223 if (streq_ptr(n
, startswith(t
, "-"))) { /* Ignore sections prefixed with "-" in valid section list */
229 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Unknown section '%s'. Ignoring.", n
);
231 *section
= mfree(*section
);
233 *section_ignored
= true;
235 free_and_replace(*section
, n
);
236 *section_line
= line
;
237 *section_ignored
= false;
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.");
252 return log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
253 "Missing '=', ignoring line.");
255 return log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
256 "Missing key name before '=', ignoring line.");
261 return next_assignment(unit
,
274 /* Go through the file and parse each line */
277 const char *filename
,
279 const char *sections
,
280 ConfigItemLookup lookup
,
282 ConfigParseFlags flags
,
284 struct stat
*ret_stat
) {
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;
297 f
= ours
= fopen(filename
, "re");
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
);
305 if (errno
== ENOENT
) {
307 *ret_stat
= (struct stat
) {};
317 if (fd
>= 0) { /* stream might not have an fd, let's be careful hence */
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
);
323 (void) stat_warn_permissions(filename
, &st
);
325 st
= (struct stat
) {};
328 _cleanup_free_
char *buf
= NULL
;
329 bool escaped
= false;
332 r
= read_line(f
, LONG_LINE_MAX
, &buf
);
336 if (flags
& CONFIG_PARSE_WARN
)
337 log_error_errno(r
, "%s:%u: Line too long", filename
, line
);
342 if (FLAGS_SET(flags
, CONFIG_PARSE_WARN
))
343 log_error_errno(r
, "%s:%u: Error while reading configuration file: %m", filename
, line
);
350 l
= skip_leading_chars(buf
, WHITESPACE
);
351 if (*l
!= '\0' && strchr(COMMENTS
, *l
))
358 q
= startswith(buf
, UTF8_BYTE_ORDER_MARK
);
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
);
372 if (!strextend(&continuation
, l
)) {
373 if (flags
& CONFIG_PARSE_WARN
)
382 for (e
= p
; *e
; e
++) {
393 continuation
= strdup(l
);
395 if (flags
& CONFIG_PARSE_WARN
)
417 if (flags
& CONFIG_PARSE_WARN
)
418 log_warning_errno(r
, "%s:%u: Failed to parse file: %m", filename
, line
);
422 continuation
= mfree(continuation
);
439 if (flags
& CONFIG_PARSE_WARN
)
440 log_warning_errno(r
, "%s:%u: Failed to parse file: %m", filename
, line
);
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
;
456 assert(stats_by_path
);
460 r
= hashmap_ensure_allocated(stats_by_path
, &path_hash_ops_free_free
);
464 st_copy
= newdup(struct stat
, st
, 1);
468 path_copy
= strdup(path
);
472 r
= hashmap_put(*stats_by_path
, path_copy
, st_copy
);
482 static int config_parse_many_files(
483 const char* const* conf_files
,
485 const char *sections
,
486 ConfigItemLookup lookup
,
488 ConfigParseFlags flags
,
490 Hashmap
**ret_stats_by_path
) {
492 _cleanup_hashmap_free_ Hashmap
*stats_by_path
= NULL
;
493 _cleanup_ordered_hashmap_free_ OrderedHashmap
*dropins
= NULL
;
494 _cleanup_set_free_ Set
*inodes
= NULL
;
498 if (ret_stats_by_path
) {
499 stats_by_path
= hashmap_new(&path_hash_ops_free_free
);
504 STRV_FOREACH(fn
, files
) {
505 _cleanup_free_
struct stat
*st_dropin
= NULL
;
506 _cleanup_fclose_
FILE *f
= NULL
;
509 f
= fopen(*fn
, "re");
519 r
= ordered_hashmap_ensure_put(&dropins
, &config_file_hash_ops_fclose
, *fn
, f
);
521 assert(r
!= -EEXIST
);
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. */
530 st_dropin
= new(struct stat
, 1);
534 if (fstat(fd
, st_dropin
) < 0)
537 r
= set_ensure_consume(&inodes
, &inode_hash_ops
, TAKE_PTR(st_dropin
));
542 /* First read the first found main config file. */
543 STRV_FOREACH(fn
, conf_files
) {
544 _cleanup_fclose_
FILE *f
= NULL
;
546 f
= fopen(*fn
, "re");
555 if (fstat(fileno(f
), &st
) < 0)
558 if (set_contains(inodes
, &st
)) {
559 log_debug("%s: symlink to/symlinked as drop-in, will be read later.", *fn
);
564 r
= config_parse(NULL
, *fn
, f
, sections
, lookup
, table
, flags
, userdata
, &st
);
569 if (ret_stats_by_path
) {
570 r
= hashmap_put_stats_by_path(&stats_by_path
, *fn
, &st
);
578 /* Then read all the drop-ins. */
580 const char *path_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
);
588 if (ret_stats_by_path
) {
589 r
= hashmap_put_stats_by_path(&stats_by_path
, path_dropin
, &st
);
595 if (ret_stats_by_path
)
596 *ret_stats_by_path
= TAKE_PTR(stats_by_path
);
601 /* Parse one main config file located in /etc/systemd and its drop-ins, which is what all systemd daemons
603 int config_parse_config_file(
604 const char *conf_file
,
605 const char *sections
,
606 ConfigItemLookup lookup
,
608 ConfigParseFlags flags
,
611 _cleanup_strv_free_
char **dropins
= NULL
, **dropin_dirs
= NULL
;
612 char **conf_paths
= CONF_PATHS_STRV("");
617 /* build the dropin dir list */
618 dropin_dirs
= new0(char*, strv_length(conf_paths
) + 1);
620 if (flags
& CONFIG_PARSE_WARN
)
626 STRV_FOREACH(p
, conf_paths
) {
629 d
= strjoin(*p
, "systemd/", conf_file
, ".d");
631 if (flags
& CONFIG_PARSE_WARN
)
636 dropin_dirs
[i
++] = d
;
639 r
= conf_files_list_strv(&dropins
, ".conf", NULL
, 0, (const char**) dropin_dirs
);
643 const char *sysconf_file
= strjoina(PKGSYSCONFDIR
, "/", conf_file
);
645 return config_parse_many_files(STRV_MAKE_CONST(sysconf_file
), dropins
,
646 sections
, lookup
, table
, flags
, userdata
, NULL
);
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
,
655 const char *sections
,
656 ConfigItemLookup lookup
,
658 ConfigParseFlags flags
,
660 Hashmap
**ret_stats_by_path
,
661 char ***ret_dropin_files
) {
663 _cleanup_strv_free_
char **files
= NULL
;
666 assert(conf_file_dirs
);
667 assert(dropin_dirname
);
671 r
= conf_files_list_dropins(&files
, dropin_dirname
, root
, conf_file_dirs
);
675 r
= config_parse_many_files(conf_files
, files
, sections
, lookup
, table
, flags
, userdata
, ret_stats_by_path
);
679 if (ret_dropin_files
)
680 *ret_dropin_files
= TAKE_PTR(files
);
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
) {
690 _cleanup_strv_free_
char **files
= NULL
;
691 _cleanup_free_
char *dropin_dirname
= NULL
;
695 assert(conf_file_dirs
);
696 assert(stats_by_path
);
698 r
= path_extract_filename(conf_file
, &dropin_dirname
);
701 if (r
== O_DIRECTORY
)
704 if (!strextend(&dropin_dirname
, ".d"))
707 r
= conf_files_list_dropins(&files
, dropin_dirname
, /* root = */ NULL
, conf_file_dirs
);
711 STRV_FOREACH(fn
, files
) {
714 if (stat(*fn
, &st
) < 0) {
721 r
= hashmap_put_stats_by_path(stats_by_path
, *fn
, &st
);
729 int config_get_stats_by_path(
733 const char* const* dirs
,
737 _cleanup_hashmap_free_ Hashmap
*stats_by_path
= NULL
;
738 _cleanup_strv_free_
char **files
= NULL
;
745 /* Unlike config_parse(), this does not support stream. */
747 r
= conf_files_list_strv(&files
, suffix
, root
, flags
, dirs
);
751 STRV_FOREACH(f
, files
) {
754 /* First read the main config file. */
755 if (stat(*f
, &st
) < 0) {
762 r
= hashmap_put_stats_by_path(&stats_by_path
, *f
, &st
);
769 /* Then read all the drop-ins if requested. */
770 r
= dropins_get_stats_by_path(*f
, dirs
, &stats_by_path
);
775 *ret
= TAKE_PTR(stats_by_path
);
779 bool stats_by_path_equal(Hashmap
*a
, Hashmap
*b
) {
780 struct stat
*st_a
, *st_b
;
783 if (hashmap_size(a
) != hashmap_size(b
))
786 HASHMAP_FOREACH_KEY(st_a
, path
, a
) {
787 st_b
= hashmap_get(b
, path
);
791 if (!stat_inode_unmodified(st_a
, st_b
))
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
);
803 static int config_section_compare_func(const ConfigSection
*x
, const ConfigSection
*y
) {
806 r
= strcmp(x
->filename
, y
->filename
);
810 return CMP(x
->line
, y
->line
);
813 DEFINE_HASH_OPS(config_section_hash_ops
, ConfigSection
, config_section_hash_func
, config_section_compare_func
);
815 int config_section_new(const char *filename
, unsigned line
, ConfigSection
**ret
) {
822 cs
= malloc0(offsetof(ConfigSection
, filename
) + strlen(filename
) + 1);
826 strcpy(cs
->filename
, filename
);
833 int _hashmap_by_section_find_unused_line(
834 HashmapBase
*entries_by_section
,
835 const char *filename
,
842 HASHMAP_BASE_FOREACH_KEY(entry
, cs
, entries_by_section
) {
843 if (filename
&& !streq(cs
->filename
, filename
))
845 n
= MAX(n
, cs
->line
);
856 #define DEFINE_PARSER(type, vartype, conv_func) \
857 DEFINE_CONFIG_PARSE_PTR(config_parse_##type, conv_func, vartype, "Failed to parse " #type " value")
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
);
874 int config_parse_iec_size(
876 const char *filename
,
879 unsigned section_line
,
886 size_t *sz
= ASSERT_PTR(data
);
894 r
= parse_size(rvalue
, 1024, &v
);
895 if (r
>= 0 && (uint64_t) (size_t) v
!= v
)
898 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to parse size value '%s', ignoring: %m", rvalue
);
906 int config_parse_si_uint64(
908 const char *filename
,
911 unsigned section_line
,
918 uint64_t *sz
= ASSERT_PTR(data
);
925 r
= parse_size(rvalue
, 1000, sz
);
927 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to parse size value '%s', ignoring: %m", rvalue
);
932 int config_parse_iec_uint64(
934 const char *filename
,
937 unsigned section_line
,
944 uint64_t *bytes
= ASSERT_PTR(data
);
951 r
= parse_size(rvalue
, 1024, bytes
);
953 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to parse size value, ignoring: %s", rvalue
);
958 int config_parse_iec_uint64_infinity(
960 const char *filename
,
963 unsigned section_line
,
970 uint64_t *bytes
= ASSERT_PTR(data
);
974 if (streq(rvalue
, "infinity")) {
979 return config_parse_iec_uint64(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, rvalue
, data
, userdata
);
982 int config_parse_bool(
984 const char *filename
,
987 unsigned section_line
,
995 bool *b
= ASSERT_PTR(data
);
1002 k
= parse_boolean(rvalue
);
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;
1014 int config_parse_id128(
1016 const char *filename
,
1018 const char *section
,
1019 unsigned section_line
,
1026 sd_id128_t
*result
= data
;
1033 r
= id128_from_string_nonzero(rvalue
, result
);
1035 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "128-bit ID/UUID is all 0, ignoring: %s", rvalue
);
1037 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to parse 128-bit ID/UUID, ignoring: %s", rvalue
);
1042 int config_parse_tristate(
1044 const char *filename
,
1046 const char *section
,
1047 unsigned section_line
,
1054 int r
, *t
= ASSERT_PTR(data
);
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. */
1063 if (isempty(rvalue
)) {
1068 r
= parse_tristate(rvalue
, t
);
1070 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1071 "Failed to parse boolean value for %s=, ignoring: %s", lvalue
, rvalue
);
1078 int config_parse_string(
1080 const char *filename
,
1082 const char *section
,
1083 unsigned section_line
,
1090 char **s
= ASSERT_PTR(data
);
1096 if (isempty(rvalue
)) {
1101 if (FLAGS_SET(ltype
, CONFIG_PARSE_STRING_SAFE
) && !string_is_safe(rvalue
)) {
1102 _cleanup_free_
char *escaped
= NULL
;
1104 escaped
= cescape(rvalue
);
1105 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1106 "Specified string contains unsafe characters, ignoring: %s", strna(escaped
));
1110 if (FLAGS_SET(ltype
, CONFIG_PARSE_STRING_ASCII
) && !ascii_is_valid(rvalue
)) {
1111 _cleanup_free_
char *escaped
= NULL
;
1113 escaped
= cescape(rvalue
);
1114 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1115 "Specified string contains invalid ASCII characters, ignoring: %s", strna(escaped
));
1119 return free_and_strdup_warn(s
, empty_to_null(rvalue
));
1122 int config_parse_dns_name(
1124 const char *filename
,
1126 const char *section
,
1127 unsigned section_line
,
1134 char **hostname
= ASSERT_PTR(data
);
1141 if (isempty(rvalue
)) {
1142 *hostname
= mfree(*hostname
);
1146 r
= dns_name_is_valid(rvalue
);
1148 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1149 "Failed to check validity of DNS domain name '%s', ignoring assignment: %m", rvalue
);
1153 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1154 "Specified invalid DNS domain name, ignoring assignment: %s", rvalue
);
1158 return free_and_strdup_warn(hostname
, rvalue
);
1161 int config_parse_hostname(
1163 const char *filename
,
1165 const char *section
,
1166 unsigned section_line
,
1173 char **hostname
= ASSERT_PTR(data
);
1179 if (isempty(rvalue
)) {
1180 *hostname
= mfree(*hostname
);
1184 if (!hostname_is_valid(rvalue
, 0)) {
1185 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1186 "Specified invalid hostname, ignoring assignment: %s", rvalue
);
1190 return config_parse_dns_name(unit
, filename
, line
, section
, section_line
,
1191 lvalue
, ltype
, rvalue
, data
, userdata
);
1194 int config_parse_path(
1196 const char *filename
,
1198 const char *section
,
1199 unsigned section_line
,
1206 _cleanup_free_
char *n
= NULL
;
1208 char **s
= ASSERT_PTR(data
);
1215 if (isempty(rvalue
))
1222 r
= path_simplify_and_warn(n
, PATH_CHECK_ABSOLUTE
| (fatal
? PATH_CHECK_FATAL
: 0), unit
, filename
, line
, lvalue
);
1224 return fatal
? -ENOEXEC
: 0;
1227 return free_and_replace(*s
, n
);
1230 int config_parse_strv(
1232 const char *filename
,
1234 const char *section
,
1235 unsigned section_line
,
1242 char ***sv
= ASSERT_PTR(data
);
1249 if (isempty(rvalue
)) {
1250 *sv
= strv_free(*sv
);
1254 for (const char *p
= rvalue
;;) {
1257 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_UNQUOTE
|EXTRACT_RETAIN_ESCAPE
);
1263 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Invalid syntax, ignoring: %s", rvalue
);
1267 r
= strv_consume(sv
, word
);
1273 int config_parse_warn_compat(
1275 const char *filename
,
1277 const char *section
,
1278 unsigned section_line
,
1285 Disabled reason
= ltype
;
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
);
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
);
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
);
1308 int config_parse_log_facility(
1310 const char *filename
,
1312 const char *section
,
1313 unsigned section_line
,
1327 x
= log_facility_unshifted_from_string(rvalue
);
1329 log_syntax(unit
, LOG_WARNING
, filename
, line
, x
, "Failed to parse log facility, ignoring: %s", rvalue
);
1333 *o
= (x
<< 3) | LOG_PRI(*o
);
1338 int config_parse_log_level(
1340 const char *filename
,
1342 const char *section
,
1343 unsigned section_line
,
1357 x
= log_level_from_string(rvalue
);
1359 log_syntax(unit
, LOG_WARNING
, filename
, line
, x
, "Failed to parse log level, ignoring: %s", rvalue
);
1363 if (*o
< 0) /* if it wasn't initialized so far, assume zero facility */
1366 *o
= (*o
& LOG_FACMASK
) | x
;
1371 int config_parse_signal(
1373 const char *filename
,
1375 const char *section
,
1376 unsigned section_line
,
1390 r
= signal_from_string(rvalue
);
1392 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to parse signal name, ignoring: %s", rvalue
);
1400 int config_parse_personality(
1402 const char *filename
,
1404 const char *section
,
1405 unsigned section_line
,
1412 unsigned long *personality
= data
, p
;
1417 assert(personality
);
1419 if (isempty(rvalue
))
1420 p
= PERSONALITY_INVALID
;
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
);
1433 int config_parse_ifname(
1435 const char *filename
,
1437 const char *section
,
1438 unsigned section_line
,
1445 char **s
= ASSERT_PTR(data
);
1452 if (isempty(rvalue
)) {
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
);
1462 r
= free_and_strdup(s
, rvalue
);
1469 int config_parse_ifnames(
1471 const char *filename
,
1473 const char *section
,
1474 unsigned section_line
,
1481 _cleanup_strv_free_
char **names
= NULL
;
1482 char ***s
= ASSERT_PTR(data
);
1489 if (isempty(rvalue
)) {
1494 for (const char *p
= rvalue
;;) {
1495 _cleanup_free_
char *word
= NULL
;
1497 r
= extract_first_word(&p
, &word
, NULL
, 0);
1501 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1502 "Failed to extract interface name, ignoring assignment: %s",
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",
1516 r
= strv_consume(&names
, TAKE_PTR(word
));
1521 r
= strv_extend_strv(s
, names
, true);
1528 int config_parse_ip_port(
1530 const char *filename
,
1532 const char *section
,
1533 unsigned section_line
,
1540 uint16_t *s
= ASSERT_PTR(data
);
1548 if (isempty(rvalue
)) {
1553 r
= parse_ip_port(rvalue
, &port
);
1555 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to parse port '%s'.", rvalue
);
1564 int config_parse_mtu(
1566 const char *filename
,
1568 const char *section
,
1569 unsigned section_line
,
1576 uint32_t *mtu
= ASSERT_PTR(data
);
1581 r
= parse_mtu(ltype
, rvalue
, mtu
);
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
,
1590 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1591 "Failed to parse MTU value '%s', ignoring: %m", rvalue
);
1598 int config_parse_rlimit(
1600 const char *filename
,
1602 const char *section
,
1603 unsigned section_line
,
1610 struct rlimit
**rl
= data
, d
= {};
1616 r
= rlimit_parse(ltype
, rvalue
, &d
);
1618 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Soft resource limit chosen higher than hard limit, ignoring: %s", rvalue
);
1622 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to parse resource value, ignoring: %s", rvalue
);
1629 rl
[ltype
] = newdup(struct rlimit
, &d
, 1);
1637 int config_parse_permille(
1639 const char *filename
,
1641 const char *section
,
1642 unsigned section_line
,
1649 unsigned *permille
= ASSERT_PTR(data
);
1656 r
= parse_permille(rvalue
);
1658 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1659 "Failed to parse permille value, ignoring: %s", rvalue
);
1663 *permille
= (unsigned) r
;
1668 int config_parse_vlanprotocol(
1670 const char *filename
,
1672 const char *section
,
1673 unsigned section_line
,
1680 int *vlan_protocol
= data
;
1685 if (isempty(rvalue
)) {
1686 *vlan_protocol
= -1;
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
;
1695 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1696 "Failed to parse VLAN protocol value, ignoring: %s", rvalue
);
1703 int config_parse_hw_addr(
1705 const char *filename
,
1707 const char *section
,
1708 unsigned section_line
,
1715 struct hw_addr_data a
, *hwaddr
= ASSERT_PTR(data
);
1722 if (isempty(rvalue
)) {
1723 *hwaddr
= HW_ADDR_NULL
;
1727 r
= parse_hw_addr_full(rvalue
, ltype
, &a
);
1729 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1730 "Not a valid hardware address, ignoring assignment: %s", rvalue
);
1738 int config_parse_hw_addrs(
1740 const char *filename
,
1742 const char *section
,
1743 unsigned section_line
,
1750 Set
**hwaddrs
= ASSERT_PTR(data
);
1757 if (isempty(rvalue
)) {
1758 /* Empty assignment resets the list */
1759 *hwaddrs
= set_free(*hwaddrs
);
1763 for (const char *p
= rvalue
;;) {
1764 _cleanup_free_
char *word
= NULL
;
1765 _cleanup_free_
struct hw_addr_data
*n
= NULL
;
1767 r
= extract_first_word(&p
, &word
, NULL
, 0);
1773 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1774 "Invalid syntax, ignoring: %s", rvalue
);
1778 n
= new(struct hw_addr_data
, 1);
1782 r
= parse_hw_addr_full(word
, ltype
, n
);
1784 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1785 "Not a valid hardware address, ignoring: %s", word
);
1789 r
= set_ensure_consume(hwaddrs
, &hw_addr_hash_ops_free
, TAKE_PTR(n
));
1795 int config_parse_ether_addr(
1797 const char *filename
,
1799 const char *section
,
1800 unsigned section_line
,
1807 _cleanup_free_
struct ether_addr
*n
= NULL
;
1808 struct ether_addr
**hwaddr
= ASSERT_PTR(data
);
1815 if (isempty(rvalue
)) {
1816 *hwaddr
= mfree(*hwaddr
);
1820 n
= new0(struct ether_addr
, 1);
1824 r
= parse_ether_addr(rvalue
, n
);
1826 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1827 "Not a valid MAC address, ignoring assignment: %s", rvalue
);
1831 free_and_replace(*hwaddr
, n
);
1836 int config_parse_ether_addrs(
1838 const char *filename
,
1840 const char *section
,
1841 unsigned section_line
,
1848 Set
**hwaddrs
= ASSERT_PTR(data
);
1855 if (isempty(rvalue
)) {
1856 /* Empty assignment resets the list */
1857 *hwaddrs
= set_free(*hwaddrs
);
1861 for (const char *p
= rvalue
;;) {
1862 _cleanup_free_
char *word
= NULL
;
1863 _cleanup_free_
struct ether_addr
*n
= NULL
;
1865 r
= extract_first_word(&p
, &word
, NULL
, 0);
1871 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1872 "Invalid syntax, ignoring: %s", rvalue
);
1876 n
= new(struct ether_addr
, 1);
1880 r
= parse_ether_addr(word
, n
);
1882 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1883 "Not a valid MAC address, ignoring: %s", word
);
1887 r
= set_ensure_consume(hwaddrs
, ðer_addr_hash_ops_free
, TAKE_PTR(n
));
1893 int config_parse_in_addr_non_null(
1895 const char *filename
,
1897 const char *section
,
1898 unsigned section_line
,
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
;
1914 assert(IN_SET(ltype
, AF_INET
, AF_INET6
));
1916 if (isempty(rvalue
)) {
1917 if (ltype
== AF_INET
)
1918 *ipv4
= (struct in_addr
) {};
1920 *ipv6
= (struct in6_addr
) {};
1924 r
= in_addr_from_string(ltype
, rvalue
, &a
);
1926 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1927 "Failed to parse %s=, ignoring assignment: %s", lvalue
, rvalue
);
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
);
1937 if (ltype
== AF_INET
)
1944 int config_parse_unsigned_bounded(
1946 const char *filename
,
1948 const char *section
,
1949 unsigned section_line
,
1964 r
= safe_atou_bounded(value
, min
, max
, ret
);
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" : "");
1970 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1971 "Failed to parse '%s=%s'%s: %m",
1972 name
, value
, ignoring
? ", ignoring" : "");
1975 return 1; /* Return 1 if something was set */
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");