1 /* SPDX-License-Identifier: LGPL-2.1+ */
10 #include "alloc-util.h"
11 #include "conf-files.h"
12 #include "conf-parser.h"
14 #include "extract-word.h"
20 #include "missing_network.h"
21 #include "nulstr-util.h"
22 #include "parse-util.h"
23 #include "path-util.h"
24 #include "process-util.h"
25 #include "rlimit-util.h"
27 #include "signal-util.h"
28 #include "socket-util.h"
29 #include "string-util.h"
31 #include "syslog-util.h"
32 #include "time-util.h"
35 int config_item_table_lookup(
39 ConfigParserCallback
*func
,
44 const ConfigTableItem
*t
;
52 for (t
= table
; t
->lvalue
; t
++) {
54 if (!streq(lvalue
, t
->lvalue
))
57 if (!streq_ptr(section
, t
->section
))
69 int config_item_perf_lookup(
73 ConfigParserCallback
*func
,
78 ConfigPerfItemLookup lookup
= (ConfigPerfItemLookup
) table
;
79 const ConfigPerfItem
*p
;
90 key
= strjoina(section
, ".", lvalue
);
91 p
= lookup(key
, strlen(key
));
93 p
= lookup(lvalue
, strlen(lvalue
));
99 *data
= (uint8_t*) userdata
+ p
->offset
;
103 /* Run the user supplied parser for an assignment */
104 static int next_assignment(
106 const char *filename
,
108 ConfigItemLookup lookup
,
111 unsigned section_line
,
114 ConfigParseFlags flags
,
117 ConfigParserCallback func
= NULL
;
128 r
= lookup(table
, section
, lvalue
, &func
, <ype
, &data
, userdata
);
133 return func(unit
, filename
, line
, section
, section_line
,
134 lvalue
, ltype
, rvalue
, data
, userdata
);
139 /* Warn about unknown non-extension fields. */
140 if (!(flags
& CONFIG_PARSE_RELAXED
) && !startswith(lvalue
, "X-"))
141 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
142 "Unknown key name '%s' in section '%s', ignoring.", lvalue
, section
);
147 /* Parse a single logical line */
148 static int parse_line(
150 const char *filename
,
152 const char *sections
,
153 ConfigItemLookup lookup
,
155 ConfigParseFlags flags
,
157 unsigned *section_line
,
158 bool *section_ignored
,
176 if (!utf8_is_valid(l
))
177 return log_syntax_invalid_utf8(unit
, LOG_WARNING
, filename
, line
, l
);
187 return log_syntax(unit
, LOG_ERR
, filename
, line
, SYNTHETIC_ERRNO(EBADMSG
), "Invalid section header '%s'", l
);
189 n
= strndup(l
+1, k
-2);
193 if (sections
&& !nulstr_contains(sections
, n
)) {
194 bool ignore
= flags
& CONFIG_PARSE_RELAXED
;
197 ignore
= ignore
|| startswith(n
, "X-");
200 NULSTR_FOREACH(t
, sections
)
201 if (streq_ptr(n
, startswith(t
, "-"))) {
207 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Unknown section '%s'. Ignoring.", n
);
210 *section
= mfree(*section
);
212 *section_ignored
= true;
214 free_and_replace(*section
, n
);
215 *section_line
= line
;
216 *section_ignored
= false;
222 if (sections
&& !*section
) {
223 if (!(flags
& CONFIG_PARSE_RELAXED
) && !*section_ignored
)
224 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Assignment outside of section. Ignoring.");
231 return log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
232 "Missing '=', ignoring line.");
234 return log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
235 "Missing key name before '=', ignoring line.");
240 return next_assignment(unit
,
253 /* Go through the file and parse each line */
254 int config_parse(const char *unit
,
255 const char *filename
,
257 const char *sections
,
258 ConfigItemLookup lookup
,
260 ConfigParseFlags flags
,
264 _cleanup_free_
char *section
= NULL
, *continuation
= NULL
;
265 _cleanup_fclose_
FILE *ours
= NULL
;
266 unsigned line
= 0, section_line
= 0;
267 bool section_ignored
= false, bom_seen
= false;
275 f
= ours
= fopen(filename
, "re");
277 /* Only log on request, except for ENOENT,
278 * since we return 0 to the caller. */
279 if ((flags
& CONFIG_PARSE_WARN
) || errno
== ENOENT
)
280 log_full_errno(errno
== ENOENT
? LOG_DEBUG
: LOG_ERR
, errno
,
281 "Failed to open configuration file '%s': %m", filename
);
282 return errno
== ENOENT
? 0 : -errno
;
287 if (fd
>= 0) { /* stream might not have an fd, let's be careful hence */
290 if (fstat(fd
, &st
) < 0)
291 return log_full_errno(FLAGS_SET(flags
, CONFIG_PARSE_WARN
) ? LOG_ERR
: LOG_DEBUG
, errno
,
292 "Failed to fstat(%s): %m", filename
);
294 (void) stat_warn_permissions(filename
, &st
);
295 mtime
= timespec_load(&st
.st_mtim
);
299 _cleanup_free_
char *buf
= NULL
;
300 bool escaped
= false;
303 r
= read_line(f
, LONG_LINE_MAX
, &buf
);
307 if (flags
& CONFIG_PARSE_WARN
)
308 log_error_errno(r
, "%s:%u: Line too long", filename
, line
);
313 if (FLAGS_SET(flags
, CONFIG_PARSE_WARN
))
314 log_error_errno(r
, "%s:%u: Error while reading configuration file: %m", filename
, line
);
321 l
= skip_leading_chars(buf
, WHITESPACE
);
322 if (*l
!= '\0' && strchr(COMMENTS
, *l
))
329 q
= startswith(buf
, UTF8_BYTE_ORDER_MARK
);
337 if (strlen(continuation
) + strlen(l
) > LONG_LINE_MAX
) {
338 if (flags
& CONFIG_PARSE_WARN
)
339 log_error("%s:%u: Continuation line too long", filename
, line
);
343 if (!strextend(&continuation
, l
, NULL
)) {
344 if (flags
& CONFIG_PARSE_WARN
)
353 for (e
= p
; *e
; e
++) {
364 continuation
= strdup(l
);
366 if (flags
& CONFIG_PARSE_WARN
)
388 if (flags
& CONFIG_PARSE_WARN
)
389 log_warning_errno(r
, "%s:%u: Failed to parse file: %m", filename
, line
);
393 continuation
= mfree(continuation
);
410 if (flags
& CONFIG_PARSE_WARN
)
411 log_warning_errno(r
, "%s:%u: Failed to parse file: %m", filename
, line
);
422 static int config_parse_many_files(
423 const char *conf_file
,
425 const char *sections
,
426 ConfigItemLookup lookup
,
428 ConfigParseFlags flags
,
437 r
= config_parse(NULL
, conf_file
, NULL
, sections
, lookup
, table
, flags
, userdata
, &mtime
);
442 STRV_FOREACH(fn
, files
) {
445 r
= config_parse(NULL
, *fn
, NULL
, sections
, lookup
, table
, flags
, userdata
, &t
);
448 if (t
> mtime
) /* Find the newest */
458 /* Parse each config file in the directories specified as nulstr. */
459 int config_parse_many_nulstr(
460 const char *conf_file
,
461 const char *conf_file_dirs
,
462 const char *sections
,
463 ConfigItemLookup lookup
,
465 ConfigParseFlags flags
,
469 _cleanup_strv_free_
char **files
= NULL
;
472 r
= conf_files_list_nulstr(&files
, ".conf", NULL
, 0, conf_file_dirs
);
476 return config_parse_many_files(conf_file
, files
, sections
, lookup
, table
, flags
, userdata
, ret_mtime
);
479 /* Parse each config file in the directories specified as strv. */
480 int config_parse_many(
481 const char *conf_file
,
482 const char* const* conf_file_dirs
,
483 const char *dropin_dirname
,
484 const char *sections
,
485 ConfigItemLookup lookup
,
487 ConfigParseFlags flags
,
491 _cleanup_strv_free_
char **dropin_dirs
= NULL
;
492 _cleanup_strv_free_
char **files
= NULL
;
496 suffix
= strjoina("/", dropin_dirname
);
497 r
= strv_extend_strv_concat(&dropin_dirs
, (char**) conf_file_dirs
, suffix
);
501 r
= conf_files_list_strv(&files
, ".conf", NULL
, 0, (const char* const*) dropin_dirs
);
505 return config_parse_many_files(conf_file
, files
, sections
, lookup
, table
, flags
, userdata
, ret_mtime
);
508 #define DEFINE_PARSER(type, vartype, conv_func) \
509 DEFINE_CONFIG_PARSE_PTR(config_parse_##type, conv_func, vartype, "Failed to parse " #type " value")
511 DEFINE_PARSER(int, int, safe_atoi
);
512 DEFINE_PARSER(long, long, safe_atoli
);
513 DEFINE_PARSER(uint8
, uint8_t, safe_atou8
);
514 DEFINE_PARSER(uint16
, uint16_t, safe_atou16
);
515 DEFINE_PARSER(uint32
, uint32_t, safe_atou32
);
516 DEFINE_PARSER(int32
, int32_t, safe_atoi32
);
517 DEFINE_PARSER(uint64
, uint64_t, safe_atou64
);
518 DEFINE_PARSER(unsigned, unsigned, safe_atou
);
519 DEFINE_PARSER(double, double, safe_atod
);
520 DEFINE_PARSER(nsec
, nsec_t
, parse_nsec
);
521 DEFINE_PARSER(sec
, usec_t
, parse_sec
);
522 DEFINE_PARSER(sec_def_infinity
, usec_t
, parse_sec_def_infinity
);
523 DEFINE_PARSER(mode
, mode_t
, parse_mode
);
525 int config_parse_iec_size(const char* unit
,
526 const char *filename
,
529 unsigned section_line
,
545 r
= parse_size(rvalue
, 1024, &v
);
546 if (r
>= 0 && (uint64_t) (size_t) v
!= v
)
549 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to parse size value '%s', ignoring: %m", rvalue
);
557 int config_parse_si_uint64(
559 const char *filename
,
562 unsigned section_line
,
577 r
= parse_size(rvalue
, 1000, sz
);
579 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to parse size value '%s', ignoring: %m", rvalue
);
584 int config_parse_iec_uint64(
586 const char *filename
,
589 unsigned section_line
,
596 uint64_t *bytes
= data
;
604 r
= parse_size(rvalue
, 1024, bytes
);
606 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to parse size value, ignoring: %s", rvalue
);
611 int config_parse_bool(const char* unit
,
612 const char *filename
,
615 unsigned section_line
,
631 k
= parse_boolean(rvalue
);
633 log_syntax(unit
, fatal
? LOG_ERR
: LOG_WARNING
, filename
, line
, k
,
634 "Failed to parse boolean value%s: %s",
635 fatal
? "" : ", ignoring", rvalue
);
636 return fatal
? -ENOEXEC
: 0;
643 int config_parse_id128(
645 const char *filename
,
648 unsigned section_line
,
655 sd_id128_t t
, *result
= data
;
662 r
= sd_id128_from_string(rvalue
, &t
);
664 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to parse 128bit ID/UUID, ignoring: %s", rvalue
);
668 if (sd_id128_is_null(t
)) {
669 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "128bit ID/UUID is all 0, ignoring: %s", rvalue
);
677 int config_parse_tristate(
679 const char *filename
,
682 unsigned section_line
,
696 /* A tristate is pretty much a boolean, except that it can
697 * also take the special value -1, indicating "uninitialized",
698 * much like NULL is for a pointer type. */
700 k
= parse_boolean(rvalue
);
702 log_syntax(unit
, LOG_WARNING
, filename
, line
, k
, "Failed to parse boolean value, ignoring: %s", rvalue
);
710 int config_parse_string(
712 const char *filename
,
715 unsigned section_line
,
729 if (free_and_strdup(s
, empty_to_null(rvalue
)) < 0)
735 int config_parse_path(
737 const char *filename
,
740 unsigned section_line
,
747 _cleanup_free_
char *n
= NULL
;
764 r
= path_simplify_and_warn(n
, PATH_CHECK_ABSOLUTE
| (fatal
? PATH_CHECK_FATAL
: 0), unit
, filename
, line
, lvalue
);
766 return fatal
? -ENOEXEC
: 0;
769 return free_and_replace(*s
, n
);
772 int config_parse_strv(
774 const char *filename
,
777 unsigned section_line
,
792 if (isempty(rvalue
)) {
793 *sv
= strv_free(*sv
);
797 for (const char *p
= rvalue
;;) {
800 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_UNQUOTE
|EXTRACT_RETAIN_ESCAPE
);
806 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Invalid syntax, ignoring: %s", rvalue
);
810 r
= strv_consume(sv
, word
);
816 int config_parse_warn_compat(
818 const char *filename
,
821 unsigned section_line
,
828 Disabled reason
= ltype
;
832 case DISABLED_CONFIGURATION
:
833 log_syntax(unit
, LOG_DEBUG
, filename
, line
, 0,
834 "Support for option %s= has been disabled at compile time and it is ignored", lvalue
);
837 case DISABLED_LEGACY
:
838 log_syntax(unit
, LOG_INFO
, filename
, line
, 0,
839 "Support for option %s= has been removed and it is ignored", lvalue
);
842 case DISABLED_EXPERIMENTAL
:
843 log_syntax(unit
, LOG_INFO
, filename
, line
, 0,
844 "Support for option %s= has not yet been enabled and it is ignored", lvalue
);
851 int config_parse_log_facility(
853 const char *filename
,
856 unsigned section_line
,
870 x
= log_facility_unshifted_from_string(rvalue
);
872 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Failed to parse log facility, ignoring: %s", rvalue
);
876 *o
= (x
<< 3) | LOG_PRI(*o
);
881 int config_parse_log_level(
883 const char *filename
,
886 unsigned section_line
,
900 x
= log_level_from_string(rvalue
);
902 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Failed to parse log level, ignoring: %s", rvalue
);
906 if (*o
< 0) /* if it wasn't initialized so far, assume zero facility */
909 *o
= (*o
& LOG_FACMASK
) | x
;
914 int config_parse_signal(
916 const char *filename
,
919 unsigned section_line
,
933 r
= signal_from_string(rvalue
);
935 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Failed to parse signal name, ignoring: %s", rvalue
);
943 int config_parse_personality(
945 const char *filename
,
948 unsigned section_line
,
955 unsigned long *personality
= data
, p
;
963 p
= PERSONALITY_INVALID
;
965 p
= personality_from_string(rvalue
);
966 if (p
== PERSONALITY_INVALID
) {
967 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Failed to parse personality, ignoring: %s", rvalue
);
976 int config_parse_ifname(
978 const char *filename
,
981 unsigned section_line
,
996 if (isempty(rvalue
)) {
1001 if (!ifname_valid(rvalue
)) {
1002 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Interface name is not valid or too long, ignoring assignment: %s", rvalue
);
1006 r
= free_and_strdup(s
, rvalue
);
1013 int config_parse_ifnames(
1015 const char *filename
,
1017 const char *section
,
1018 unsigned section_line
,
1025 _cleanup_strv_free_
char **names
= NULL
;
1034 if (isempty(rvalue
)) {
1039 for (const char *p
= rvalue
;;) {
1040 _cleanup_free_
char *word
= NULL
;
1042 r
= extract_first_word(&p
, &word
, NULL
, 0);
1046 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1047 "Failed to extract interface name, ignoring assignment: %s",
1054 if (!ifname_valid_full(word
, ltype
)) {
1055 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1056 "Interface name is not valid or too long, ignoring assignment: %s",
1061 r
= strv_consume(&names
, TAKE_PTR(word
));
1066 r
= strv_extend_strv(s
, names
, true);
1073 int config_parse_ip_port(
1075 const char *filename
,
1077 const char *section
,
1078 unsigned section_line
,
1094 if (isempty(rvalue
)) {
1099 r
= parse_ip_port(rvalue
, &port
);
1101 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to parse port '%s'.", rvalue
);
1110 int config_parse_mtu(
1112 const char *filename
,
1114 const char *section
,
1115 unsigned section_line
,
1122 uint32_t *mtu
= data
;
1128 r
= parse_mtu(ltype
, rvalue
, mtu
);
1130 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1131 "Maximum transfer unit (MTU) value out of range. Permitted range is %" PRIu32
"…%" PRIu32
", ignoring: %s",
1132 (uint32_t) (ltype
== AF_INET6
? IPV6_MIN_MTU
: IPV4_MIN_MTU
), (uint32_t) UINT32_MAX
,
1137 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1138 "Failed to parse MTU value '%s', ignoring: %m", rvalue
);
1145 int config_parse_rlimit(
1147 const char *filename
,
1149 const char *section
,
1150 unsigned section_line
,
1157 struct rlimit
**rl
= data
, d
= {};
1163 r
= rlimit_parse(ltype
, rvalue
, &d
);
1165 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Soft resource limit chosen higher than hard limit, ignoring: %s", rvalue
);
1169 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to parse resource value, ignoring: %s", rvalue
);
1176 rl
[ltype
] = newdup(struct rlimit
, &d
, 1);
1184 int config_parse_permille(const char* unit
,
1185 const char *filename
,
1187 const char *section
,
1188 unsigned section_line
,
1195 unsigned *permille
= data
;
1203 r
= parse_permille(rvalue
);
1205 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1206 "Failed to parse permille value, ignoring: %s", rvalue
);
1210 *permille
= (unsigned) r
;
1215 int config_parse_vlanprotocol(const char* unit
,
1216 const char *filename
,
1218 const char *section
,
1219 unsigned section_line
,
1225 int *vlan_protocol
= data
;
1229 if (isempty(rvalue
)) {
1230 *vlan_protocol
= -1;
1234 if (STR_IN_SET(rvalue
, "802.1ad", "802.1AD"))
1235 *vlan_protocol
= ETH_P_8021AD
;
1236 else if (STR_IN_SET(rvalue
, "802.1q", "802.1Q"))
1237 *vlan_protocol
= ETH_P_8021Q
;
1239 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1240 "Failed to parse VLAN protocol value, ignoring: %s", rvalue
);