1 /* SPDX-License-Identifier: LGPL-2.1+ */
11 #include "alloc-util.h"
12 #include "conf-files.h"
13 #include "conf-parser.h"
15 #include "extract-word.h"
21 #include "parse-util.h"
22 #include "path-util.h"
23 #include "process-util.h"
24 #include "signal-util.h"
25 #include "socket-util.h"
26 #include "string-util.h"
28 #include "syslog-util.h"
29 #include "time-util.h"
31 #include "rlimit-util.h"
33 int config_item_table_lookup(
37 ConfigParserCallback
*func
,
42 const ConfigTableItem
*t
;
50 for (t
= table
; t
->lvalue
; t
++) {
52 if (!streq(lvalue
, t
->lvalue
))
55 if (!streq_ptr(section
, t
->section
))
67 int config_item_perf_lookup(
71 ConfigParserCallback
*func
,
76 ConfigPerfItemLookup lookup
= (ConfigPerfItemLookup
) table
;
77 const ConfigPerfItem
*p
;
88 key
= strjoina(section
, ".", lvalue
);
89 p
= lookup(key
, strlen(key
));
91 p
= lookup(lvalue
, strlen(lvalue
));
97 *data
= (uint8_t*) userdata
+ p
->offset
;
101 /* Run the user supplied parser for an assignment */
102 static int next_assignment(
104 const char *filename
,
106 ConfigItemLookup lookup
,
109 unsigned section_line
,
112 ConfigParseFlags flags
,
115 ConfigParserCallback func
= NULL
;
126 r
= lookup(table
, section
, lvalue
, &func
, <ype
, &data
, userdata
);
131 return func(unit
, filename
, line
, section
, section_line
,
132 lvalue
, ltype
, rvalue
, data
, userdata
);
137 /* Warn about unknown non-extension fields. */
138 if (!(flags
& CONFIG_PARSE_RELAXED
) && !startswith(lvalue
, "X-"))
139 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Unknown lvalue '%s' in section '%s'", lvalue
, section
);
144 /* Parse a single logical line */
145 static int parse_line(
147 const char *filename
,
149 const char *sections
,
150 ConfigItemLookup lookup
,
152 ConfigParseFlags flags
,
154 unsigned *section_line
,
155 bool *section_ignored
,
173 include
= first_word(l
, ".include");
175 _cleanup_free_
char *fn
= NULL
;
177 /* .includes are a bad idea, we only support them here
178 * for historical reasons. They create cyclic include
179 * problems and make it difficult to detect
180 * configuration file changes with an easy
181 * stat(). Better approaches, such as .d/ drop-in
184 * Support for them should be eventually removed. */
186 if (!(flags
& CONFIG_PARSE_ALLOW_INCLUDE
)) {
187 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, ".include not allowed here. Ignoring.");
191 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
192 ".include directives are deprecated, and support for them will be removed in a future version of systemd. "
193 "Please use drop-in files instead.");
195 fn
= file_in_same_dir(filename
, strstrip(include
));
199 return config_parse(unit
, fn
, NULL
, sections
, lookup
, table
, flags
, userdata
);
202 if (!utf8_is_valid(l
))
203 return log_syntax_invalid_utf8(unit
, LOG_WARNING
, filename
, line
, l
);
213 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid section header '%s'", l
);
217 n
= strndup(l
+1, k
-2);
221 if (sections
&& !nulstr_contains(sections
, n
)) {
223 if (!(flags
& CONFIG_PARSE_RELAXED
) && !startswith(n
, "X-"))
224 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Unknown section '%s'. Ignoring.", n
);
227 *section
= mfree(*section
);
229 *section_ignored
= true;
231 free_and_replace(*section
, n
);
232 *section_line
= line
;
233 *section_ignored
= false;
239 if (sections
&& !*section
) {
241 if (!(flags
& CONFIG_PARSE_RELAXED
) && !*section_ignored
)
242 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Assignment outside of section. Ignoring.");
249 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Missing '='.");
256 return next_assignment(unit
,
269 /* Go through the file and parse each line */
270 int config_parse(const char *unit
,
271 const char *filename
,
273 const char *sections
,
274 ConfigItemLookup lookup
,
276 ConfigParseFlags flags
,
279 _cleanup_free_
char *section
= NULL
, *continuation
= NULL
;
280 _cleanup_fclose_
FILE *ours
= NULL
;
281 unsigned line
= 0, section_line
= 0;
282 bool section_ignored
= false;
289 f
= ours
= fopen(filename
, "re");
291 /* Only log on request, except for ENOENT,
292 * since we return 0 to the caller. */
293 if ((flags
& CONFIG_PARSE_WARN
) || errno
== ENOENT
)
294 log_full_errno(errno
== ENOENT
? LOG_DEBUG
: LOG_ERR
, errno
,
295 "Failed to open configuration file '%s': %m", filename
);
296 return errno
== ENOENT
? 0 : -errno
;
300 fd_warn_permissions(filename
, fileno(f
));
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 (CONFIG_PARSE_WARN
)
318 log_error_errno(r
, "%s:%u: Error while reading configuration file: %m", filename
, line
);
323 if (strchr(COMMENTS
, *buf
))
327 if (!(flags
& CONFIG_PARSE_REFUSE_BOM
)) {
330 q
= startswith(buf
, UTF8_BYTE_ORDER_MARK
);
333 flags
|= CONFIG_PARSE_REFUSE_BOM
;
338 if (strlen(continuation
) + strlen(l
) > LONG_LINE_MAX
) {
339 if (flags
& CONFIG_PARSE_WARN
)
340 log_error("%s:%u: Continuation line too long", filename
, line
);
344 if (!strextend(&continuation
, l
, NULL
)) {
345 if (flags
& CONFIG_PARSE_WARN
)
354 for (e
= p
; *e
; e
++) {
365 continuation
= strdup(l
);
367 if (flags
& CONFIG_PARSE_WARN
)
389 if (flags
& CONFIG_PARSE_WARN
)
390 log_warning_errno(r
, "%s:%u: Failed to parse file: %m", filename
, line
);
394 continuation
= mfree(continuation
);
411 if (flags
& CONFIG_PARSE_WARN
)
412 log_warning_errno(r
, "%s:%u: Failed to parse file: %m", filename
, line
);
420 static int config_parse_many_files(
421 const char *conf_file
,
423 const char *sections
,
424 ConfigItemLookup lookup
,
426 ConfigParseFlags flags
,
433 r
= config_parse(NULL
, conf_file
, NULL
, sections
, lookup
, table
, flags
, userdata
);
438 STRV_FOREACH(fn
, files
) {
439 r
= config_parse(NULL
, *fn
, NULL
, sections
, lookup
, table
, flags
, userdata
);
447 /* Parse each config file in the directories specified as nulstr. */
448 int config_parse_many_nulstr(
449 const char *conf_file
,
450 const char *conf_file_dirs
,
451 const char *sections
,
452 ConfigItemLookup lookup
,
454 ConfigParseFlags flags
,
457 _cleanup_strv_free_
char **files
= NULL
;
460 r
= conf_files_list_nulstr(&files
, ".conf", NULL
, 0, conf_file_dirs
);
464 return config_parse_many_files(conf_file
, files
, sections
, lookup
, table
, flags
, userdata
);
467 /* Parse each config file in the directories specified as strv. */
468 int config_parse_many(
469 const char *conf_file
,
470 const char* const* conf_file_dirs
,
471 const char *dropin_dirname
,
472 const char *sections
,
473 ConfigItemLookup lookup
,
475 ConfigParseFlags flags
,
478 _cleanup_strv_free_
char **dropin_dirs
= NULL
;
479 _cleanup_strv_free_
char **files
= NULL
;
483 suffix
= strjoina("/", dropin_dirname
);
484 r
= strv_extend_strv_concat(&dropin_dirs
, (char**) conf_file_dirs
, suffix
);
488 r
= conf_files_list_strv(&files
, ".conf", NULL
, 0, (const char* const*) dropin_dirs
);
492 return config_parse_many_files(conf_file
, files
, sections
, lookup
, table
, flags
, userdata
);
495 #define DEFINE_PARSER(type, vartype, conv_func) \
496 DEFINE_CONFIG_PARSE_PTR(config_parse_##type, conv_func, vartype, "Failed to parse " #type " value")
498 DEFINE_PARSER(int, int, safe_atoi
);
499 DEFINE_PARSER(long, long, safe_atoli
);
500 DEFINE_PARSER(uint8
, uint8_t, safe_atou8
);
501 DEFINE_PARSER(uint16
, uint16_t, safe_atou16
);
502 DEFINE_PARSER(uint32
, uint32_t, safe_atou32
);
503 DEFINE_PARSER(uint64
, uint64_t, safe_atou64
);
504 DEFINE_PARSER(unsigned, unsigned, safe_atou
);
505 DEFINE_PARSER(double, double, safe_atod
);
506 DEFINE_PARSER(nsec
, nsec_t
, parse_nsec
);
507 DEFINE_PARSER(sec
, usec_t
, parse_sec
);
508 DEFINE_PARSER(mode
, mode_t
, parse_mode
);
510 int config_parse_iec_size(const char* unit
,
511 const char *filename
,
514 unsigned section_line
,
530 r
= parse_size(rvalue
, 1024, &v
);
531 if (r
>= 0 && (uint64_t) (size_t) v
!= v
)
534 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse size value '%s', ignoring: %m", rvalue
);
542 int config_parse_si_size(
544 const char *filename
,
547 unsigned section_line
,
563 r
= parse_size(rvalue
, 1000, &v
);
564 if (r
>= 0 && (uint64_t) (size_t) v
!= v
)
567 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse size value '%s', ignoring: %m", rvalue
);
575 int config_parse_iec_uint64(
577 const char *filename
,
580 unsigned section_line
,
587 uint64_t *bytes
= data
;
595 r
= parse_size(rvalue
, 1024, bytes
);
597 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse size value, ignoring: %s", rvalue
);
602 int config_parse_bool(const char* unit
,
603 const char *filename
,
606 unsigned section_line
,
622 k
= parse_boolean(rvalue
);
624 log_syntax(unit
, LOG_ERR
, filename
, line
, k
,
625 "Failed to parse boolean value%s: %s",
626 fatal
? "" : ", ignoring", rvalue
);
627 return fatal
? -ENOEXEC
: 0;
634 int config_parse_tristate(
636 const char *filename
,
639 unsigned section_line
,
653 /* A tristate is pretty much a boolean, except that it can
654 * also take the special value -1, indicating "uninitialized",
655 * much like NULL is for a pointer type. */
657 k
= parse_boolean(rvalue
);
659 log_syntax(unit
, LOG_ERR
, filename
, line
, k
, "Failed to parse boolean value, ignoring: %s", rvalue
);
667 int config_parse_string(
669 const char *filename
,
672 unsigned section_line
,
686 if (free_and_strdup(s
, empty_to_null(rvalue
)) < 0)
692 int config_parse_path(
694 const char *filename
,
697 unsigned section_line
,
704 _cleanup_free_
char *n
= NULL
;
721 r
= path_simplify_and_warn(n
, PATH_CHECK_ABSOLUTE
| (fatal
? PATH_CHECK_FATAL
: 0), unit
, filename
, line
, lvalue
);
723 return fatal
? -ENOEXEC
: 0;
726 return free_and_replace(*s
, n
);
729 int config_parse_strv(
731 const char *filename
,
734 unsigned section_line
,
749 if (isempty(rvalue
)) {
750 *sv
= strv_free(*sv
);
757 r
= extract_first_word(&rvalue
, &word
, NULL
, EXTRACT_QUOTES
|EXTRACT_RETAIN_ESCAPE
);
763 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid syntax, ignoring: %s", rvalue
);
767 r
= strv_consume(sv
, word
);
775 int config_parse_warn_compat(
777 const char *filename
,
780 unsigned section_line
,
787 Disabled reason
= ltype
;
791 case DISABLED_CONFIGURATION
:
792 log_syntax(unit
, LOG_DEBUG
, filename
, line
, 0,
793 "Support for option %s= has been disabled at compile time and it is ignored", lvalue
);
796 case DISABLED_LEGACY
:
797 log_syntax(unit
, LOG_INFO
, filename
, line
, 0,
798 "Support for option %s= has been removed and it is ignored", lvalue
);
801 case DISABLED_EXPERIMENTAL
:
802 log_syntax(unit
, LOG_INFO
, filename
, line
, 0,
803 "Support for option %s= has not yet been enabled and it is ignored", lvalue
);
810 int config_parse_log_facility(
812 const char *filename
,
815 unsigned section_line
,
829 x
= log_facility_unshifted_from_string(rvalue
);
831 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse log facility, ignoring: %s", rvalue
);
835 *o
= (x
<< 3) | LOG_PRI(*o
);
840 int config_parse_log_level(
842 const char *filename
,
845 unsigned section_line
,
859 x
= log_level_from_string(rvalue
);
861 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse log level, ignoring: %s", rvalue
);
865 if (*o
< 0) /* if it wasn't initialized so far, assume zero facility */
868 *o
= (*o
& LOG_FACMASK
) | x
;
873 int config_parse_signal(
875 const char *filename
,
878 unsigned section_line
,
892 r
= signal_from_string(rvalue
);
894 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse signal name, ignoring: %s", rvalue
);
902 int config_parse_personality(
904 const char *filename
,
907 unsigned section_line
,
914 unsigned long *personality
= data
, p
;
922 p
= PERSONALITY_INVALID
;
924 p
= personality_from_string(rvalue
);
925 if (p
== PERSONALITY_INVALID
) {
926 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse personality, ignoring: %s", rvalue
);
935 int config_parse_ifname(
937 const char *filename
,
940 unsigned section_line
,
955 if (isempty(rvalue
)) {
960 if (!ifname_valid(rvalue
)) {
961 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Interface name is not valid or too long, ignoring assignment: %s", rvalue
);
965 r
= free_and_strdup(s
, rvalue
);
972 int config_parse_ip_port(
974 const char *filename
,
977 unsigned section_line
,
993 if (isempty(rvalue
)) {
998 r
= parse_ip_port(rvalue
, &port
);
1000 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse port '%s'.", rvalue
);
1009 int config_parse_mtu(
1011 const char *filename
,
1013 const char *section
,
1014 unsigned section_line
,
1021 uint32_t *mtu
= data
;
1027 r
= parse_mtu(ltype
, rvalue
, mtu
);
1029 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
1030 "Maximum transfer unit (MTU) value out of range. Permitted range is %" PRIu32
"…%" PRIu32
", ignoring: %s",
1031 (uint32_t) (ltype
== AF_INET6
? IPV6_MIN_MTU
: IPV4_MIN_MTU
), (uint32_t) UINT32_MAX
,
1036 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
1037 "Failed to parse MTU value '%s', ignoring: %m", rvalue
);
1044 int config_parse_rlimit(
1046 const char *filename
,
1048 const char *section
,
1049 unsigned section_line
,
1056 struct rlimit
**rl
= data
, d
= {};
1062 r
= rlimit_parse(ltype
, rvalue
, &d
);
1064 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Soft resource limit chosen higher than hard limit, ignoring: %s", rvalue
);
1068 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse resource value, ignoring: %s", rvalue
);
1075 rl
[ltype
] = newdup(struct rlimit
, &d
, 1);
1083 int config_parse_permille(const char* unit
,
1084 const char *filename
,
1086 const char *section
,
1087 unsigned section_line
,
1094 unsigned *permille
= data
;
1102 r
= parse_permille(rvalue
);
1104 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
1105 "Failed to parse permille value, ignoring: %s", rvalue
);
1109 *permille
= (unsigned) r
;