1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
10 #include "alloc-util.h"
11 #include "conf-files.h"
12 #include "conf-parser.h"
14 #include "ether-addr-util.h"
15 #include "extract-word.h"
21 #include "missing_network.h"
22 #include "nulstr-util.h"
23 #include "parse-util.h"
24 #include "path-util.h"
25 #include "percent-util.h"
26 #include "process-util.h"
27 #include "rlimit-util.h"
30 #include "signal-util.h"
31 #include "socket-util.h"
32 #include "string-util.h"
34 #include "syslog-util.h"
35 #include "time-util.h"
38 int config_item_table_lookup(
42 ConfigParserCallback
*func
,
47 const ConfigTableItem
*t
;
55 for (t
= table
; t
->lvalue
; t
++) {
57 if (!streq(lvalue
, t
->lvalue
))
60 if (!streq_ptr(section
, t
->section
))
72 int config_item_perf_lookup(
76 ConfigParserCallback
*func
,
81 ConfigPerfItemLookup lookup
= (ConfigPerfItemLookup
) table
;
82 const ConfigPerfItem
*p
;
93 key
= strjoina(section
, ".", lvalue
);
94 p
= lookup(key
, strlen(key
));
96 p
= lookup(lvalue
, strlen(lvalue
));
102 *data
= (uint8_t*) userdata
+ p
->offset
;
106 /* Run the user supplied parser for an assignment */
107 static int next_assignment(
109 const char *filename
,
111 ConfigItemLookup lookup
,
114 unsigned section_line
,
117 ConfigParseFlags flags
,
120 ConfigParserCallback func
= NULL
;
131 r
= lookup(table
, section
, lvalue
, &func
, <ype
, &data
, userdata
);
136 return func(unit
, filename
, line
, section
, section_line
,
137 lvalue
, ltype
, rvalue
, data
, userdata
);
142 /* Warn about unknown non-extension fields. */
143 if (!(flags
& CONFIG_PARSE_RELAXED
) && !startswith(lvalue
, "X-"))
144 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
145 "Unknown key name '%s' in section '%s', ignoring.", lvalue
, section
);
150 /* Parse a single logical line */
151 static int parse_line(
153 const char *filename
,
155 const char *sections
,
156 ConfigItemLookup lookup
,
158 ConfigParseFlags flags
,
160 unsigned *section_line
,
161 bool *section_ignored
,
179 if (!utf8_is_valid(l
))
180 return log_syntax_invalid_utf8(unit
, LOG_WARNING
, filename
, line
, l
);
190 return log_syntax(unit
, LOG_ERR
, filename
, line
, SYNTHETIC_ERRNO(EBADMSG
), "Invalid section header '%s'", l
);
192 n
= strndup(l
+1, k
-2);
196 if (sections
&& !nulstr_contains(sections
, n
)) {
197 bool ignore
= flags
& CONFIG_PARSE_RELAXED
;
200 ignore
= ignore
|| startswith(n
, "X-");
203 NULSTR_FOREACH(t
, sections
)
204 if (streq_ptr(n
, startswith(t
, "-"))) {
210 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Unknown section '%s'. Ignoring.", n
);
213 *section
= mfree(*section
);
215 *section_ignored
= true;
217 free_and_replace(*section
, n
);
218 *section_line
= line
;
219 *section_ignored
= false;
225 if (sections
&& !*section
) {
226 if (!(flags
& CONFIG_PARSE_RELAXED
) && !*section_ignored
)
227 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Assignment outside of section. Ignoring.");
234 return log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
235 "Missing '=', ignoring line.");
237 return log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
238 "Missing key name before '=', ignoring line.");
243 return next_assignment(unit
,
256 /* Go through the file and parse each line */
259 const char *filename
,
261 const char *sections
,
262 ConfigItemLookup lookup
,
264 ConfigParseFlags flags
,
268 _cleanup_free_
char *section
= NULL
, *continuation
= NULL
;
269 _cleanup_fclose_
FILE *ours
= NULL
;
270 unsigned line
= 0, section_line
= 0;
271 bool section_ignored
= false, bom_seen
= false;
279 f
= ours
= fopen(filename
, "re");
281 /* Only log on request, except for ENOENT,
282 * since we return 0 to the caller. */
283 if ((flags
& CONFIG_PARSE_WARN
) || errno
== ENOENT
)
284 log_full_errno(errno
== ENOENT
? LOG_DEBUG
: LOG_ERR
, errno
,
285 "Failed to open configuration file '%s': %m", filename
);
286 return errno
== ENOENT
? 0 : -errno
;
291 if (fd
>= 0) { /* stream might not have an fd, let's be careful hence */
294 if (fstat(fd
, &st
) < 0)
295 return log_full_errno(FLAGS_SET(flags
, CONFIG_PARSE_WARN
) ? LOG_ERR
: LOG_DEBUG
, errno
,
296 "Failed to fstat(%s): %m", filename
);
298 (void) stat_warn_permissions(filename
, &st
);
299 mtime
= timespec_load(&st
.st_mtim
);
303 _cleanup_free_
char *buf
= NULL
;
304 bool escaped
= false;
307 r
= read_line(f
, LONG_LINE_MAX
, &buf
);
311 if (flags
& CONFIG_PARSE_WARN
)
312 log_error_errno(r
, "%s:%u: Line too long", filename
, line
);
317 if (FLAGS_SET(flags
, CONFIG_PARSE_WARN
))
318 log_error_errno(r
, "%s:%u: Error while reading configuration file: %m", filename
, line
);
325 l
= skip_leading_chars(buf
, WHITESPACE
);
326 if (*l
!= '\0' && strchr(COMMENTS
, *l
))
333 q
= startswith(buf
, UTF8_BYTE_ORDER_MARK
);
341 if (strlen(continuation
) + strlen(l
) > LONG_LINE_MAX
) {
342 if (flags
& CONFIG_PARSE_WARN
)
343 log_error("%s:%u: Continuation line too long", filename
, line
);
347 if (!strextend(&continuation
, l
)) {
348 if (flags
& CONFIG_PARSE_WARN
)
357 for (e
= p
; *e
; e
++) {
368 continuation
= strdup(l
);
370 if (flags
& CONFIG_PARSE_WARN
)
392 if (flags
& CONFIG_PARSE_WARN
)
393 log_warning_errno(r
, "%s:%u: Failed to parse file: %m", filename
, line
);
397 continuation
= mfree(continuation
);
414 if (flags
& CONFIG_PARSE_WARN
)
415 log_warning_errno(r
, "%s:%u: Failed to parse file: %m", filename
, line
);
426 static int config_parse_many_files(
427 const char *conf_file
,
429 const char *sections
,
430 ConfigItemLookup lookup
,
432 ConfigParseFlags flags
,
441 r
= config_parse(NULL
, conf_file
, NULL
, sections
, lookup
, table
, flags
, userdata
, &mtime
);
446 STRV_FOREACH(fn
, files
) {
449 r
= config_parse(NULL
, *fn
, NULL
, sections
, lookup
, table
, flags
, userdata
, &t
);
452 if (t
> mtime
) /* Find the newest */
462 /* Parse each config file in the directories specified as nulstr. */
463 int config_parse_many_nulstr(
464 const char *conf_file
,
465 const char *conf_file_dirs
,
466 const char *sections
,
467 ConfigItemLookup lookup
,
469 ConfigParseFlags flags
,
473 _cleanup_strv_free_
char **files
= NULL
;
476 r
= conf_files_list_nulstr(&files
, ".conf", NULL
, 0, conf_file_dirs
);
480 return config_parse_many_files(conf_file
, files
, sections
, lookup
, table
, flags
, userdata
, ret_mtime
);
483 /* Parse each config file in the directories specified as strv. */
484 int config_parse_many(
485 const char *conf_file
,
486 const char* const* conf_file_dirs
,
487 const char *dropin_dirname
,
488 const char *sections
,
489 ConfigItemLookup lookup
,
491 ConfigParseFlags flags
,
495 _cleanup_strv_free_
char **dropin_dirs
= NULL
;
496 _cleanup_strv_free_
char **files
= NULL
;
500 suffix
= strjoina("/", dropin_dirname
);
501 r
= strv_extend_strv_concat(&dropin_dirs
, (char**) conf_file_dirs
, suffix
);
505 r
= conf_files_list_strv(&files
, ".conf", NULL
, 0, (const char* const*) dropin_dirs
);
509 return config_parse_many_files(conf_file
, files
, sections
, lookup
, table
, flags
, userdata
, ret_mtime
);
512 #define DEFINE_PARSER(type, vartype, conv_func) \
513 DEFINE_CONFIG_PARSE_PTR(config_parse_##type, conv_func, vartype, "Failed to parse " #type " value")
515 DEFINE_PARSER(int, int, safe_atoi
);
516 DEFINE_PARSER(long, long, safe_atoli
);
517 DEFINE_PARSER(uint8
, uint8_t, safe_atou8
);
518 DEFINE_PARSER(uint16
, uint16_t, safe_atou16
);
519 DEFINE_PARSER(uint32
, uint32_t, safe_atou32
);
520 DEFINE_PARSER(int32
, int32_t, safe_atoi32
);
521 DEFINE_PARSER(uint64
, uint64_t, safe_atou64
);
522 DEFINE_PARSER(unsigned, unsigned, safe_atou
);
523 DEFINE_PARSER(double, double, safe_atod
);
524 DEFINE_PARSER(nsec
, nsec_t
, parse_nsec
);
525 DEFINE_PARSER(sec
, usec_t
, parse_sec
);
526 DEFINE_PARSER(sec_def_infinity
, usec_t
, parse_sec_def_infinity
);
527 DEFINE_PARSER(mode
, mode_t
, parse_mode
);
529 int config_parse_iec_size(
531 const char *filename
,
534 unsigned section_line
,
550 r
= parse_size(rvalue
, 1024, &v
);
551 if (r
>= 0 && (uint64_t) (size_t) v
!= v
)
554 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to parse size value '%s', ignoring: %m", rvalue
);
562 int config_parse_si_uint64(
564 const char *filename
,
567 unsigned section_line
,
582 r
= parse_size(rvalue
, 1000, sz
);
584 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to parse size value '%s', ignoring: %m", rvalue
);
589 int config_parse_iec_uint64(
591 const char *filename
,
594 unsigned section_line
,
601 uint64_t *bytes
= data
;
609 r
= parse_size(rvalue
, 1024, bytes
);
611 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to parse size value, ignoring: %s", rvalue
);
616 int config_parse_bool(
618 const char *filename
,
621 unsigned section_line
,
637 k
= parse_boolean(rvalue
);
639 log_syntax(unit
, fatal
? LOG_ERR
: LOG_WARNING
, filename
, line
, k
,
640 "Failed to parse boolean value%s: %s",
641 fatal
? "" : ", ignoring", rvalue
);
642 return fatal
? -ENOEXEC
: 0;
649 int config_parse_id128(
651 const char *filename
,
654 unsigned section_line
,
661 sd_id128_t t
, *result
= data
;
668 r
= sd_id128_from_string(rvalue
, &t
);
670 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to parse 128bit ID/UUID, ignoring: %s", rvalue
);
674 if (sd_id128_is_null(t
)) {
675 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "128bit ID/UUID is all 0, ignoring: %s", rvalue
);
683 int config_parse_tristate(
685 const char *filename
,
688 unsigned section_line
,
702 /* A tristate is pretty much a boolean, except that it can
703 * also take the special value -1, indicating "uninitialized",
704 * much like NULL is for a pointer type. */
706 k
= parse_boolean(rvalue
);
708 log_syntax(unit
, LOG_WARNING
, filename
, line
, k
, "Failed to parse boolean value, ignoring: %s", rvalue
);
716 int config_parse_string(
718 const char *filename
,
721 unsigned section_line
,
735 return free_and_strdup_warn(s
, empty_to_null(rvalue
));
738 int config_parse_path(
740 const char *filename
,
743 unsigned section_line
,
750 _cleanup_free_
char *n
= NULL
;
767 r
= path_simplify_and_warn(n
, PATH_CHECK_ABSOLUTE
| (fatal
? PATH_CHECK_FATAL
: 0), unit
, filename
, line
, lvalue
);
769 return fatal
? -ENOEXEC
: 0;
772 return free_and_replace(*s
, n
);
775 int config_parse_strv(
777 const char *filename
,
780 unsigned section_line
,
795 if (isempty(rvalue
)) {
796 *sv
= strv_free(*sv
);
800 for (const char *p
= rvalue
;;) {
803 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_UNQUOTE
|EXTRACT_RETAIN_ESCAPE
);
809 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Invalid syntax, ignoring: %s", rvalue
);
813 r
= strv_consume(sv
, word
);
819 int config_parse_warn_compat(
821 const char *filename
,
824 unsigned section_line
,
831 Disabled reason
= ltype
;
835 case DISABLED_CONFIGURATION
:
836 log_syntax(unit
, LOG_DEBUG
, filename
, line
, 0,
837 "Support for option %s= has been disabled at compile time and it is ignored", lvalue
);
840 case DISABLED_LEGACY
:
841 log_syntax(unit
, LOG_INFO
, filename
, line
, 0,
842 "Support for option %s= has been removed and it is ignored", lvalue
);
845 case DISABLED_EXPERIMENTAL
:
846 log_syntax(unit
, LOG_INFO
, filename
, line
, 0,
847 "Support for option %s= has not yet been enabled and it is ignored", lvalue
);
854 int config_parse_log_facility(
856 const char *filename
,
859 unsigned section_line
,
873 x
= log_facility_unshifted_from_string(rvalue
);
875 log_syntax(unit
, LOG_WARNING
, filename
, line
, x
, "Failed to parse log facility, ignoring: %s", rvalue
);
879 *o
= (x
<< 3) | LOG_PRI(*o
);
884 int config_parse_log_level(
886 const char *filename
,
889 unsigned section_line
,
903 x
= log_level_from_string(rvalue
);
905 log_syntax(unit
, LOG_WARNING
, filename
, line
, x
, "Failed to parse log level, ignoring: %s", rvalue
);
909 if (*o
< 0) /* if it wasn't initialized so far, assume zero facility */
912 *o
= (*o
& LOG_FACMASK
) | x
;
917 int config_parse_signal(
919 const char *filename
,
922 unsigned section_line
,
936 r
= signal_from_string(rvalue
);
938 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to parse signal name, ignoring: %s", rvalue
);
946 int config_parse_personality(
948 const char *filename
,
951 unsigned section_line
,
958 unsigned long *personality
= data
, p
;
966 p
= PERSONALITY_INVALID
;
968 p
= personality_from_string(rvalue
);
969 if (p
== PERSONALITY_INVALID
) {
970 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Failed to parse personality, ignoring: %s", rvalue
);
979 int config_parse_ifname(
981 const char *filename
,
984 unsigned section_line
,
999 if (isempty(rvalue
)) {
1004 if (!ifname_valid(rvalue
)) {
1005 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Interface name is not valid or too long, ignoring assignment: %s", rvalue
);
1009 r
= free_and_strdup(s
, rvalue
);
1016 int config_parse_ifnames(
1018 const char *filename
,
1020 const char *section
,
1021 unsigned section_line
,
1028 _cleanup_strv_free_
char **names
= NULL
;
1037 if (isempty(rvalue
)) {
1042 for (const char *p
= rvalue
;;) {
1043 _cleanup_free_
char *word
= NULL
;
1045 r
= extract_first_word(&p
, &word
, NULL
, 0);
1049 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1050 "Failed to extract interface name, ignoring assignment: %s",
1057 if (!ifname_valid_full(word
, ltype
)) {
1058 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1059 "Interface name is not valid or too long, ignoring assignment: %s",
1064 r
= strv_consume(&names
, TAKE_PTR(word
));
1069 r
= strv_extend_strv(s
, names
, true);
1076 int config_parse_ip_port(
1078 const char *filename
,
1080 const char *section
,
1081 unsigned section_line
,
1097 if (isempty(rvalue
)) {
1102 r
= parse_ip_port(rvalue
, &port
);
1104 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to parse port '%s'.", rvalue
);
1113 int config_parse_mtu(
1115 const char *filename
,
1117 const char *section
,
1118 unsigned section_line
,
1125 uint32_t *mtu
= data
;
1131 r
= parse_mtu(ltype
, rvalue
, mtu
);
1133 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1134 "Maximum transfer unit (MTU) value out of range. Permitted range is %" PRIu32
"…%" PRIu32
", ignoring: %s",
1135 (uint32_t) (ltype
== AF_INET6
? IPV6_MIN_MTU
: IPV4_MIN_MTU
), (uint32_t) UINT32_MAX
,
1140 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1141 "Failed to parse MTU value '%s', ignoring: %m", rvalue
);
1148 int config_parse_rlimit(
1150 const char *filename
,
1152 const char *section
,
1153 unsigned section_line
,
1160 struct rlimit
**rl
= data
, d
= {};
1166 r
= rlimit_parse(ltype
, rvalue
, &d
);
1168 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Soft resource limit chosen higher than hard limit, ignoring: %s", rvalue
);
1172 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to parse resource value, ignoring: %s", rvalue
);
1179 rl
[ltype
] = newdup(struct rlimit
, &d
, 1);
1187 int config_parse_permille(
1189 const char *filename
,
1191 const char *section
,
1192 unsigned section_line
,
1199 unsigned *permille
= data
;
1207 r
= parse_permille(rvalue
);
1209 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1210 "Failed to parse permille value, ignoring: %s", rvalue
);
1214 *permille
= (unsigned) r
;
1219 int config_parse_vlanprotocol(
1221 const char *filename
,
1223 const char *section
,
1224 unsigned section_line
,
1231 int *vlan_protocol
= data
;
1236 if (isempty(rvalue
)) {
1237 *vlan_protocol
= -1;
1241 if (STR_IN_SET(rvalue
, "802.1ad", "802.1AD"))
1242 *vlan_protocol
= ETH_P_8021AD
;
1243 else if (STR_IN_SET(rvalue
, "802.1q", "802.1Q"))
1244 *vlan_protocol
= ETH_P_8021Q
;
1246 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1247 "Failed to parse VLAN protocol value, ignoring: %s", rvalue
);
1254 int config_parse_hwaddr(
1256 const char *filename
,
1258 const char *section
,
1259 unsigned section_line
,
1266 _cleanup_free_
struct ether_addr
*n
= NULL
;
1267 struct ether_addr
**hwaddr
= data
;
1275 if (isempty(rvalue
)) {
1276 *hwaddr
= mfree(*hwaddr
);
1280 n
= new0(struct ether_addr
, 1);
1284 r
= ether_addr_from_string(rvalue
, n
);
1286 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1287 "Not a valid MAC address, ignoring assignment: %s", rvalue
);
1291 free_and_replace(*hwaddr
, n
);
1296 int config_parse_hwaddrs(
1298 const char *filename
,
1300 const char *section
,
1301 unsigned section_line
,
1308 Set
**hwaddrs
= data
;
1316 if (isempty(rvalue
)) {
1317 /* Empty assignment resets the list */
1318 *hwaddrs
= set_free_free(*hwaddrs
);
1322 for (const char *p
= rvalue
;;) {
1323 _cleanup_free_
char *word
= NULL
;
1324 _cleanup_free_
struct ether_addr
*n
= NULL
;
1326 r
= extract_first_word(&p
, &word
, NULL
, 0);
1332 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1333 "Invalid syntax, ignoring: %s", rvalue
);
1337 n
= new(struct ether_addr
, 1);
1341 r
= ether_addr_from_string(word
, n
);
1343 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1344 "Not a valid MAC address, ignoring: %s", word
);
1348 r
= set_ensure_put(hwaddrs
, ðer_addr_hash_ops
, n
);
1352 TAKE_PTR(n
); /* avoid cleanup */
1356 DEFINE_CONFIG_PARSE(config_parse_percent
, parse_percent
, "Failed to parse percent value");
1357 DEFINE_CONFIG_PARSE(config_parse_permyriad
, parse_permyriad
, "Failed to parse permyriad value");