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 single logical 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 include
= first_word(l
, ".include");
199 _cleanup_free_
char *fn
= NULL
;
201 /* .includes are a bad idea, we only support them here
202 * for historical reasons. They create cyclic include
203 * problems and make it difficult to detect
204 * configuration file changes with an easy
205 * stat(). Better approaches, such as .d/ drop-in
208 * Support for them should be eventually removed. */
210 if (!(flags
& CONFIG_PARSE_ALLOW_INCLUDE
)) {
211 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, ".include not allowed here. Ignoring.");
215 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
216 ".include directives are deprecated, and support for them will be removed in a future version of systemd. "
217 "Please use drop-in files instead.");
219 fn
= file_in_same_dir(filename
, strstrip(include
));
223 return config_parse(unit
, fn
, NULL
, sections
, lookup
, table
, flags
, userdata
);
234 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid section header '%s'", l
);
238 n
= strndup(l
+1, k
-2);
242 if (sections
&& !nulstr_contains(sections
, n
)) {
244 if (!(flags
& CONFIG_PARSE_RELAXED
) && !startswith(n
, "X-"))
245 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Unknown section '%s'. Ignoring.", n
);
248 *section
= mfree(*section
);
250 *section_ignored
= true;
254 *section_line
= line
;
255 *section_ignored
= false;
261 if (sections
&& !*section
) {
263 if (!(flags
& CONFIG_PARSE_RELAXED
) && !*section_ignored
)
264 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Assignment outside of section. Ignoring.");
271 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Missing '='.");
278 return next_assignment(unit
,
291 /* Go through the file and parse each line */
292 int config_parse(const char *unit
,
293 const char *filename
,
295 const char *sections
,
296 ConfigItemLookup lookup
,
298 ConfigParseFlags flags
,
301 _cleanup_free_
char *section
= NULL
, *continuation
= NULL
;
302 _cleanup_fclose_
FILE *ours
= NULL
;
303 unsigned line
= 0, section_line
= 0;
304 bool section_ignored
= false;
311 f
= ours
= fopen(filename
, "re");
313 /* Only log on request, except for ENOENT,
314 * since we return 0 to the caller. */
315 if ((flags
& CONFIG_PARSE_WARN
) || errno
== ENOENT
)
316 log_full(errno
== ENOENT
? LOG_DEBUG
: LOG_ERR
,
317 "Failed to open configuration file '%s': %m", filename
);
318 return errno
== ENOENT
? 0 : -errno
;
322 fd_warn_permissions(filename
, fileno(f
));
325 _cleanup_free_
char *buf
= NULL
;
326 bool escaped
= false;
329 r
= read_line(f
, LONG_LINE_MAX
, &buf
);
333 if (flags
& CONFIG_PARSE_WARN
)
334 log_error_errno(r
, "%s:%u: Line too long", filename
, line
);
339 if (CONFIG_PARSE_WARN
)
340 log_error_errno(r
, "%s:%u: Error while reading configuration file: %m", filename
, line
);
346 if (!(flags
& CONFIG_PARSE_REFUSE_BOM
)) {
349 q
= startswith(buf
, UTF8_BYTE_ORDER_MARK
);
352 flags
|= CONFIG_PARSE_REFUSE_BOM
;
357 if (strlen(continuation
) + strlen(l
) > LONG_LINE_MAX
) {
358 if (flags
& CONFIG_PARSE_WARN
)
359 log_error("%s:%u: Continuation line too long", filename
, line
);
363 if (!strextend(&continuation
, l
, NULL
)) {
364 if (flags
& CONFIG_PARSE_WARN
)
373 for (e
= p
; *e
; e
++) {
384 continuation
= strdup(l
);
386 if (flags
& CONFIG_PARSE_WARN
)
408 if (flags
& CONFIG_PARSE_WARN
)
409 log_warning_errno(r
, "%s:%u: Failed to parse file: %m", filename
, line
);
414 continuation
= mfree(continuation
);
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 int config_parse_##type( \
498 const char *filename, \
500 const char *section, \
501 unsigned section_line, \
502 const char *lvalue, \
504 const char *rvalue, \
516 r = conv_func(rvalue, i); \
518 log_syntax(unit, LOG_ERR, filename, line, r, \
519 "Failed to parse %s value, ignoring: %s", \
525 DEFINE_PARSER(int, int, safe_atoi
);
526 DEFINE_PARSER(long, long, safe_atoli
);
527 DEFINE_PARSER(uint8
, uint8_t, safe_atou8
);
528 DEFINE_PARSER(uint16
, uint16_t, safe_atou16
);
529 DEFINE_PARSER(uint32
, uint32_t, safe_atou32
);
530 DEFINE_PARSER(uint64
, uint64_t, safe_atou64
);
531 DEFINE_PARSER(unsigned, unsigned, safe_atou
);
532 DEFINE_PARSER(double, double, safe_atod
);
533 DEFINE_PARSER(nsec
, nsec_t
, parse_nsec
);
534 DEFINE_PARSER(sec
, usec_t
, parse_sec
);
535 DEFINE_PARSER(mode
, mode_t
, parse_mode
);
537 int config_parse_iec_size(const char* unit
,
538 const char *filename
,
541 unsigned section_line
,
557 r
= parse_size(rvalue
, 1024, &v
);
558 if (r
< 0 || (uint64_t) (size_t) v
!= v
) {
559 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse size value, ignoring: %s", rvalue
);
567 int config_parse_si_size(
569 const char *filename
,
572 unsigned section_line
,
588 r
= parse_size(rvalue
, 1000, &v
);
589 if (r
< 0 || (uint64_t) (size_t) v
!= v
) {
590 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse size value, ignoring: %s", rvalue
);
598 int config_parse_iec_uint64(
600 const char *filename
,
603 unsigned section_line
,
610 uint64_t *bytes
= data
;
618 r
= parse_size(rvalue
, 1024, bytes
);
620 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse size value, ignoring: %s", rvalue
);
625 int config_parse_bool(const char* unit
,
626 const char *filename
,
629 unsigned section_line
,
645 k
= parse_boolean(rvalue
);
647 log_syntax(unit
, LOG_ERR
, filename
, line
, k
,
648 "Failed to parse boolean value%s: %s",
649 fatal
? "" : ", ignoring", rvalue
);
650 return fatal
? -ENOEXEC
: 0;
657 int config_parse_tristate(
659 const char *filename
,
662 unsigned section_line
,
676 /* A tristate is pretty much a boolean, except that it can
677 * also take the special value -1, indicating "uninitialized",
678 * much like NULL is for a pointer type. */
680 k
= parse_boolean(rvalue
);
682 log_syntax(unit
, LOG_ERR
, filename
, line
, k
, "Failed to parse boolean value, ignoring: %s", rvalue
);
690 int config_parse_string(
692 const char *filename
,
695 unsigned section_line
,
709 if (!utf8_is_valid(rvalue
)) {
710 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
728 int config_parse_path(
730 const char *filename
,
733 unsigned section_line
,
748 if (isempty(rvalue
)) {
753 if (!utf8_is_valid(rvalue
)) {
754 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
755 return fatal
? -ENOEXEC
: 0;
758 if (!path_is_absolute(rvalue
)) {
759 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
760 "Not an absolute path%s: %s",
761 fatal
? "" : ", ignoring", rvalue
);
762 return fatal
? -ENOEXEC
: 0;
769 path_kill_slashes(n
);
778 int config_parse_strv(
780 const char *filename
,
783 unsigned section_line
,
798 if (isempty(rvalue
)) {
799 *sv
= strv_free(*sv
);
806 r
= extract_first_word(&rvalue
, &word
, NULL
, EXTRACT_QUOTES
|EXTRACT_RETAIN_ESCAPE
);
812 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid syntax, ignoring: %s", rvalue
);
816 if (!utf8_is_valid(word
)) {
817 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, word
);
822 r
= strv_consume(sv
, word
);
830 int config_parse_warn_compat(
832 const char *filename
,
835 unsigned section_line
,
841 Disabled reason
= ltype
;
844 case DISABLED_CONFIGURATION
:
845 log_syntax(unit
, LOG_DEBUG
, filename
, line
, 0,
846 "Support for option %s= has been disabled at compile time and it is ignored", lvalue
);
848 case DISABLED_LEGACY
:
849 log_syntax(unit
, LOG_INFO
, filename
, line
, 0,
850 "Support for option %s= has been removed and it is ignored", lvalue
);
852 case DISABLED_EXPERIMENTAL
:
853 log_syntax(unit
, LOG_INFO
, filename
, line
, 0,
854 "Support for option %s= has not yet been enabled and it is ignored", lvalue
);
861 int config_parse_log_facility(
863 const char *filename
,
866 unsigned section_line
,
880 x
= log_facility_unshifted_from_string(rvalue
);
882 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse log facility, ignoring: %s", rvalue
);
886 *o
= (x
<< 3) | LOG_PRI(*o
);
891 int config_parse_log_level(
893 const char *filename
,
896 unsigned section_line
,
910 x
= log_level_from_string(rvalue
);
912 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse log level, ignoring: %s", rvalue
);
916 if (*o
< 0) /* if it wasn't initialized so far, assume zero facility */
919 *o
= (*o
& LOG_FACMASK
) | x
;
924 int config_parse_signal(
926 const char *filename
,
929 unsigned section_line
,
943 r
= signal_from_string_try_harder(rvalue
);
945 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse signal name, ignoring: %s", rvalue
);
953 int config_parse_personality(
955 const char *filename
,
958 unsigned section_line
,
965 unsigned long *personality
= data
, p
;
973 p
= PERSONALITY_INVALID
;
975 p
= personality_from_string(rvalue
);
976 if (p
== PERSONALITY_INVALID
) {
977 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse personality, ignoring: %s", rvalue
);
986 int config_parse_ifname(
988 const char *filename
,
991 unsigned section_line
,
1006 if (isempty(rvalue
)) {
1011 if (!ifname_valid(rvalue
)) {
1012 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Interface name is not valid or too long, ignoring assignment: %s", rvalue
);
1016 r
= free_and_strdup(s
, rvalue
);
1023 int config_parse_ip_port(
1025 const char *filename
,
1027 const char *section
,
1028 unsigned section_line
,
1044 if (isempty(rvalue
)) {
1049 r
= parse_ip_port(rvalue
, &port
);
1051 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse port '%s'.", rvalue
);
1060 int config_parse_join_controllers(
1062 const char *filename
,
1064 const char *section
,
1065 unsigned section_line
,
1072 char ****ret
= data
;
1073 const char *whole_rvalue
= rvalue
;
1075 _cleanup_(strv_free_freep
) char ***controllers
= NULL
;
1083 _cleanup_free_
char *word
= NULL
;
1087 r
= extract_first_word(&rvalue
, &word
, NULL
, EXTRACT_QUOTES
);
1089 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid value for %s: %s", lvalue
, whole_rvalue
);
1095 l
= strv_split(word
, ",");
1100 if (strv_length(l
) <= 1) {
1106 controllers
= new(char**, 2);
1113 controllers
[1] = NULL
;
1120 t
= new0(char**, n
+2);
1128 for (a
= controllers
; *a
; a
++)
1129 if (strv_overlap(*a
, l
)) {
1130 if (strv_extend_strv(&l
, *a
, false) < 0) {
1149 t
[n
++] = strv_uniq(l
);
1151 strv_free_free(controllers
);
1155 if (!isempty(rvalue
))
1156 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
1158 /* As a special case, return a single empty strv, to override the default */
1160 controllers
= new(char**, 2);
1163 controllers
[0] = strv_new(NULL
, NULL
);
1164 if (!controllers
[0])
1166 controllers
[1] = NULL
;
1169 strv_free_free(*ret
);