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 "process-util.h"
26 #include "rlimit-util.h"
29 #include "signal-util.h"
30 #include "socket-util.h"
31 #include "string-util.h"
33 #include "syslog-util.h"
34 #include "time-util.h"
37 int config_item_table_lookup(
41 ConfigParserCallback
*func
,
46 const ConfigTableItem
*t
;
54 for (t
= table
; t
->lvalue
; t
++) {
56 if (!streq(lvalue
, t
->lvalue
))
59 if (!streq_ptr(section
, t
->section
))
71 int config_item_perf_lookup(
75 ConfigParserCallback
*func
,
80 ConfigPerfItemLookup lookup
= (ConfigPerfItemLookup
) table
;
81 const ConfigPerfItem
*p
;
92 key
= strjoina(section
, ".", lvalue
);
93 p
= lookup(key
, strlen(key
));
95 p
= lookup(lvalue
, strlen(lvalue
));
101 *data
= (uint8_t*) userdata
+ p
->offset
;
105 /* Run the user supplied parser for an assignment */
106 static int next_assignment(
108 const char *filename
,
110 ConfigItemLookup lookup
,
113 unsigned section_line
,
116 ConfigParseFlags flags
,
119 ConfigParserCallback func
= NULL
;
130 r
= lookup(table
, section
, lvalue
, &func
, <ype
, &data
, userdata
);
135 return func(unit
, filename
, line
, section
, section_line
,
136 lvalue
, ltype
, rvalue
, data
, userdata
);
141 /* Warn about unknown non-extension fields. */
142 if (!(flags
& CONFIG_PARSE_RELAXED
) && !startswith(lvalue
, "X-"))
143 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
144 "Unknown key name '%s' in section '%s', ignoring.", lvalue
, section
);
149 /* Parse a single logical line */
150 static int parse_line(
152 const char *filename
,
154 const char *sections
,
155 ConfigItemLookup lookup
,
157 ConfigParseFlags flags
,
159 unsigned *section_line
,
160 bool *section_ignored
,
178 if (!utf8_is_valid(l
))
179 return log_syntax_invalid_utf8(unit
, LOG_WARNING
, filename
, line
, l
);
189 return log_syntax(unit
, LOG_ERR
, filename
, line
, SYNTHETIC_ERRNO(EBADMSG
), "Invalid section header '%s'", l
);
191 n
= strndup(l
+1, k
-2);
195 if (sections
&& !nulstr_contains(sections
, n
)) {
196 bool ignore
= flags
& CONFIG_PARSE_RELAXED
;
199 ignore
= ignore
|| startswith(n
, "X-");
202 NULSTR_FOREACH(t
, sections
)
203 if (streq_ptr(n
, startswith(t
, "-"))) {
209 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Unknown section '%s'. Ignoring.", n
);
212 *section
= mfree(*section
);
214 *section_ignored
= true;
216 free_and_replace(*section
, n
);
217 *section_line
= line
;
218 *section_ignored
= false;
224 if (sections
&& !*section
) {
225 if (!(flags
& CONFIG_PARSE_RELAXED
) && !*section_ignored
)
226 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Assignment outside of section. Ignoring.");
233 return log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
234 "Missing '=', ignoring line.");
236 return log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
237 "Missing key name before '=', ignoring line.");
242 return next_assignment(unit
,
255 /* Go through the file and parse each line */
258 const char *filename
,
260 const char *sections
,
261 ConfigItemLookup lookup
,
263 ConfigParseFlags flags
,
267 _cleanup_free_
char *section
= NULL
, *continuation
= NULL
;
268 _cleanup_fclose_
FILE *ours
= NULL
;
269 unsigned line
= 0, section_line
= 0;
270 bool section_ignored
= false, bom_seen
= false;
278 f
= ours
= fopen(filename
, "re");
280 /* Only log on request, except for ENOENT,
281 * since we return 0 to the caller. */
282 if ((flags
& CONFIG_PARSE_WARN
) || errno
== ENOENT
)
283 log_full_errno(errno
== ENOENT
? LOG_DEBUG
: LOG_ERR
, errno
,
284 "Failed to open configuration file '%s': %m", filename
);
285 return errno
== ENOENT
? 0 : -errno
;
290 if (fd
>= 0) { /* stream might not have an fd, let's be careful hence */
293 if (fstat(fd
, &st
) < 0)
294 return log_full_errno(FLAGS_SET(flags
, CONFIG_PARSE_WARN
) ? LOG_ERR
: LOG_DEBUG
, errno
,
295 "Failed to fstat(%s): %m", filename
);
297 (void) stat_warn_permissions(filename
, &st
);
298 mtime
= timespec_load(&st
.st_mtim
);
302 _cleanup_free_
char *buf
= NULL
;
303 bool escaped
= false;
306 r
= read_line(f
, LONG_LINE_MAX
, &buf
);
310 if (flags
& CONFIG_PARSE_WARN
)
311 log_error_errno(r
, "%s:%u: Line too long", filename
, line
);
316 if (FLAGS_SET(flags
, CONFIG_PARSE_WARN
))
317 log_error_errno(r
, "%s:%u: Error while reading configuration file: %m", filename
, line
);
324 l
= skip_leading_chars(buf
, WHITESPACE
);
325 if (*l
!= '\0' && strchr(COMMENTS
, *l
))
332 q
= startswith(buf
, UTF8_BYTE_ORDER_MARK
);
340 if (strlen(continuation
) + strlen(l
) > LONG_LINE_MAX
) {
341 if (flags
& CONFIG_PARSE_WARN
)
342 log_error("%s:%u: Continuation line too long", filename
, line
);
346 if (!strextend(&continuation
, l
)) {
347 if (flags
& CONFIG_PARSE_WARN
)
356 for (e
= p
; *e
; e
++) {
367 continuation
= strdup(l
);
369 if (flags
& CONFIG_PARSE_WARN
)
391 if (flags
& CONFIG_PARSE_WARN
)
392 log_warning_errno(r
, "%s:%u: Failed to parse file: %m", filename
, line
);
396 continuation
= mfree(continuation
);
413 if (flags
& CONFIG_PARSE_WARN
)
414 log_warning_errno(r
, "%s:%u: Failed to parse file: %m", filename
, line
);
425 static int config_parse_many_files(
426 const char *conf_file
,
428 const char *sections
,
429 ConfigItemLookup lookup
,
431 ConfigParseFlags flags
,
440 r
= config_parse(NULL
, conf_file
, NULL
, sections
, lookup
, table
, flags
, userdata
, &mtime
);
445 STRV_FOREACH(fn
, files
) {
448 r
= config_parse(NULL
, *fn
, NULL
, sections
, lookup
, table
, flags
, userdata
, &t
);
451 if (t
> mtime
) /* Find the newest */
461 /* Parse each config file in the directories specified as nulstr. */
462 int config_parse_many_nulstr(
463 const char *conf_file
,
464 const char *conf_file_dirs
,
465 const char *sections
,
466 ConfigItemLookup lookup
,
468 ConfigParseFlags flags
,
472 _cleanup_strv_free_
char **files
= NULL
;
475 r
= conf_files_list_nulstr(&files
, ".conf", NULL
, 0, conf_file_dirs
);
479 return config_parse_many_files(conf_file
, files
, sections
, lookup
, table
, flags
, userdata
, ret_mtime
);
482 /* Parse each config file in the directories specified as strv. */
483 int config_parse_many(
484 const char *conf_file
,
485 const char* const* conf_file_dirs
,
486 const char *dropin_dirname
,
487 const char *sections
,
488 ConfigItemLookup lookup
,
490 ConfigParseFlags flags
,
494 _cleanup_strv_free_
char **dropin_dirs
= NULL
;
495 _cleanup_strv_free_
char **files
= NULL
;
499 suffix
= strjoina("/", dropin_dirname
);
500 r
= strv_extend_strv_concat(&dropin_dirs
, (char**) conf_file_dirs
, suffix
);
504 r
= conf_files_list_strv(&files
, ".conf", NULL
, 0, (const char* const*) dropin_dirs
);
508 return config_parse_many_files(conf_file
, files
, sections
, lookup
, table
, flags
, userdata
, ret_mtime
);
511 #define DEFINE_PARSER(type, vartype, conv_func) \
512 DEFINE_CONFIG_PARSE_PTR(config_parse_##type, conv_func, vartype, "Failed to parse " #type " value")
514 DEFINE_PARSER(int, int, safe_atoi
);
515 DEFINE_PARSER(long, long, safe_atoli
);
516 DEFINE_PARSER(uint8
, uint8_t, safe_atou8
);
517 DEFINE_PARSER(uint16
, uint16_t, safe_atou16
);
518 DEFINE_PARSER(uint32
, uint32_t, safe_atou32
);
519 DEFINE_PARSER(int32
, int32_t, safe_atoi32
);
520 DEFINE_PARSER(uint64
, uint64_t, safe_atou64
);
521 DEFINE_PARSER(unsigned, unsigned, safe_atou
);
522 DEFINE_PARSER(double, double, safe_atod
);
523 DEFINE_PARSER(nsec
, nsec_t
, parse_nsec
);
524 DEFINE_PARSER(sec
, usec_t
, parse_sec
);
525 DEFINE_PARSER(sec_def_infinity
, usec_t
, parse_sec_def_infinity
);
526 DEFINE_PARSER(mode
, mode_t
, parse_mode
);
528 int config_parse_iec_size(
530 const char *filename
,
533 unsigned section_line
,
549 r
= parse_size(rvalue
, 1024, &v
);
550 if (r
>= 0 && (uint64_t) (size_t) v
!= v
)
553 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to parse size value '%s', ignoring: %m", rvalue
);
561 int config_parse_si_uint64(
563 const char *filename
,
566 unsigned section_line
,
581 r
= parse_size(rvalue
, 1000, sz
);
583 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to parse size value '%s', ignoring: %m", rvalue
);
588 int config_parse_iec_uint64(
590 const char *filename
,
593 unsigned section_line
,
600 uint64_t *bytes
= data
;
608 r
= parse_size(rvalue
, 1024, bytes
);
610 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to parse size value, ignoring: %s", rvalue
);
615 int config_parse_bool(
617 const char *filename
,
620 unsigned section_line
,
636 k
= parse_boolean(rvalue
);
638 log_syntax(unit
, fatal
? LOG_ERR
: LOG_WARNING
, filename
, line
, k
,
639 "Failed to parse boolean value%s: %s",
640 fatal
? "" : ", ignoring", rvalue
);
641 return fatal
? -ENOEXEC
: 0;
648 int config_parse_id128(
650 const char *filename
,
653 unsigned section_line
,
660 sd_id128_t t
, *result
= data
;
667 r
= sd_id128_from_string(rvalue
, &t
);
669 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to parse 128bit ID/UUID, ignoring: %s", rvalue
);
673 if (sd_id128_is_null(t
)) {
674 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "128bit ID/UUID is all 0, ignoring: %s", rvalue
);
682 int config_parse_tristate(
684 const char *filename
,
687 unsigned section_line
,
701 /* A tristate is pretty much a boolean, except that it can
702 * also take the special value -1, indicating "uninitialized",
703 * much like NULL is for a pointer type. */
705 k
= parse_boolean(rvalue
);
707 log_syntax(unit
, LOG_WARNING
, filename
, line
, k
, "Failed to parse boolean value, ignoring: %s", rvalue
);
715 int config_parse_string(
717 const char *filename
,
720 unsigned section_line
,
734 if (free_and_strdup(s
, empty_to_null(rvalue
)) < 0)
740 int config_parse_path(
742 const char *filename
,
745 unsigned section_line
,
752 _cleanup_free_
char *n
= NULL
;
769 r
= path_simplify_and_warn(n
, PATH_CHECK_ABSOLUTE
| (fatal
? PATH_CHECK_FATAL
: 0), unit
, filename
, line
, lvalue
);
771 return fatal
? -ENOEXEC
: 0;
774 return free_and_replace(*s
, n
);
777 int config_parse_strv(
779 const char *filename
,
782 unsigned section_line
,
797 if (isempty(rvalue
)) {
798 *sv
= strv_free(*sv
);
802 for (const char *p
= rvalue
;;) {
805 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_UNQUOTE
|EXTRACT_RETAIN_ESCAPE
);
811 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Invalid syntax, ignoring: %s", rvalue
);
815 r
= strv_consume(sv
, word
);
821 int config_parse_warn_compat(
823 const char *filename
,
826 unsigned section_line
,
833 Disabled reason
= ltype
;
837 case DISABLED_CONFIGURATION
:
838 log_syntax(unit
, LOG_DEBUG
, filename
, line
, 0,
839 "Support for option %s= has been disabled at compile time and it is ignored", lvalue
);
842 case DISABLED_LEGACY
:
843 log_syntax(unit
, LOG_INFO
, filename
, line
, 0,
844 "Support for option %s= has been removed and it is ignored", lvalue
);
847 case DISABLED_EXPERIMENTAL
:
848 log_syntax(unit
, LOG_INFO
, filename
, line
, 0,
849 "Support for option %s= has not yet been enabled and it is ignored", lvalue
);
856 int config_parse_log_facility(
858 const char *filename
,
861 unsigned section_line
,
875 x
= log_facility_unshifted_from_string(rvalue
);
877 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Failed to parse log facility, ignoring: %s", rvalue
);
881 *o
= (x
<< 3) | LOG_PRI(*o
);
886 int config_parse_log_level(
888 const char *filename
,
891 unsigned section_line
,
905 x
= log_level_from_string(rvalue
);
907 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Failed to parse log level, ignoring: %s", rvalue
);
911 if (*o
< 0) /* if it wasn't initialized so far, assume zero facility */
914 *o
= (*o
& LOG_FACMASK
) | x
;
919 int config_parse_signal(
921 const char *filename
,
924 unsigned section_line
,
938 r
= signal_from_string(rvalue
);
940 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Failed to parse signal name, ignoring: %s", rvalue
);
948 int config_parse_personality(
950 const char *filename
,
953 unsigned section_line
,
960 unsigned long *personality
= data
, p
;
968 p
= PERSONALITY_INVALID
;
970 p
= personality_from_string(rvalue
);
971 if (p
== PERSONALITY_INVALID
) {
972 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Failed to parse personality, ignoring: %s", rvalue
);
981 int config_parse_ifname(
983 const char *filename
,
986 unsigned section_line
,
1001 if (isempty(rvalue
)) {
1006 if (!ifname_valid(rvalue
)) {
1007 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Interface name is not valid or too long, ignoring assignment: %s", rvalue
);
1011 r
= free_and_strdup(s
, rvalue
);
1018 int config_parse_ifnames(
1020 const char *filename
,
1022 const char *section
,
1023 unsigned section_line
,
1030 _cleanup_strv_free_
char **names
= NULL
;
1039 if (isempty(rvalue
)) {
1044 for (const char *p
= rvalue
;;) {
1045 _cleanup_free_
char *word
= NULL
;
1047 r
= extract_first_word(&p
, &word
, NULL
, 0);
1051 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1052 "Failed to extract interface name, ignoring assignment: %s",
1059 if (!ifname_valid_full(word
, ltype
)) {
1060 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1061 "Interface name is not valid or too long, ignoring assignment: %s",
1066 r
= strv_consume(&names
, TAKE_PTR(word
));
1071 r
= strv_extend_strv(s
, names
, true);
1078 int config_parse_ip_port(
1080 const char *filename
,
1082 const char *section
,
1083 unsigned section_line
,
1099 if (isempty(rvalue
)) {
1104 r
= parse_ip_port(rvalue
, &port
);
1106 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to parse port '%s'.", rvalue
);
1115 int config_parse_mtu(
1117 const char *filename
,
1119 const char *section
,
1120 unsigned section_line
,
1127 uint32_t *mtu
= data
;
1133 r
= parse_mtu(ltype
, rvalue
, mtu
);
1135 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1136 "Maximum transfer unit (MTU) value out of range. Permitted range is %" PRIu32
"…%" PRIu32
", ignoring: %s",
1137 (uint32_t) (ltype
== AF_INET6
? IPV6_MIN_MTU
: IPV4_MIN_MTU
), (uint32_t) UINT32_MAX
,
1142 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1143 "Failed to parse MTU value '%s', ignoring: %m", rvalue
);
1150 int config_parse_rlimit(
1152 const char *filename
,
1154 const char *section
,
1155 unsigned section_line
,
1162 struct rlimit
**rl
= data
, d
= {};
1168 r
= rlimit_parse(ltype
, rvalue
, &d
);
1170 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Soft resource limit chosen higher than hard limit, ignoring: %s", rvalue
);
1174 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to parse resource value, ignoring: %s", rvalue
);
1181 rl
[ltype
] = newdup(struct rlimit
, &d
, 1);
1189 int config_parse_permille(
1191 const char *filename
,
1193 const char *section
,
1194 unsigned section_line
,
1201 unsigned *permille
= data
;
1209 r
= parse_permille(rvalue
);
1211 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1212 "Failed to parse permille value, ignoring: %s", rvalue
);
1216 *permille
= (unsigned) r
;
1221 int config_parse_vlanprotocol(
1223 const char *filename
,
1225 const char *section
,
1226 unsigned section_line
,
1233 int *vlan_protocol
= data
;
1238 if (isempty(rvalue
)) {
1239 *vlan_protocol
= -1;
1243 if (STR_IN_SET(rvalue
, "802.1ad", "802.1AD"))
1244 *vlan_protocol
= ETH_P_8021AD
;
1245 else if (STR_IN_SET(rvalue
, "802.1q", "802.1Q"))
1246 *vlan_protocol
= ETH_P_8021Q
;
1248 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1249 "Failed to parse VLAN protocol value, ignoring: %s", rvalue
);
1256 int config_parse_hwaddr(
1258 const char *filename
,
1260 const char *section
,
1261 unsigned section_line
,
1268 _cleanup_free_
struct ether_addr
*n
= NULL
;
1269 struct ether_addr
**hwaddr
= data
;
1277 if (isempty(rvalue
)) {
1278 *hwaddr
= mfree(*hwaddr
);
1282 n
= new0(struct ether_addr
, 1);
1286 r
= ether_addr_from_string(rvalue
, n
);
1288 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1289 "Not a valid MAC address, ignoring assignment: %s", rvalue
);
1293 free_and_replace(*hwaddr
, n
);
1298 int config_parse_hwaddrs(
1300 const char *filename
,
1302 const char *section
,
1303 unsigned section_line
,
1310 Set
**hwaddrs
= data
;
1318 if (isempty(rvalue
)) {
1319 /* Empty assignment resets the list */
1320 *hwaddrs
= set_free_free(*hwaddrs
);
1324 for (const char *p
= rvalue
;;) {
1325 _cleanup_free_
char *word
= NULL
;
1326 _cleanup_free_
struct ether_addr
*n
= NULL
;
1328 r
= extract_first_word(&p
, &word
, NULL
, 0);
1334 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1335 "Invalid syntax, ignoring: %s", rvalue
);
1339 n
= new(struct ether_addr
, 1);
1343 r
= ether_addr_from_string(word
, n
);
1345 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1346 "Not a valid MAC address, ignoring: %s", word
);
1350 r
= set_ensure_put(hwaddrs
, ðer_addr_hash_ops
, n
);
1354 TAKE_PTR(n
); /* avoid cleanup */
1358 DEFINE_CONFIG_PARSE(config_parse_percent
, parse_percent
, "Failed to parse percent value");
1359 DEFINE_CONFIG_PARSE(config_parse_permyriad
, parse_permyriad
, "Failed to parse permyriad value");