1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2010 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
27 #include <sys/types.h>
29 #include "alloc-util.h"
30 #include "conf-files.h"
31 #include "conf-parser.h"
33 #include "extract-word.h"
39 #include "parse-util.h"
40 #include "path-util.h"
41 #include "process-util.h"
42 #include "signal-util.h"
43 #include "socket-util.h"
44 #include "string-util.h"
46 #include "syslog-util.h"
47 #include "time-util.h"
50 int config_item_table_lookup(
54 ConfigParserCallback
*func
,
59 const ConfigTableItem
*t
;
67 for (t
= table
; t
->lvalue
; t
++) {
69 if (!streq(lvalue
, t
->lvalue
))
72 if (!streq_ptr(section
, t
->section
))
84 int config_item_perf_lookup(
88 ConfigParserCallback
*func
,
93 ConfigPerfItemLookup lookup
= (ConfigPerfItemLookup
) table
;
94 const ConfigPerfItem
*p
;
103 p
= lookup(lvalue
, strlen(lvalue
));
107 key
= strjoin(section
, ".", lvalue
);
111 p
= lookup(key
, strlen(key
));
120 *data
= (uint8_t*) userdata
+ p
->offset
;
124 /* Run the user supplied parser for an assignment */
125 static int next_assignment(
127 const char *filename
,
129 ConfigItemLookup lookup
,
132 unsigned section_line
,
135 ConfigParseFlags flags
,
138 ConfigParserCallback func
= NULL
;
149 r
= lookup(table
, section
, lvalue
, &func
, <ype
, &data
, userdata
);
155 return func(unit
, filename
, line
, section
, section_line
,
156 lvalue
, ltype
, rvalue
, data
, userdata
);
161 /* Warn about unknown non-extension fields. */
162 if (!(flags
& CONFIG_PARSE_RELAXED
) && !startswith(lvalue
, "X-"))
163 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Unknown lvalue '%s' in section '%s'", lvalue
, section
);
168 /* Parse a variable assignment line */
169 static int parse_line(
171 const char *filename
,
173 const char *sections
,
174 ConfigItemLookup lookup
,
176 ConfigParseFlags flags
,
178 unsigned *section_line
,
179 bool *section_ignored
,
194 if (strchr(COMMENTS
"\n", *l
))
197 if (startswith(l
, ".include ")) {
198 _cleanup_free_
char *fn
= NULL
;
200 /* .includes are a bad idea, we only support them here
201 * for historical reasons. They create cyclic include
202 * problems and make it difficult to detect
203 * configuration file changes with an easy
204 * stat(). Better approaches, such as .d/ drop-in
207 * Support for them should be eventually removed. */
209 if (!(flags
& CONFIG_PARSE_ALLOW_INCLUDE
)) {
210 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, ".include not allowed here. Ignoring.");
214 fn
= file_in_same_dir(filename
, strstrip(l
+9));
218 return config_parse(unit
, fn
, NULL
, sections
, lookup
, table
, flags
, userdata
);
229 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid section header '%s'", l
);
233 n
= strndup(l
+1, k
-2);
237 if (sections
&& !nulstr_contains(sections
, n
)) {
239 if (!(flags
& CONFIG_PARSE_RELAXED
) && !startswith(n
, "X-"))
240 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Unknown section '%s'. Ignoring.", n
);
243 *section
= mfree(*section
);
245 *section_ignored
= true;
249 *section_line
= line
;
250 *section_ignored
= false;
256 if (sections
&& !*section
) {
258 if (!(flags
& CONFIG_PARSE_RELAXED
) && !*section_ignored
)
259 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Assignment outside of section. Ignoring.");
266 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Missing '='.");
273 return next_assignment(unit
,
286 /* Go through the file and parse each line */
287 int config_parse(const char *unit
,
288 const char *filename
,
290 const char *sections
,
291 ConfigItemLookup lookup
,
293 ConfigParseFlags flags
,
296 _cleanup_free_
char *section
= NULL
, *continuation
= NULL
;
297 _cleanup_fclose_
FILE *ours
= NULL
;
298 unsigned line
= 0, section_line
= 0;
299 bool section_ignored
= false;
306 f
= ours
= fopen(filename
, "re");
308 /* Only log on request, except for ENOENT,
309 * since we return 0 to the caller. */
310 if ((flags
& CONFIG_PARSE_WARN
) || errno
== ENOENT
)
311 log_full(errno
== ENOENT
? LOG_DEBUG
: LOG_ERR
,
312 "Failed to open configuration file '%s': %m", filename
);
313 return errno
== ENOENT
? 0 : -errno
;
317 fd_warn_permissions(filename
, fileno(f
));
320 _cleanup_free_
char *buf
= NULL
;
321 bool escaped
= false;
324 r
= read_line(f
, LONG_LINE_MAX
, &buf
);
328 if (flags
& CONFIG_PARSE_WARN
)
329 log_error_errno(r
, "%s:%u: Line too long", filename
, line
);
334 if (CONFIG_PARSE_WARN
)
335 log_error_errno(r
, "%s:%u: Error while reading configuration file: %m", filename
, line
);
341 if (!(flags
& CONFIG_PARSE_REFUSE_BOM
)) {
344 q
= startswith(buf
, UTF8_BYTE_ORDER_MARK
);
347 flags
|= CONFIG_PARSE_REFUSE_BOM
;
352 if (strlen(continuation
) + strlen(l
) > LONG_LINE_MAX
) {
353 if (flags
& CONFIG_PARSE_WARN
)
354 log_error("%s:%u: Continuation line too long", filename
, line
);
358 if (!strextend(&continuation
, l
, NULL
)) {
359 if (flags
& CONFIG_PARSE_WARN
)
368 for (e
= p
; *e
; e
++) {
379 continuation
= strdup(l
);
381 if (flags
& CONFIG_PARSE_WARN
)
403 if (flags
& CONFIG_PARSE_WARN
)
404 log_warning_errno(r
, "%s:%u: Failed to parse file: %m", filename
, line
);
409 continuation
= mfree(continuation
);
415 static int config_parse_many_files(
416 const char *conf_file
,
418 const char *sections
,
419 ConfigItemLookup lookup
,
421 ConfigParseFlags flags
,
428 r
= config_parse(NULL
, conf_file
, NULL
, sections
, lookup
, table
, flags
, userdata
);
433 STRV_FOREACH(fn
, files
) {
434 r
= config_parse(NULL
, *fn
, NULL
, sections
, lookup
, table
, flags
, userdata
);
442 /* Parse each config file in the directories specified as nulstr. */
443 int config_parse_many_nulstr(
444 const char *conf_file
,
445 const char *conf_file_dirs
,
446 const char *sections
,
447 ConfigItemLookup lookup
,
449 ConfigParseFlags flags
,
452 _cleanup_strv_free_
char **files
= NULL
;
455 r
= conf_files_list_nulstr(&files
, ".conf", NULL
, 0, conf_file_dirs
);
459 return config_parse_many_files(conf_file
, files
, sections
, lookup
, table
, flags
, userdata
);
462 /* Parse each config file in the directories specified as strv. */
463 int config_parse_many(
464 const char *conf_file
,
465 const char* const* conf_file_dirs
,
466 const char *dropin_dirname
,
467 const char *sections
,
468 ConfigItemLookup lookup
,
470 ConfigParseFlags flags
,
473 _cleanup_strv_free_
char **dropin_dirs
= NULL
;
474 _cleanup_strv_free_
char **files
= NULL
;
478 suffix
= strjoina("/", dropin_dirname
);
479 r
= strv_extend_strv_concat(&dropin_dirs
, (char**) conf_file_dirs
, suffix
);
483 r
= conf_files_list_strv(&files
, ".conf", NULL
, 0, (const char* const*) dropin_dirs
);
487 return config_parse_many_files(conf_file
, files
, sections
, lookup
, table
, flags
, userdata
);
490 #define DEFINE_PARSER(type, vartype, conv_func) \
491 int config_parse_##type( \
493 const char *filename, \
495 const char *section, \
496 unsigned section_line, \
497 const char *lvalue, \
499 const char *rvalue, \
511 r = conv_func(rvalue, i); \
513 log_syntax(unit, LOG_ERR, filename, line, r, \
514 "Failed to parse %s value, ignoring: %s", \
520 DEFINE_PARSER(int, int, safe_atoi
);
521 DEFINE_PARSER(long, long, safe_atoli
);
522 DEFINE_PARSER(uint8
, uint8_t, safe_atou8
);
523 DEFINE_PARSER(uint16
, uint16_t, safe_atou16
);
524 DEFINE_PARSER(uint32
, uint32_t, safe_atou32
);
525 DEFINE_PARSER(uint64
, uint64_t, safe_atou64
);
526 DEFINE_PARSER(unsigned, unsigned, safe_atou
);
527 DEFINE_PARSER(double, double, safe_atod
);
528 DEFINE_PARSER(nsec
, nsec_t
, parse_nsec
);
529 DEFINE_PARSER(sec
, usec_t
, parse_sec
);
530 DEFINE_PARSER(mode
, mode_t
, parse_mode
);
532 int config_parse_iec_size(const char* unit
,
533 const char *filename
,
536 unsigned section_line
,
552 r
= parse_size(rvalue
, 1024, &v
);
553 if (r
< 0 || (uint64_t) (size_t) v
!= v
) {
554 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse size value, ignoring: %s", rvalue
);
562 int config_parse_si_size(
564 const char *filename
,
567 unsigned section_line
,
583 r
= parse_size(rvalue
, 1000, &v
);
584 if (r
< 0 || (uint64_t) (size_t) v
!= v
) {
585 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse size value, ignoring: %s", rvalue
);
593 int config_parse_iec_uint64(
595 const char *filename
,
598 unsigned section_line
,
605 uint64_t *bytes
= data
;
613 r
= parse_size(rvalue
, 1024, bytes
);
615 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse size value, ignoring: %s", rvalue
);
620 int config_parse_bool(const char* unit
,
621 const char *filename
,
624 unsigned section_line
,
640 k
= parse_boolean(rvalue
);
642 log_syntax(unit
, LOG_ERR
, filename
, line
, k
,
643 "Failed to parse boolean value%s: %s",
644 fatal
? "" : ", ignoring", rvalue
);
645 return fatal
? -ENOEXEC
: 0;
652 int config_parse_tristate(
654 const char *filename
,
657 unsigned section_line
,
671 /* A tristate is pretty much a boolean, except that it can
672 * also take the special value -1, indicating "uninitialized",
673 * much like NULL is for a pointer type. */
675 k
= parse_boolean(rvalue
);
677 log_syntax(unit
, LOG_ERR
, filename
, line
, k
, "Failed to parse boolean value, ignoring: %s", rvalue
);
685 int config_parse_string(
687 const char *filename
,
690 unsigned section_line
,
704 if (!utf8_is_valid(rvalue
)) {
705 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
723 int config_parse_path(
725 const char *filename
,
728 unsigned section_line
,
743 if (isempty(rvalue
)) {
748 if (!utf8_is_valid(rvalue
)) {
749 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
750 return fatal
? -ENOEXEC
: 0;
753 if (!path_is_absolute(rvalue
)) {
754 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
755 "Not an absolute path%s: %s",
756 fatal
? "" : ", ignoring", rvalue
);
757 return fatal
? -ENOEXEC
: 0;
764 path_kill_slashes(n
);
773 int config_parse_strv(
775 const char *filename
,
778 unsigned section_line
,
793 if (isempty(rvalue
)) {
794 *sv
= strv_free(*sv
);
801 r
= extract_first_word(&rvalue
, &word
, NULL
, EXTRACT_QUOTES
|EXTRACT_RETAIN_ESCAPE
);
807 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid syntax, ignoring: %s", rvalue
);
811 if (!utf8_is_valid(word
)) {
812 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, word
);
817 r
= strv_consume(sv
, word
);
825 int config_parse_warn_compat(
827 const char *filename
,
830 unsigned section_line
,
836 Disabled reason
= ltype
;
839 case DISABLED_CONFIGURATION
:
840 log_syntax(unit
, LOG_DEBUG
, filename
, line
, 0,
841 "Support for option %s= has been disabled at compile time and it is ignored", lvalue
);
843 case DISABLED_LEGACY
:
844 log_syntax(unit
, LOG_INFO
, filename
, line
, 0,
845 "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_ERR
, 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_ERR
, 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_try_harder(rvalue
);
940 log_syntax(unit
, LOG_ERR
, 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_ERR
, 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_ERR
, 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_ip_port(
1020 const char *filename
,
1022 const char *section
,
1023 unsigned section_line
,
1039 if (isempty(rvalue
)) {
1044 r
= parse_ip_port(rvalue
, &port
);
1046 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse port '%s'.", rvalue
);
1055 int config_parse_join_controllers(
1057 const char *filename
,
1059 const char *section
,
1060 unsigned section_line
,
1067 char ****ret
= data
;
1068 const char *whole_rvalue
= rvalue
;
1070 _cleanup_(strv_free_freep
) char ***controllers
= NULL
;
1078 _cleanup_free_
char *word
= NULL
;
1082 r
= extract_first_word(&rvalue
, &word
, NULL
, EXTRACT_QUOTES
);
1084 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid value for %s: %s", lvalue
, whole_rvalue
);
1090 l
= strv_split(word
, ",");
1095 if (strv_length(l
) <= 1) {
1101 controllers
= new(char**, 2);
1108 controllers
[1] = NULL
;
1115 t
= new0(char**, n
+2);
1123 for (a
= controllers
; *a
; a
++)
1124 if (strv_overlap(*a
, l
)) {
1125 if (strv_extend_strv(&l
, *a
, false) < 0) {
1144 t
[n
++] = strv_uniq(l
);
1146 strv_free_free(controllers
);
1150 if (!isempty(rvalue
))
1151 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
1153 /* As a special case, return a single empty strv, to override the default */
1155 controllers
= new(char**, 2);
1158 controllers
[0] = strv_new(NULL
, NULL
);
1159 if (!controllers
[0])
1161 controllers
[1] = NULL
;
1164 strv_free_free(*ret
);