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 */
193 assert(section_line
);
194 assert(section_ignored
);
203 if (!utf8_is_valid(l
))
204 return log_syntax_invalid_utf8(unit
, LOG_WARNING
, filename
, line
, l
);
207 _cleanup_free_
char *n
= NULL
;
214 return log_syntax(unit
, LOG_ERR
, filename
, line
, SYNTHETIC_ERRNO(EBADMSG
), "Invalid section header '%s'", l
);
216 n
= strndup(l
+1, k
-2);
220 if (!string_is_safe(n
, /* flags= */ 0))
221 return log_syntax(unit
, LOG_ERR
, filename
, line
, SYNTHETIC_ERRNO(EBADMSG
), "Section header invalid '%s'", l
);
223 if (sections
&& !nulstr_contains(sections
, n
)) {
226 ignore
= (flags
& CONFIG_PARSE_RELAXED
) || startswith(n
, "X-");
229 NULSTR_FOREACH(t
, sections
)
230 if (streq_ptr(n
, startswith(t
, "-"))) { /* Ignore sections prefixed with "-" in valid section list */
236 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Unknown section '%s'. Ignoring.", n
);
238 *section
= mfree(*section
);
240 *section_ignored
= true;
242 free_and_replace(*section
, n
);
243 *section_line
= line
;
244 *section_ignored
= false;
250 if (sections
&& !*section
) {
251 if (!(flags
& CONFIG_PARSE_RELAXED
) && !*section_ignored
)
252 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Assignment outside of section. Ignoring.");
259 return log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
260 "Missing '=', ignoring line.");
262 return log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
263 "Missing key name before '=', ignoring line.");
268 return next_assignment(unit
,
281 /* Go through the file and parse each line */
284 const char *filename
,
286 const char *sections
,
287 ConfigItemLookup lookup
,
289 ConfigParseFlags flags
,
291 struct stat
*ret_stat
) {
293 _cleanup_free_
char *section
= NULL
, *continuation
= NULL
;
294 _cleanup_fclose_
FILE *ours
= NULL
;
295 unsigned line
= 0, section_line
= 0;
296 bool section_ignored
= false, bom_seen
= false;
304 f
= ours
= fopen(filename
, "re");
306 /* Only log on request, except for ENOENT,
307 * since we return 0 to the caller. */
308 if ((flags
& CONFIG_PARSE_WARN
) || errno
== ENOENT
)
309 log_full_errno(errno
== ENOENT
? LOG_DEBUG
: LOG_ERR
, errno
,
310 "Failed to open configuration file '%s': %m", filename
);
312 if (errno
== ENOENT
) {
314 *ret_stat
= (struct stat
) {};
324 if (fd
>= 0) { /* stream might not have an fd, let's be careful hence */
326 if (fstat(fd
, &st
) < 0)
327 return log_full_errno(FLAGS_SET(flags
, CONFIG_PARSE_WARN
) ? LOG_ERR
: LOG_DEBUG
, errno
,
328 "Failed to fstat(%s): %m", filename
);
330 (void) stat_warn_permissions(filename
, &st
);
332 st
= (struct stat
) {};
335 _cleanup_free_
char *buf
= NULL
;
336 bool escaped
= false;
339 r
= read_line(f
, LONG_LINE_MAX
, &buf
);
343 if (flags
& CONFIG_PARSE_WARN
)
344 log_error_errno(r
, "%s:%u: Line too long", filename
, line
);
349 if (FLAGS_SET(flags
, CONFIG_PARSE_WARN
))
350 log_error_errno(r
, "%s:%u: Error while reading configuration file: %m", filename
, line
);
357 l
= skip_leading_chars(buf
, WHITESPACE
);
358 if (*l
!= '\0' && strchr(COMMENTS
, *l
))
365 q
= startswith(buf
, UTF8_BYTE_ORDER_MARK
);
373 if (strlen(continuation
) + strlen(l
) > LONG_LINE_MAX
) {
374 if (flags
& CONFIG_PARSE_WARN
)
375 log_error("%s:%u: Continuation line too long", filename
, line
);
379 if (!strextend(&continuation
, l
)) {
380 if (flags
& CONFIG_PARSE_WARN
)
389 for (e
= p
; *e
; e
++) {
400 continuation
= strdup(l
);
402 if (flags
& CONFIG_PARSE_WARN
)
424 if (flags
& CONFIG_PARSE_WARN
)
425 log_warning_errno(r
, "%s:%u: Failed to parse file: %m", filename
, line
);
429 continuation
= mfree(continuation
);
446 if (flags
& CONFIG_PARSE_WARN
)
447 log_warning_errno(r
, "%s:%u: Failed to parse file: %m", filename
, line
);
458 int hashmap_put_stats_by_path(Hashmap
**stats_by_path
, const char *path
, const struct stat
*st
) {
459 _cleanup_free_
struct stat
*st_copy
= NULL
;
460 _cleanup_free_
char *path_copy
= NULL
;
463 assert(stats_by_path
);
467 st_copy
= newdup(struct stat
, st
, 1);
471 path_copy
= strdup(path
);
475 r
= hashmap_ensure_put(stats_by_path
, &path_hash_ops_free_free
, path_copy
, st_copy
);
485 static int config_parse_many_files(
488 const char* const* conf_files
,
490 const char *sections
,
491 ConfigItemLookup lookup
,
493 ConfigParseFlags flags
,
495 Hashmap
**ret_stats_by_path
) {
497 _cleanup_hashmap_free_ Hashmap
*stats_by_path
= NULL
;
498 _cleanup_ordered_hashmap_free_ OrderedHashmap
*dropins
= NULL
;
499 _cleanup_set_free_ Set
*inodes
= NULL
;
501 int r
, level
= FLAGS_SET(flags
, CONFIG_PARSE_WARN
) ? LOG_WARNING
: LOG_DEBUG
;
503 if (ret_stats_by_path
) {
504 stats_by_path
= hashmap_new(&path_hash_ops_free_free
);
506 return log_oom_full(level
);
509 /* Pin and stat() all dropins */
510 STRV_FOREACH(fn
, files
) {
511 _cleanup_fclose_
FILE *f
= NULL
;
512 r
= chase_and_fopenat_unlocked(root_fd
, root_fd
, *fn
, CHASE_MUST_BE_REGULAR
, "re", /* ret_path= */ NULL
, &f
);
516 return log_full_errno(level
, r
, "Failed to open %s: %m", *fn
);
521 r
= ordered_hashmap_ensure_put(&dropins
, &config_file_hash_ops_fclose
, *fn
, f
);
523 assert(r
== -ENOMEM
);
524 return log_oom_full(level
);
529 /* Get inodes for all drop-ins. Later we'll verify if main config is a symlink to or is
530 * symlinked as one of them. If so, we skip reading main config file directly. */
532 _cleanup_free_
struct stat
*st_dropin
= new(struct stat
, 1);
534 return log_oom_full(level
);
536 if (fstat(fd
, st_dropin
) < 0)
537 return log_full_errno(level
, errno
, "Failed to stat %s: %m", *fn
);
539 r
= set_ensure_consume(&inodes
, &inode_hash_ops
, TAKE_PTR(st_dropin
));
541 return log_oom_full(level
);
544 /* First process the first found main config file. */
545 STRV_FOREACH(fn
, conf_files
) {
546 _cleanup_fclose_
FILE *f
= NULL
;
547 r
= chase_and_fopenat_unlocked(root_fd
, root_fd
, *fn
, CHASE_MUST_BE_REGULAR
, "re", /* ret_path= */ NULL
, &f
);
551 return log_full_errno(level
, r
, "Failed to open %s: %m", *fn
);
554 if (fstat(fileno(f
), &st
) < 0)
555 return log_full_errno(level
, errno
, "Failed to stat %s: %m", *fn
);
557 if (set_contains(inodes
, &st
)) {
558 log_debug("%s: symlink to/symlinked as drop-in, will be read later.", *fn
);
563 r
= config_parse(/* unit= */ NULL
, *fn
, f
, sections
, lookup
, table
, flags
, userdata
, &st
);
565 return r
; /* config_parse() logs internally. */
568 if (ret_stats_by_path
) {
569 r
= hashmap_put_stats_by_path(&stats_by_path
, *fn
, &st
);
571 return log_full_errno(level
, r
, "Failed to save stats of %s: %m", *fn
);
577 /* Then read all the drop-ins. */
578 const char *path_dropin
;
580 ORDERED_HASHMAP_FOREACH_KEY(f_dropin
, path_dropin
, dropins
) {
581 r
= config_parse(/* unit= */ NULL
, path_dropin
, f_dropin
, sections
, lookup
, table
, flags
, userdata
, &st
);
583 return r
; /* config_parse() logs internally. */
586 if (ret_stats_by_path
) {
587 r
= hashmap_put_stats_by_path(&stats_by_path
, path_dropin
, &st
);
589 return log_full_errno(level
, r
, "Failed to save stats of %s: %m", path_dropin
);
593 if (ret_stats_by_path
)
594 *ret_stats_by_path
= TAKE_PTR(stats_by_path
);
599 static int normalize_root_fd(const char *root
, int *root_fd
, int *ret_opened_fd
) {
601 assert(ret_opened_fd
);
603 /* Normalizes a root dir specification: if root_fd is already valid, keep it. Otherwise, we open the
606 if (wildcard_fd_is_valid(*root_fd
)) {
607 *ret_opened_fd
= -EBADF
;
611 if (empty_or_root(root
)) {
612 *root_fd
= XAT_FDROOT
;
613 *ret_opened_fd
= -EBADF
;
617 int fd
= open(root
, O_CLOEXEC
|O_PATH
|O_DIRECTORY
);
619 return log_error_errno(errno
, "Failed to open root directory '%s': %m", root
);
621 *ret_opened_fd
= *root_fd
= fd
;
625 /* Parse each config file in the directories specified as strv. */
626 int config_parse_many_full(
627 const char* const* conf_files
,
628 const char* const* conf_file_dirs
,
629 const char *dropin_dirname
,
632 const char *sections
,
633 ConfigItemLookup lookup
,
635 ConfigParseFlags flags
,
637 Hashmap
**ret_stats_by_path
,
638 char ***ret_dropin_files
) {
640 _cleanup_strv_free_
char **files
= NULL
;
643 assert(conf_file_dirs
);
644 assert(dropin_dirname
);
647 _cleanup_close_
int opened_root_fd
= -EBADF
;
648 r
= normalize_root_fd(root
, &root_fd
, &opened_root_fd
);
652 r
= conf_files_list_dropins(
657 FLAGS_SET(flags
, CONFIG_PARSE_WARN
) ? CONF_FILES_WARN
: 0,
660 return log_full_errno(FLAGS_SET(flags
, CONFIG_PARSE_WARN
) ? LOG_WARNING
: LOG_DEBUG
, r
,
661 "Failed to list drop-ins in %s: %m", dropin_dirname
);
663 r
= config_parse_many_files(
675 return r
; /* config_parse_many_files() logs internally. */
677 if (ret_dropin_files
)
678 *ret_dropin_files
= TAKE_PTR(files
);
683 int config_parse_standard_file_with_dropins_full(
686 const char *main_file
, /* A path like "systemd/frobnicator.conf" */
687 const char *sections
,
688 ConfigItemLookup lookup
,
690 ConfigParseFlags flags
,
692 Hashmap
**ret_stats_by_path
,
693 char ***ret_dropin_files
) {
695 const char* const *conf_file_dirs
= (const char* const*) CONF_PATHS_STRV("");
696 _cleanup_strv_free_
char **conf_files
= NULL
;
697 int r
, level
= FLAGS_SET(flags
, CONFIG_PARSE_WARN
) ? LOG_WARNING
: LOG_DEBUG
;
699 /* Build the list of main config files */
700 r
= strv_extend_strv_concat(
705 return log_oom_full(level
);
707 _cleanup_free_
char *dropin_dirname
= strjoin(main_file
, ".d");
709 return log_oom_full(level
);
711 return config_parse_many_full(
712 (const char* const*) conf_files
,
726 static int dropins_get_stats_by_path(
727 const char* conf_file
,
728 const char* const* conf_file_dirs
,
729 Hashmap
**stats_by_path
) {
731 _cleanup_strv_free_
char **files
= NULL
;
732 _cleanup_free_
char *dropin_dirname
= NULL
;
736 assert(conf_file_dirs
);
737 assert(stats_by_path
);
739 r
= path_extract_filename(conf_file
, &dropin_dirname
);
742 if (r
== O_DIRECTORY
)
745 if (!strextend(&dropin_dirname
, ".d"))
748 r
= conf_files_list_dropins(
752 /* root_fd= */ XAT_FDROOT
,
758 STRV_FOREACH(fn
, files
) {
761 if (stat(*fn
, &st
) < 0) {
768 r
= hashmap_put_stats_by_path(stats_by_path
, *fn
, &st
);
776 int config_get_stats_by_path(
779 ConfFilesFlags flags
,
780 const char* const* dirs
,
784 _cleanup_hashmap_free_ Hashmap
*stats_by_path
= NULL
;
785 _cleanup_strv_free_
char **files
= NULL
;
792 /* Unlike config_parse(), this does not support stream. */
794 r
= conf_files_list_strv(&files
, suffix
, root
, flags
, dirs
);
798 STRV_FOREACH(f
, files
) {
801 /* First read the main config file. */
802 if (stat(*f
, &st
) < 0) {
809 /* Skipping an empty file. */
810 if (null_or_empty(&st
))
813 r
= hashmap_put_stats_by_path(&stats_by_path
, *f
, &st
);
820 /* Then read all the drop-ins if requested. */
821 r
= dropins_get_stats_by_path(*f
, dirs
, &stats_by_path
);
826 *ret
= TAKE_PTR(stats_by_path
);
830 bool stats_by_path_equal(Hashmap
*a
, Hashmap
*b
) {
831 struct stat
*st_a
, *st_b
;
834 if (hashmap_size(a
) != hashmap_size(b
))
837 HASHMAP_FOREACH_KEY(st_a
, path
, a
) {
838 st_b
= hashmap_get(b
, path
);
842 if (!stat_inode_unmodified(st_a
, st_b
))
849 int config_section_parse(
850 const ConfigSectionParser
*parsers
,
853 const char *filename
,
856 unsigned section_line
,
863 assert(n_parsers
> 0);
865 assert((size_t) ltype
< n_parsers
);
868 const ConfigSectionParser
*e
= parsers
+ ltype
;
871 /* This is used when a object is dynamically allocated per [SECTION] in a config parser, e.g.
872 * [Address] for systemd.network. Takes the allocated object as 'userdata', then it is passed to
873 * config parsers in the table. The 'data' field points to an element of the passed object, where
874 * its offset is given by the table. */
876 return e
->parser(unit
, filename
, line
, section
, section_line
, lvalue
, e
->ltype
, rvalue
,
877 (uint8_t*) userdata
+ e
->offset
, userdata
);
880 void config_section_hash_func(const ConfigSection
*c
, struct siphash
*state
) {
881 siphash24_compress_string(c
->filename
, state
);
882 siphash24_compress_typesafe(c
->line
, state
);
885 int config_section_compare_func(const ConfigSection
*x
, const ConfigSection
*y
) {
888 r
= strcmp(x
->filename
, y
->filename
);
892 return CMP(x
->line
, y
->line
);
895 DEFINE_HASH_OPS(config_section_hash_ops
, ConfigSection
, config_section_hash_func
, config_section_compare_func
);
897 int config_section_new(const char *filename
, unsigned line
, ConfigSection
**ret
) {
904 cs
= malloc0(offsetof(ConfigSection
, filename
) + strlen(filename
) + 1);
908 strcpy(cs
->filename
, filename
);
915 static int _hashmap_by_section_find_unused_line(
916 HashmapBase
*entries_by_section
,
917 const char *filename
,
926 HASHMAP_BASE_FOREACH_KEY(entry
, cs
, entries_by_section
) {
927 if (filename
&& !streq(cs
->filename
, filename
))
929 n
= MAX(n
, cs
->line
);
940 int hashmap_by_section_find_unused_line(
941 Hashmap
*entries_by_section
,
942 const char *filename
,
945 return _hashmap_by_section_find_unused_line(HASHMAP_BASE(entries_by_section
), filename
, ret
);
948 int ordered_hashmap_by_section_find_unused_line(
949 OrderedHashmap
*entries_by_section
,
950 const char *filename
,
953 return _hashmap_by_section_find_unused_line(HASHMAP_BASE(entries_by_section
), filename
, ret
);
956 #define DEFINE_PARSER(type, vartype, conv_func) \
957 DEFINE_CONFIG_PARSE_PTR(config_parse_##type, conv_func, vartype)
959 DEFINE_PARSER(int, int, safe_atoi
);
960 DEFINE_PARSER(long, long, safe_atoli
);
961 DEFINE_PARSER(uint8
, uint8_t, safe_atou8
);
962 DEFINE_PARSER(uint16
, uint16_t, safe_atou16
);
963 DEFINE_PARSER(uint32
, uint32_t, safe_atou32
);
964 DEFINE_PARSER(int32
, int32_t, safe_atoi32
);
965 DEFINE_PARSER(uint64
, uint64_t, safe_atou64
);
966 DEFINE_PARSER(unsigned, unsigned, safe_atou
);
967 DEFINE_PARSER(double, double, safe_atod
);
968 DEFINE_PARSER(nsec
, nsec_t
, parse_nsec
);
969 DEFINE_PARSER(sec
, usec_t
, parse_sec
);
970 DEFINE_PARSER(sec_def_infinity
, usec_t
, parse_sec_def_infinity
);
971 DEFINE_PARSER(mode
, mode_t
, parse_mode
);
972 DEFINE_PARSER(pid
, pid_t
, parse_pid
);
974 int config_parse_iec_size(
976 const char *filename
,
979 unsigned section_line
,
986 size_t *sz
= ASSERT_PTR(data
);
994 r
= parse_size(rvalue
, 1024, &v
);
995 if (r
>= 0 && (uint64_t) (size_t) v
!= v
)
998 return log_syntax_parse_error(unit
, filename
, line
, r
, lvalue
, rvalue
);
1004 int config_parse_iec_size_long(
1006 const char *filename
,
1008 const char *section
,
1009 unsigned section_line
,
1016 long *sz
= ASSERT_PTR(data
);
1024 r
= parse_size(rvalue
, 1024, &v
);
1025 if (r
>= 0 && v
> LONG_MAX
)
1028 return log_syntax_parse_error(unit
, filename
, line
, r
, lvalue
, rvalue
);
1034 int config_parse_si_uint64(
1036 const char *filename
,
1038 const char *section
,
1039 unsigned section_line
,
1046 uint64_t *sz
= ASSERT_PTR(data
);
1053 r
= parse_size(rvalue
, 1000, sz
);
1055 return log_syntax_parse_error(unit
, filename
, line
, r
, lvalue
, rvalue
);
1060 int config_parse_iec_uint64(
1062 const char *filename
,
1064 const char *section
,
1065 unsigned section_line
,
1072 uint64_t *bytes
= ASSERT_PTR(data
);
1079 r
= parse_size(rvalue
, 1024, bytes
);
1081 return log_syntax_parse_error(unit
, filename
, line
, r
, lvalue
, rvalue
);
1086 int config_parse_iec_uint64_infinity(
1088 const char *filename
,
1090 const char *section
,
1091 unsigned section_line
,
1098 uint64_t *bytes
= ASSERT_PTR(data
);
1102 if (streq(rvalue
, "infinity")) {
1103 *bytes
= UINT64_MAX
;
1107 return config_parse_iec_uint64(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, rvalue
, data
, userdata
);
1110 int config_parse_bool(
1112 const char *filename
,
1114 const char *section
,
1115 unsigned section_line
,
1122 bool *b
= ASSERT_PTR(data
);
1130 r
= parse_boolean(rvalue
);
1132 log_syntax_parse_error_full(unit
, filename
, line
, r
, fatal
, lvalue
, rvalue
);
1133 return fatal
? -ENOEXEC
: 0;
1140 int config_parse_uint32_flag(
1142 const char *filename
,
1144 const char *section
,
1145 unsigned section_line
,
1152 uint32_t *flags
= ASSERT_PTR(data
);
1157 r
= isempty(rvalue
) ? 0 : parse_boolean(rvalue
);
1159 return log_syntax_parse_error(unit
, filename
, line
, r
, lvalue
, rvalue
);
1161 SET_FLAG(*flags
, ltype
, r
);
1165 int config_parse_uint32_invert_flag(
1167 const char *filename
,
1169 const char *section
,
1170 unsigned section_line
,
1177 uint32_t *flags
= ASSERT_PTR(data
);
1182 r
= isempty(rvalue
) ? 0 : parse_boolean(rvalue
);
1184 return log_syntax_parse_error(unit
, filename
, line
, r
, lvalue
, rvalue
);
1186 SET_FLAG(*flags
, ltype
, !r
);
1190 int config_parse_id128(
1192 const char *filename
,
1194 const char *section
,
1195 unsigned section_line
,
1202 sd_id128_t
*result
= data
;
1209 r
= id128_from_string_nonzero(rvalue
, result
);
1211 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "128-bit ID/UUID is all 0, ignoring: %s", rvalue
);
1215 return log_syntax_parse_error(unit
, filename
, line
, r
, lvalue
, rvalue
);
1220 int config_parse_tristate(
1222 const char *filename
,
1224 const char *section
,
1225 unsigned section_line
,
1232 int r
, *t
= ASSERT_PTR(data
);
1238 /* A tristate is pretty much a boolean, except that it can also take an empty string,
1239 * indicating "uninitialized", much like NULL is for a pointer type. */
1241 if (isempty(rvalue
)) {
1246 r
= parse_tristate(rvalue
, t
);
1248 return log_syntax_parse_error(unit
, filename
, line
, r
, lvalue
, rvalue
);
1253 int config_parse_string(
1255 const char *filename
,
1257 const char *section
,
1258 unsigned section_line
,
1265 char **s
= ASSERT_PTR(data
);
1272 if (isempty(rvalue
)) {
1277 if (FLAGS_SET(ltype
, CONFIG_PARSE_STRING_SAFE
) && !string_is_safe(rvalue
, STRING_ALLOW_GLOBS
)) {
1278 _cleanup_free_
char *escaped
= NULL
;
1280 escaped
= cescape(rvalue
);
1281 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1282 "Specified string contains unsafe characters, ignoring: %s", strna(escaped
));
1286 if (FLAGS_SET(ltype
, CONFIG_PARSE_STRING_ASCII
) && !ascii_is_valid(rvalue
)) {
1287 _cleanup_free_
char *escaped
= NULL
;
1289 escaped
= cescape(rvalue
);
1290 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1291 "Specified string contains invalid ASCII characters, ignoring: %s", strna(escaped
));
1295 r
= free_and_strdup_warn(s
, rvalue
);
1302 int config_parse_dns_name(
1304 const char *filename
,
1306 const char *section
,
1307 unsigned section_line
,
1314 char **hostname
= ASSERT_PTR(data
);
1321 if (isempty(rvalue
)) {
1322 *hostname
= mfree(*hostname
);
1326 r
= dns_name_is_valid(rvalue
);
1328 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1329 "Failed to check validity of DNS domain name '%s', ignoring assignment: %m", rvalue
);
1333 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1334 "Specified invalid DNS domain name, ignoring assignment: %s", rvalue
);
1338 r
= free_and_strdup_warn(hostname
, rvalue
);
1345 int config_parse_hostname(
1347 const char *filename
,
1349 const char *section
,
1350 unsigned section_line
,
1357 char **hostname
= ASSERT_PTR(data
);
1363 if (isempty(rvalue
)) {
1364 *hostname
= mfree(*hostname
);
1368 if (!hostname_is_valid(rvalue
, 0)) {
1369 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1370 "Specified invalid hostname, ignoring assignment: %s", rvalue
);
1374 return config_parse_dns_name(unit
, filename
, line
, section
, section_line
,
1375 lvalue
, ltype
, rvalue
, data
, userdata
);
1378 int config_parse_path(
1380 const char *filename
,
1382 const char *section
,
1383 unsigned section_line
,
1390 _cleanup_free_
char *n
= NULL
;
1392 char **s
= ASSERT_PTR(data
);
1399 if (isempty(rvalue
)) {
1408 r
= path_simplify_and_warn(n
, PATH_CHECK_ABSOLUTE
| (fatal
? PATH_CHECK_FATAL
: 0), unit
, filename
, line
, lvalue
);
1410 return fatal
? -ENOEXEC
: 0;
1412 free_and_replace(*s
, n
);
1416 int config_parse_strv(
1418 const char *filename
,
1420 const char *section
,
1421 unsigned section_line
,
1423 int ltype
, /* When true, duplicated entries will be filtered. */
1428 char ***sv
= ASSERT_PTR(data
);
1435 if (isempty(rvalue
)) {
1436 *sv
= strv_free(*sv
);
1440 _cleanup_strv_free_
char **strv
= NULL
;
1441 for (const char *p
= rvalue
;;) {
1444 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_UNQUOTE
|EXTRACT_RETAIN_ESCAPE
);
1446 return log_syntax_parse_error(unit
, filename
, line
, r
, lvalue
, rvalue
);
1450 r
= strv_consume(&strv
, word
);
1455 r
= strv_extend_strv_consume(sv
, TAKE_PTR(strv
), /* filter_duplicates= */ ltype
);
1462 int config_parse_warn_compat(
1464 const char *filename
,
1466 const char *section
,
1467 unsigned section_line
,
1474 Disabled reason
= ltype
;
1478 case DISABLED_CONFIGURATION
:
1479 log_syntax(unit
, LOG_DEBUG
, filename
, line
, 0,
1480 "Support for option %s= has been disabled at compile time and it is ignored", lvalue
);
1483 case DISABLED_LEGACY
:
1484 log_syntax(unit
, LOG_INFO
, filename
, line
, 0,
1485 "Support for option %s= has been removed and it is ignored", lvalue
);
1488 case DISABLED_EXPERIMENTAL
:
1489 log_syntax(unit
, LOG_INFO
, filename
, line
, 0,
1490 "Support for option %s= has not yet been enabled and it is ignored", lvalue
);
1497 int config_parse_log_facility(
1499 const char *filename
,
1501 const char *section
,
1502 unsigned section_line
,
1516 x
= log_facility_unshifted_from_string(rvalue
);
1518 return log_syntax_parse_error(unit
, filename
, line
, x
, lvalue
, rvalue
);
1520 *o
= (x
<< 3) | LOG_PRI(*o
);
1525 int config_parse_log_level(
1527 const char *filename
,
1529 const char *section
,
1530 unsigned section_line
,
1544 x
= log_level_from_string(rvalue
);
1546 return log_syntax_parse_error(unit
, filename
, line
, x
, lvalue
, rvalue
);
1548 if (*o
< 0) /* if it wasn't initialized so far, assume zero facility */
1551 *o
= (*o
& LOG_FACMASK
) | x
;
1556 int config_parse_signal(
1558 const char *filename
,
1560 const char *section
,
1561 unsigned section_line
,
1575 r
= signal_from_string(rvalue
);
1577 return log_syntax_parse_error(unit
, filename
, line
, r
, lvalue
, rvalue
);
1583 int config_parse_personality(
1585 const char *filename
,
1587 const char *section
,
1588 unsigned section_line
,
1595 unsigned long *personality
= data
, p
;
1600 assert(personality
);
1602 if (isempty(rvalue
)) {
1603 *personality
= PERSONALITY_INVALID
;
1607 p
= personality_from_string(rvalue
);
1608 if (p
== PERSONALITY_INVALID
)
1609 return log_syntax_parse_error(unit
, filename
, line
, 0, lvalue
, rvalue
);
1615 int config_parse_ifname(
1617 const char *filename
,
1619 const char *section
,
1620 unsigned section_line
,
1627 char **s
= ASSERT_PTR(data
);
1634 if (isempty(rvalue
)) {
1639 if (!ifname_valid(rvalue
)) {
1640 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Interface name is not valid or too long, ignoring assignment: %s", rvalue
);
1644 r
= free_and_strdup_warn(s
, rvalue
);
1651 int config_parse_ifnames(
1653 const char *filename
,
1655 const char *section
,
1656 unsigned section_line
,
1663 _cleanup_strv_free_
char **names
= NULL
;
1664 char ***s
= ASSERT_PTR(data
);
1671 if (isempty(rvalue
)) {
1676 for (const char *p
= rvalue
;;) {
1677 _cleanup_free_
char *word
= NULL
;
1679 r
= extract_first_word(&p
, &word
, NULL
, 0);
1681 return log_syntax_parse_error(unit
, filename
, line
, r
, lvalue
, rvalue
);
1685 if (!ifname_valid_full(word
, ltype
)) {
1686 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1687 "Interface name is not valid or too long, ignoring assignment: %s",
1692 r
= strv_consume(&names
, TAKE_PTR(word
));
1697 r
= strv_extend_strv(s
, names
, true);
1704 int config_parse_ip_port(
1706 const char *filename
,
1708 const char *section
,
1709 unsigned section_line
,
1716 uint16_t *s
= ASSERT_PTR(data
);
1724 if (isempty(rvalue
)) {
1729 r
= parse_ip_port(rvalue
, &port
);
1731 return log_syntax_parse_error(unit
, filename
, line
, r
, lvalue
, rvalue
);
1737 int config_parse_mtu(
1739 const char *filename
,
1741 const char *section
,
1742 unsigned section_line
,
1749 uint32_t *mtu
= ASSERT_PTR(data
);
1754 r
= parse_mtu(ltype
, rvalue
, mtu
);
1756 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1757 "Maximum transfer unit (MTU) value out of range. Permitted range is %" PRIu32
"…%" PRIu32
", ignoring: %s",
1758 (uint32_t) (ltype
== AF_INET6
? IPV6_MIN_MTU
: IPV4_MIN_MTU
), (uint32_t) UINT32_MAX
,
1763 return log_syntax_parse_error(unit
, filename
, line
, r
, lvalue
, rvalue
);
1768 int config_parse_rlimit(
1770 const char *filename
,
1772 const char *section
,
1773 unsigned section_line
,
1780 struct rlimit
**rl
= data
, d
= {};
1786 r
= rlimit_parse(ltype
, rvalue
, &d
);
1788 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Soft resource limit chosen higher than hard limit, ignoring: %s", rvalue
);
1792 return log_syntax_parse_error(unit
, filename
, line
, r
, lvalue
, rvalue
);
1797 rl
[ltype
] = newdup(struct rlimit
, &d
, 1);
1805 int config_parse_permille(
1807 const char *filename
,
1809 const char *section
,
1810 unsigned section_line
,
1817 unsigned *permille
= ASSERT_PTR(data
);
1824 r
= parse_permille(rvalue
);
1826 return log_syntax_parse_error(unit
, filename
, line
, r
, lvalue
, rvalue
);
1828 *permille
= (unsigned) r
;
1832 int config_parse_vlanprotocol(
1834 const char *filename
,
1836 const char *section
,
1837 unsigned section_line
,
1844 int *vlan_protocol
= data
;
1849 if (isempty(rvalue
)) {
1850 *vlan_protocol
= -1;
1854 if (STR_IN_SET(rvalue
, "802.1ad", "802.1AD"))
1855 *vlan_protocol
= ETH_P_8021AD
;
1856 else if (STR_IN_SET(rvalue
, "802.1q", "802.1Q"))
1857 *vlan_protocol
= ETH_P_8021Q
;
1859 return log_syntax_parse_error(unit
, filename
, line
, 0, lvalue
, rvalue
);
1864 int config_parse_hw_addr(
1866 const char *filename
,
1868 const char *section
,
1869 unsigned section_line
,
1876 struct hw_addr_data
*hwaddr
= ASSERT_PTR(data
);
1883 if (isempty(rvalue
)) {
1884 *hwaddr
= HW_ADDR_NULL
;
1888 r
= parse_hw_addr_full(rvalue
, ltype
, hwaddr
);
1890 return log_syntax_parse_error(unit
, filename
, line
, r
, lvalue
, rvalue
);
1895 int config_parse_hw_addrs(
1897 const char *filename
,
1899 const char *section
,
1900 unsigned section_line
,
1907 Set
**hwaddrs
= ASSERT_PTR(data
);
1914 if (isempty(rvalue
)) {
1915 /* Empty assignment resets the list */
1916 *hwaddrs
= set_free(*hwaddrs
);
1920 for (const char *p
= rvalue
;;) {
1921 _cleanup_free_
char *word
= NULL
;
1922 _cleanup_free_
struct hw_addr_data
*n
= NULL
;
1924 r
= extract_first_word(&p
, &word
, NULL
, 0);
1926 return log_syntax_parse_error(unit
, filename
, line
, r
, lvalue
, rvalue
);
1930 n
= new(struct hw_addr_data
, 1);
1934 r
= parse_hw_addr_full(word
, ltype
, n
);
1936 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1937 "Not a valid hardware address, ignoring: %s", word
);
1941 r
= set_ensure_consume(hwaddrs
, &hw_addr_hash_ops_free
, TAKE_PTR(n
));
1947 int config_parse_ether_addr(
1949 const char *filename
,
1951 const char *section
,
1952 unsigned section_line
,
1959 _cleanup_free_
struct ether_addr
*n
= NULL
;
1960 struct ether_addr
**hwaddr
= ASSERT_PTR(data
);
1967 if (isempty(rvalue
)) {
1968 *hwaddr
= mfree(*hwaddr
);
1972 n
= new0(struct ether_addr
, 1);
1976 r
= parse_ether_addr(rvalue
, n
);
1978 return log_syntax_parse_error(unit
, filename
, line
, r
, lvalue
, rvalue
);
1980 free_and_replace(*hwaddr
, n
);
1984 int config_parse_ether_addrs(
1986 const char *filename
,
1988 const char *section
,
1989 unsigned section_line
,
1996 Set
**hwaddrs
= ASSERT_PTR(data
);
2003 if (isempty(rvalue
)) {
2004 /* Empty assignment resets the list */
2005 *hwaddrs
= set_free(*hwaddrs
);
2009 for (const char *p
= rvalue
;;) {
2010 _cleanup_free_
char *word
= NULL
;
2011 _cleanup_free_
struct ether_addr
*n
= NULL
;
2013 r
= extract_first_word(&p
, &word
, NULL
, 0);
2015 return log_syntax_parse_error(unit
, filename
, line
, r
, lvalue
, rvalue
);
2019 n
= new(struct ether_addr
, 1);
2023 r
= parse_ether_addr(word
, n
);
2025 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2026 "Not a valid MAC address, ignoring: %s", word
);
2030 r
= set_ensure_consume(hwaddrs
, ðer_addr_hash_ops_free
, TAKE_PTR(n
));
2036 int config_parse_in_addr_non_null(
2038 const char *filename
,
2040 const char *section
,
2041 unsigned section_line
,
2048 /* data must be a pointer to struct in_addr or in6_addr, and the type is determined by ltype. */
2049 struct in_addr
*ipv4
= ASSERT_PTR(data
);
2050 struct in6_addr
*ipv6
= ASSERT_PTR(data
);
2051 union in_addr_union a
;
2057 assert(IN_SET(ltype
, AF_INET
, AF_INET6
));
2059 if (isempty(rvalue
)) {
2060 if (ltype
== AF_INET
)
2061 *ipv4
= (struct in_addr
) {};
2063 *ipv6
= (struct in6_addr
) {};
2067 r
= in_addr_from_string(ltype
, rvalue
, &a
);
2069 return log_syntax_parse_error(unit
, filename
, line
, r
, lvalue
, rvalue
);
2071 if (!in_addr_is_set(ltype
, &a
)) {
2072 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
2073 "%s= cannot be the ANY address, ignoring: %s", lvalue
, rvalue
);
2077 if (ltype
== AF_INET
)
2084 int config_parse_in_addr_data(
2086 const char *filename
,
2088 const char *section
,
2089 unsigned section_line
,
2096 struct in_addr_data
*p
= ASSERT_PTR(data
);
2102 if (isempty(rvalue
)) {
2103 *p
= (struct in_addr_data
) {};
2107 r
= in_addr_from_string_auto(rvalue
, &p
->family
, &p
->address
);
2109 return log_syntax_parse_error(unit
, filename
, line
, r
, lvalue
, rvalue
);
2114 int config_parse_in_addr_prefix(
2116 const char *filename
,
2118 const char *section
,
2119 unsigned section_line
,
2121 int ltype
, /* takes boolean, whether we warn about missing prefixlen */
2126 struct in_addr_prefix
*p
= ASSERT_PTR(data
);
2132 if (isempty(rvalue
)) {
2133 *p
= (struct in_addr_prefix
) {};
2137 r
= in_addr_prefix_from_string_auto_full(rvalue
, ltype
? PREFIXLEN_REFUSE
: PREFIXLEN_FULL
, &p
->family
, &p
->address
, &p
->prefixlen
);
2139 r
= in_addr_prefix_from_string_auto(rvalue
, &p
->family
, &p
->address
, &p
->prefixlen
);
2141 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2142 "%s=%s is specified without prefix length. Assuming the prefix length is %u. "
2143 "Please specify the prefix length explicitly.", lvalue
, rvalue
, p
->prefixlen
);
2146 return log_syntax_parse_error(unit
, filename
, line
, r
, lvalue
, rvalue
);
2151 int config_parse_unsigned_bounded(
2153 const char *filename
,
2155 const char *section
,
2156 unsigned section_line
,
2171 r
= safe_atou_bounded(rvalue
, min
, max
, ret
);
2173 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2174 "Invalid '%s=%s', allowed range is %u..%u%s.",
2175 lvalue
, rvalue
, min
, max
, ignoring
? ", ignoring" : "");
2176 return ignoring
? 0 : r
;
2179 return log_syntax_parse_error_full(unit
, filename
, line
, r
, /* critical= */ !ignoring
, lvalue
, rvalue
);
2181 return 1; /* Return 1 if something was set */
2184 int config_parse_calendar(
2186 const char *filename
,
2188 const char *section
,
2189 unsigned section_line
,
2196 CalendarSpec
**cr
= data
;
2197 _cleanup_(calendar_spec_freep
) CalendarSpec
*c
= NULL
;
2205 if (isempty(rvalue
)) {
2206 *cr
= calendar_spec_free(*cr
);
2210 r
= calendar_spec_from_string(rvalue
, &c
);
2212 return log_syntax_parse_error(unit
, filename
, line
, r
, lvalue
, rvalue
);
2214 free_and_replace_full(*cr
, c
, calendar_spec_free
);
2218 DEFINE_CONFIG_PARSE(config_parse_percent
, parse_percent
);
2219 DEFINE_CONFIG_PARSE(config_parse_permyriad
, parse_permyriad
);
2220 DEFINE_CONFIG_PARSE_PTR(config_parse_sec_fix_0
, parse_sec_fix_0
, usec_t
);
2222 int config_parse_timezone(
2224 const char *filename
,
2226 const char *section
,
2227 unsigned section_line
,
2234 char **tz
= ASSERT_PTR(data
);
2241 if (isempty(rvalue
)) {
2246 r
= verify_timezone(rvalue
, LOG_WARNING
);
2248 return log_syntax_parse_error(unit
, filename
, line
, r
, lvalue
, rvalue
);
2250 r
= free_and_strdup_warn(tz
, rvalue
);
2257 int config_parse_ip_protocol(
2259 const char *filename
,
2261 const char *section
,
2262 unsigned section_line
,
2269 uint8_t *proto
= ASSERT_PTR(data
);
2272 r
= isempty(rvalue
) ? 0 : parse_ip_protocol_full(rvalue
, /* relaxed= */ ltype
);
2274 return log_syntax_parse_error(unit
, filename
, line
, r
, lvalue
, rvalue
);
2276 if (r
> UINT8_MAX
) {
2277 /* linux/fib_rules.h and linux/fou.h define the netlink field as one byte, so we need to
2278 * reject protocols numbers that don't fit in one byte. */
2279 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2280 "Invalid '%s=%s', allowed range is 0..255, ignoring.",
2286 return 1; /* done. */
2289 int config_parse_loadavg(
2291 const char *filename
,
2293 const char *section
,
2294 unsigned section_line
,
2301 loadavg_t
*i
= ASSERT_PTR(data
);
2306 r
= parse_permyriad(rvalue
);
2308 return log_syntax_parse_error(unit
, filename
, line
, r
, lvalue
, rvalue
);
2310 r
= store_loadavg_fixed_point(r
/ 100, r
% 100, i
);
2312 return log_syntax_parse_error(unit
, filename
, line
, r
, lvalue
, rvalue
);
2314 return 1; /* done. */