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", \
519 struct __useless_struct_to_allow_trailing_semicolon__
521 DEFINE_PARSER(int, int, safe_atoi
);
522 DEFINE_PARSER(long, long, safe_atoli
);
523 DEFINE_PARSER(uint8
, uint8_t, safe_atou8
);
524 DEFINE_PARSER(uint16
, uint16_t, safe_atou16
);
525 DEFINE_PARSER(uint32
, uint32_t, safe_atou32
);
526 DEFINE_PARSER(uint64
, uint64_t, safe_atou64
);
527 DEFINE_PARSER(unsigned, unsigned, safe_atou
);
528 DEFINE_PARSER(double, double, safe_atod
);
529 DEFINE_PARSER(nsec
, nsec_t
, parse_nsec
);
530 DEFINE_PARSER(sec
, usec_t
, parse_sec
);
531 DEFINE_PARSER(mode
, mode_t
, parse_mode
);
533 int config_parse_iec_size(const char* unit
,
534 const char *filename
,
537 unsigned section_line
,
553 r
= parse_size(rvalue
, 1024, &v
);
554 if (r
< 0 || (uint64_t) (size_t) v
!= v
) {
555 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse size value, ignoring: %s", rvalue
);
563 int config_parse_si_size(
565 const char *filename
,
568 unsigned section_line
,
584 r
= parse_size(rvalue
, 1000, &v
);
585 if (r
< 0 || (uint64_t) (size_t) v
!= v
) {
586 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse size value, ignoring: %s", rvalue
);
594 int config_parse_iec_uint64(
596 const char *filename
,
599 unsigned section_line
,
606 uint64_t *bytes
= data
;
614 r
= parse_size(rvalue
, 1024, bytes
);
616 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse size value, ignoring: %s", rvalue
);
621 int config_parse_bool(const char* unit
,
622 const char *filename
,
625 unsigned section_line
,
641 k
= parse_boolean(rvalue
);
643 log_syntax(unit
, LOG_ERR
, filename
, line
, k
,
644 "Failed to parse boolean value%s: %s",
645 fatal
? "" : ", ignoring", rvalue
);
646 return fatal
? -ENOEXEC
: 0;
653 int config_parse_tristate(
655 const char *filename
,
658 unsigned section_line
,
672 /* A tristate is pretty much a boolean, except that it can
673 * also take the special value -1, indicating "uninitialized",
674 * much like NULL is for a pointer type. */
676 k
= parse_boolean(rvalue
);
678 log_syntax(unit
, LOG_ERR
, filename
, line
, k
, "Failed to parse boolean value, ignoring: %s", rvalue
);
686 int config_parse_string(
688 const char *filename
,
691 unsigned section_line
,
705 if (!utf8_is_valid(rvalue
)) {
706 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
724 int config_parse_path(
726 const char *filename
,
729 unsigned section_line
,
744 if (isempty(rvalue
)) {
749 if (!utf8_is_valid(rvalue
)) {
750 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
751 return fatal
? -ENOEXEC
: 0;
754 if (!path_is_absolute(rvalue
)) {
755 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
756 "Not an absolute path%s: %s",
757 fatal
? "" : ", ignoring", rvalue
);
758 return fatal
? -ENOEXEC
: 0;
765 path_kill_slashes(n
);
774 int config_parse_strv(
776 const char *filename
,
779 unsigned section_line
,
794 if (isempty(rvalue
)) {
795 *sv
= strv_free(*sv
);
802 r
= extract_first_word(&rvalue
, &word
, NULL
, EXTRACT_QUOTES
|EXTRACT_RETAIN_ESCAPE
);
808 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid syntax, ignoring: %s", rvalue
);
812 if (!utf8_is_valid(word
)) {
813 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, word
);
818 r
= strv_consume(sv
, word
);
826 int config_parse_log_facility(
828 const char *filename
,
831 unsigned section_line
,
845 x
= log_facility_unshifted_from_string(rvalue
);
847 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse log facility, ignoring: %s", rvalue
);
851 *o
= (x
<< 3) | LOG_PRI(*o
);
856 int config_parse_log_level(
858 const char *filename
,
861 unsigned section_line
,
875 x
= log_level_from_string(rvalue
);
877 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse log level, ignoring: %s", rvalue
);
881 if (*o
< 0) /* if it wasn't initialized so far, assume zero facility */
884 *o
= (*o
& LOG_FACMASK
) | x
;
889 int config_parse_signal(
891 const char *filename
,
894 unsigned section_line
,
908 r
= signal_from_string_try_harder(rvalue
);
910 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse signal name, ignoring: %s", rvalue
);
918 int config_parse_personality(
920 const char *filename
,
923 unsigned section_line
,
930 unsigned long *personality
= data
, p
;
938 p
= PERSONALITY_INVALID
;
940 p
= personality_from_string(rvalue
);
941 if (p
== PERSONALITY_INVALID
) {
942 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse personality, ignoring: %s", rvalue
);
951 int config_parse_ifname(
953 const char *filename
,
956 unsigned section_line
,
971 if (isempty(rvalue
)) {
976 if (!ifname_valid(rvalue
)) {
977 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Interface name is not valid or too long, ignoring assignment: %s", rvalue
);
981 r
= free_and_strdup(s
, rvalue
);
988 int config_parse_ip_port(
990 const char *filename
,
993 unsigned section_line
,
1009 if (isempty(rvalue
)) {
1014 r
= parse_ip_port(rvalue
, &port
);
1016 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse port '%s'.", rvalue
);