1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2010 Lennart Poettering
14 #include <sys/types.h>
16 #include "alloc-util.h"
17 #include "conf-files.h"
18 #include "conf-parser.h"
20 #include "extract-word.h"
26 #include "parse-util.h"
27 #include "path-util.h"
28 #include "process-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
;
90 p
= lookup(lvalue
, strlen(lvalue
));
94 key
= strjoin(section
, ".", lvalue
);
98 p
= lookup(key
, strlen(key
));
107 *data
= (uint8_t*) userdata
+ p
->offset
;
111 /* Run the user supplied parser for an assignment */
112 static int next_assignment(
114 const char *filename
,
116 ConfigItemLookup lookup
,
119 unsigned section_line
,
122 ConfigParseFlags flags
,
125 ConfigParserCallback func
= NULL
;
136 r
= lookup(table
, section
, lvalue
, &func
, <ype
, &data
, userdata
);
142 return func(unit
, filename
, line
, section
, section_line
,
143 lvalue
, ltype
, rvalue
, data
, userdata
);
148 /* Warn about unknown non-extension fields. */
149 if (!(flags
& CONFIG_PARSE_RELAXED
) && !startswith(lvalue
, "X-"))
150 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Unknown lvalue '%s' in section '%s'", lvalue
, section
);
155 /* Parse a single logical line */
156 static int parse_line(
158 const char *filename
,
160 const char *sections
,
161 ConfigItemLookup lookup
,
163 ConfigParseFlags flags
,
165 unsigned *section_line
,
166 bool *section_ignored
,
181 if (strchr(COMMENTS
"\n", *l
))
184 include
= first_word(l
, ".include");
186 _cleanup_free_
char *fn
= NULL
;
188 /* .includes are a bad idea, we only support them here
189 * for historical reasons. They create cyclic include
190 * problems and make it difficult to detect
191 * configuration file changes with an easy
192 * stat(). Better approaches, such as .d/ drop-in
195 * Support for them should be eventually removed. */
197 if (!(flags
& CONFIG_PARSE_ALLOW_INCLUDE
)) {
198 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, ".include not allowed here. Ignoring.");
202 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
203 ".include directives are deprecated, and support for them will be removed in a future version of systemd. "
204 "Please use drop-in files instead.");
206 fn
= file_in_same_dir(filename
, strstrip(include
));
210 return config_parse(unit
, fn
, NULL
, sections
, lookup
, table
, flags
, userdata
);
221 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid section header '%s'", l
);
225 n
= strndup(l
+1, k
-2);
229 if (sections
&& !nulstr_contains(sections
, n
)) {
231 if (!(flags
& CONFIG_PARSE_RELAXED
) && !startswith(n
, "X-"))
232 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Unknown section '%s'. Ignoring.", n
);
235 *section
= mfree(*section
);
237 *section_ignored
= true;
241 *section_line
= line
;
242 *section_ignored
= false;
248 if (sections
&& !*section
) {
250 if (!(flags
& CONFIG_PARSE_RELAXED
) && !*section_ignored
)
251 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Assignment outside of section. Ignoring.");
258 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Missing '='.");
265 return next_assignment(unit
,
278 /* Go through the file and parse each line */
279 int config_parse(const char *unit
,
280 const char *filename
,
282 const char *sections
,
283 ConfigItemLookup lookup
,
285 ConfigParseFlags flags
,
288 _cleanup_free_
char *section
= NULL
, *continuation
= NULL
;
289 _cleanup_fclose_
FILE *ours
= NULL
;
290 unsigned line
= 0, section_line
= 0;
291 bool section_ignored
= false;
298 f
= ours
= fopen(filename
, "re");
300 /* Only log on request, except for ENOENT,
301 * since we return 0 to the caller. */
302 if ((flags
& CONFIG_PARSE_WARN
) || errno
== ENOENT
)
303 log_full(errno
== ENOENT
? LOG_DEBUG
: LOG_ERR
,
304 "Failed to open configuration file '%s': %m", filename
);
305 return errno
== ENOENT
? 0 : -errno
;
309 fd_warn_permissions(filename
, fileno(f
));
312 _cleanup_free_
char *buf
= NULL
;
313 bool escaped
= false;
316 r
= read_line(f
, LONG_LINE_MAX
, &buf
);
320 if (flags
& CONFIG_PARSE_WARN
)
321 log_error_errno(r
, "%s:%u: Line too long", filename
, line
);
326 if (CONFIG_PARSE_WARN
)
327 log_error_errno(r
, "%s:%u: Error while reading configuration file: %m", filename
, line
);
333 if (!(flags
& CONFIG_PARSE_REFUSE_BOM
)) {
336 q
= startswith(buf
, UTF8_BYTE_ORDER_MARK
);
339 flags
|= CONFIG_PARSE_REFUSE_BOM
;
344 if (strlen(continuation
) + strlen(l
) > LONG_LINE_MAX
) {
345 if (flags
& CONFIG_PARSE_WARN
)
346 log_error("%s:%u: Continuation line too long", filename
, line
);
350 if (!strextend(&continuation
, l
, NULL
)) {
351 if (flags
& CONFIG_PARSE_WARN
)
360 for (e
= p
; *e
; e
++) {
371 continuation
= strdup(l
);
373 if (flags
& CONFIG_PARSE_WARN
)
395 if (flags
& CONFIG_PARSE_WARN
)
396 log_warning_errno(r
, "%s:%u: Failed to parse file: %m", filename
, line
);
401 continuation
= mfree(continuation
);
418 if (flags
& CONFIG_PARSE_WARN
)
419 log_warning_errno(r
, "%s:%u: Failed to parse file: %m", filename
, line
);
428 static int config_parse_many_files(
429 const char *conf_file
,
431 const char *sections
,
432 ConfigItemLookup lookup
,
434 ConfigParseFlags flags
,
441 r
= config_parse(NULL
, conf_file
, NULL
, sections
, lookup
, table
, flags
, userdata
);
446 STRV_FOREACH(fn
, files
) {
447 r
= config_parse(NULL
, *fn
, NULL
, sections
, lookup
, table
, flags
, userdata
);
455 /* Parse each config file in the directories specified as nulstr. */
456 int config_parse_many_nulstr(
457 const char *conf_file
,
458 const char *conf_file_dirs
,
459 const char *sections
,
460 ConfigItemLookup lookup
,
462 ConfigParseFlags flags
,
465 _cleanup_strv_free_
char **files
= NULL
;
468 r
= conf_files_list_nulstr(&files
, ".conf", NULL
, 0, conf_file_dirs
);
472 return config_parse_many_files(conf_file
, files
, sections
, lookup
, table
, flags
, userdata
);
475 /* Parse each config file in the directories specified as strv. */
476 int config_parse_many(
477 const char *conf_file
,
478 const char* const* conf_file_dirs
,
479 const char *dropin_dirname
,
480 const char *sections
,
481 ConfigItemLookup lookup
,
483 ConfigParseFlags flags
,
486 _cleanup_strv_free_
char **dropin_dirs
= NULL
;
487 _cleanup_strv_free_
char **files
= NULL
;
491 suffix
= strjoina("/", dropin_dirname
);
492 r
= strv_extend_strv_concat(&dropin_dirs
, (char**) conf_file_dirs
, suffix
);
496 r
= conf_files_list_strv(&files
, ".conf", NULL
, 0, (const char* const*) dropin_dirs
);
500 return config_parse_many_files(conf_file
, files
, sections
, lookup
, table
, flags
, userdata
);
503 #define DEFINE_PARSER(type, vartype, conv_func) \
504 int config_parse_##type( \
506 const char *filename, \
508 const char *section, \
509 unsigned section_line, \
510 const char *lvalue, \
512 const char *rvalue, \
524 r = conv_func(rvalue, i); \
526 log_syntax(unit, LOG_ERR, filename, line, r, \
527 "Failed to parse %s value, ignoring: %s", \
533 DEFINE_PARSER(int, int, safe_atoi
);
534 DEFINE_PARSER(long, long, safe_atoli
);
535 DEFINE_PARSER(uint8
, uint8_t, safe_atou8
);
536 DEFINE_PARSER(uint16
, uint16_t, safe_atou16
);
537 DEFINE_PARSER(uint32
, uint32_t, safe_atou32
);
538 DEFINE_PARSER(uint64
, uint64_t, safe_atou64
);
539 DEFINE_PARSER(unsigned, unsigned, safe_atou
);
540 DEFINE_PARSER(double, double, safe_atod
);
541 DEFINE_PARSER(nsec
, nsec_t
, parse_nsec
);
542 DEFINE_PARSER(sec
, usec_t
, parse_sec
);
543 DEFINE_PARSER(mode
, mode_t
, parse_mode
);
545 int config_parse_iec_size(const char* unit
,
546 const char *filename
,
549 unsigned section_line
,
565 r
= parse_size(rvalue
, 1024, &v
);
566 if (r
< 0 || (uint64_t) (size_t) v
!= v
) {
567 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse size value, ignoring: %s", rvalue
);
575 int config_parse_si_size(
577 const char *filename
,
580 unsigned section_line
,
596 r
= parse_size(rvalue
, 1000, &v
);
597 if (r
< 0 || (uint64_t) (size_t) v
!= v
) {
598 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse size value, ignoring: %s", rvalue
);
606 int config_parse_iec_uint64(
608 const char *filename
,
611 unsigned section_line
,
618 uint64_t *bytes
= data
;
626 r
= parse_size(rvalue
, 1024, bytes
);
628 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse size value, ignoring: %s", rvalue
);
633 int config_parse_bool(const char* unit
,
634 const char *filename
,
637 unsigned section_line
,
653 k
= parse_boolean(rvalue
);
655 log_syntax(unit
, LOG_ERR
, filename
, line
, k
,
656 "Failed to parse boolean value%s: %s",
657 fatal
? "" : ", ignoring", rvalue
);
658 return fatal
? -ENOEXEC
: 0;
665 int config_parse_tristate(
667 const char *filename
,
670 unsigned section_line
,
684 /* A tristate is pretty much a boolean, except that it can
685 * also take the special value -1, indicating "uninitialized",
686 * much like NULL is for a pointer type. */
688 k
= parse_boolean(rvalue
);
690 log_syntax(unit
, LOG_ERR
, filename
, line
, k
, "Failed to parse boolean value, ignoring: %s", rvalue
);
698 int config_parse_string(
700 const char *filename
,
703 unsigned section_line
,
717 if (!utf8_is_valid(rvalue
)) {
718 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
736 int config_parse_path(
738 const char *filename
,
741 unsigned section_line
,
756 if (isempty(rvalue
)) {
761 if (!utf8_is_valid(rvalue
)) {
762 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
763 return fatal
? -ENOEXEC
: 0;
766 if (!path_is_absolute(rvalue
)) {
767 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
768 "Not an absolute path%s: %s",
769 fatal
? "" : ", ignoring", rvalue
);
770 return fatal
? -ENOEXEC
: 0;
777 path_kill_slashes(n
);
786 int config_parse_strv(
788 const char *filename
,
791 unsigned section_line
,
806 if (isempty(rvalue
)) {
807 *sv
= strv_free(*sv
);
814 r
= extract_first_word(&rvalue
, &word
, NULL
, EXTRACT_QUOTES
|EXTRACT_RETAIN_ESCAPE
);
820 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid syntax, ignoring: %s", rvalue
);
824 if (!utf8_is_valid(word
)) {
825 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, word
);
830 r
= strv_consume(sv
, word
);
838 int config_parse_warn_compat(
840 const char *filename
,
843 unsigned section_line
,
849 Disabled reason
= ltype
;
852 case DISABLED_CONFIGURATION
:
853 log_syntax(unit
, LOG_DEBUG
, filename
, line
, 0,
854 "Support for option %s= has been disabled at compile time and it is ignored", lvalue
);
856 case DISABLED_LEGACY
:
857 log_syntax(unit
, LOG_INFO
, filename
, line
, 0,
858 "Support for option %s= has been removed and it is ignored", lvalue
);
860 case DISABLED_EXPERIMENTAL
:
861 log_syntax(unit
, LOG_INFO
, filename
, line
, 0,
862 "Support for option %s= has not yet been enabled and it is ignored", lvalue
);
869 int config_parse_log_facility(
871 const char *filename
,
874 unsigned section_line
,
888 x
= log_facility_unshifted_from_string(rvalue
);
890 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse log facility, ignoring: %s", rvalue
);
894 *o
= (x
<< 3) | LOG_PRI(*o
);
899 int config_parse_log_level(
901 const char *filename
,
904 unsigned section_line
,
918 x
= log_level_from_string(rvalue
);
920 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse log level, ignoring: %s", rvalue
);
924 if (*o
< 0) /* if it wasn't initialized so far, assume zero facility */
927 *o
= (*o
& LOG_FACMASK
) | x
;
932 int config_parse_signal(
934 const char *filename
,
937 unsigned section_line
,
951 r
= signal_from_string(rvalue
);
953 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse signal name, ignoring: %s", rvalue
);
961 int config_parse_personality(
963 const char *filename
,
966 unsigned section_line
,
973 unsigned long *personality
= data
, p
;
981 p
= PERSONALITY_INVALID
;
983 p
= personality_from_string(rvalue
);
984 if (p
== PERSONALITY_INVALID
) {
985 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse personality, ignoring: %s", rvalue
);
994 int config_parse_ifname(
996 const char *filename
,
999 unsigned section_line
,
1014 if (isempty(rvalue
)) {
1019 if (!ifname_valid(rvalue
)) {
1020 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Interface name is not valid or too long, ignoring assignment: %s", rvalue
);
1024 r
= free_and_strdup(s
, rvalue
);
1031 int config_parse_ip_port(
1033 const char *filename
,
1035 const char *section
,
1036 unsigned section_line
,
1052 if (isempty(rvalue
)) {
1057 r
= parse_ip_port(rvalue
, &port
);
1059 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse port '%s'.", rvalue
);
1068 int config_parse_join_controllers(
1070 const char *filename
,
1072 const char *section
,
1073 unsigned section_line
,
1080 char ****ret
= data
;
1081 const char *whole_rvalue
= rvalue
;
1083 _cleanup_(strv_free_freep
) char ***controllers
= NULL
;
1091 _cleanup_free_
char *word
= NULL
;
1095 r
= extract_first_word(&rvalue
, &word
, NULL
, EXTRACT_QUOTES
);
1097 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid value for %s: %s", lvalue
, whole_rvalue
);
1103 l
= strv_split(word
, ",");
1108 if (strv_length(l
) <= 1) {
1114 controllers
= new(char**, 2);
1121 controllers
[1] = NULL
;
1128 t
= new0(char**, n
+2);
1136 for (a
= controllers
; *a
; a
++)
1137 if (strv_overlap(*a
, l
)) {
1138 if (strv_extend_strv(&l
, *a
, false) < 0) {
1157 t
[n
++] = strv_uniq(l
);
1159 strv_free_free(controllers
);
1163 if (!isempty(rvalue
))
1164 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
1166 /* As a special case, return a single empty strv, to override the default */
1168 controllers
= new(char**, 2);
1171 controllers
[0] = strv_new(NULL
, NULL
);
1172 if (!controllers
[0])
1174 controllers
[1] = NULL
;
1177 strv_free_free(*ret
);
1178 *ret
= TAKE_PTR(controllers
);
1183 int config_parse_mtu(
1185 const char *filename
,
1187 const char *section
,
1188 unsigned section_line
,
1195 uint32_t *mtu
= data
;
1201 r
= parse_mtu(ltype
, rvalue
, mtu
);
1203 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
1204 "Maximum transfer unit (MTU) value out of range. Permitted range is %" PRIu32
"…%" PRIu32
", ignoring: %s",
1205 (uint32_t) (ltype
== AF_INET6
? IPV6_MIN_MTU
: IPV4_MIN_MTU
), (uint32_t) UINT32_MAX
,
1210 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
1211 "Failed to parse MTU value '%s', ignoring: %m", rvalue
);