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 /// Additional includes needed by elogind
54 int config_item_table_lookup(
58 ConfigParserCallback *func,
63 const ConfigTableItem *t;
71 for (t = table; t->lvalue; t++) {
73 if (!streq(lvalue, t->lvalue))
76 if (!streq_ptr(section, t->section))
88 int config_item_perf_lookup(
92 ConfigParserCallback *func,
97 ConfigPerfItemLookup lookup = (ConfigPerfItemLookup) table;
98 const ConfigPerfItem *p;
107 p = lookup(lvalue, strlen(lvalue));
111 key = strjoin(section, ".", lvalue);
115 p = lookup(key, strlen(key));
124 *data = (uint8_t*) userdata + p->offset;
128 /* Run the user supplied parser for an assignment */
129 static int next_assignment(
131 const char *filename,
133 ConfigItemLookup lookup,
136 unsigned section_line,
139 ConfigParseFlags flags,
142 ConfigParserCallback func = NULL;
153 r = lookup(table, section, lvalue, &func, <ype, &data, userdata);
159 return func(unit, filename, line, section, section_line,
160 lvalue, ltype, rvalue, data, userdata);
165 /* Warn about unknown non-extension fields. */
166 if (!(flags & CONFIG_PARSE_RELAXED) && !startswith(lvalue, "X-"))
167 log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown lvalue '%s' in section '%s'", lvalue, section);
172 /* Parse a variable assignment line */
173 static int parse_line(
175 const char *filename,
177 const char *sections,
178 ConfigItemLookup lookup,
180 ConfigParseFlags flags,
182 unsigned *section_line,
183 bool *section_ignored,
198 if (strchr(COMMENTS "\n", *l))
201 if (startswith(l, ".include ")) {
202 _cleanup_free_ char *fn = NULL;
204 /* .includes are a bad idea, we only support them here
205 * for historical reasons. They create cyclic include
206 * problems and make it difficult to detect
207 * configuration file changes with an easy
208 * stat(). Better approaches, such as .d/ drop-in
211 * Support for them should be eventually removed. */
213 if (!(flags & CONFIG_PARSE_ALLOW_INCLUDE)) {
214 log_syntax(unit, LOG_ERR, filename, line, 0, ".include not allowed here. Ignoring.");
218 fn = file_in_same_dir(filename, strstrip(l+9));
222 return config_parse(unit, fn, NULL, sections, lookup, table, flags, userdata);
233 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid section header '%s'", l);
237 n = strndup(l+1, k-2);
241 if (sections && !nulstr_contains(sections, n)) {
243 if (!(flags & CONFIG_PARSE_RELAXED) && !startswith(n, "X-"))
244 log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown section '%s'. Ignoring.", n);
247 *section = mfree(*section);
249 *section_ignored = true;
253 *section_line = line;
254 *section_ignored = false;
260 if (sections && !*section) {
262 if (!(flags & CONFIG_PARSE_RELAXED) && !*section_ignored)
263 log_syntax(unit, LOG_WARNING, filename, line, 0, "Assignment outside of section. Ignoring.");
270 log_syntax(unit, LOG_WARNING, filename, line, 0, "Missing '='.");
277 return next_assignment(unit,
290 /* Go through the file and parse each line */
291 int config_parse(const char *unit,
292 const char *filename,
294 const char *sections,
295 ConfigItemLookup lookup,
297 ConfigParseFlags flags,
300 _cleanup_free_ char *section = NULL, *continuation = NULL;
301 _cleanup_fclose_ FILE *ours = NULL;
302 unsigned line = 0, section_line = 0;
303 bool section_ignored = false;
310 f = ours = fopen(filename, "re");
312 /* Only log on request, except for ENOENT,
313 * since we return 0 to the caller. */
314 if ((flags & CONFIG_PARSE_WARN) || errno == ENOENT)
315 log_full(errno == ENOENT ? LOG_DEBUG : LOG_ERR,
316 "Failed to open configuration file '%s': %m", filename);
317 return errno == ENOENT ? 0 : -errno;
321 fd_warn_permissions(filename, fileno(f));
324 _cleanup_free_ char *buf = NULL;
325 bool escaped = false;
328 r = read_line(f, LONG_LINE_MAX, &buf);
332 if (flags & CONFIG_PARSE_WARN)
333 log_error_errno(r, "%s:%u: Line too long", filename, line);
338 if (CONFIG_PARSE_WARN)
339 log_error_errno(r, "%s:%u: Error while reading configuration file: %m", filename, line);
345 if (!(flags & CONFIG_PARSE_REFUSE_BOM)) {
348 q = startswith(buf, UTF8_BYTE_ORDER_MARK);
351 flags |= CONFIG_PARSE_REFUSE_BOM;
356 if (strlen(continuation) + strlen(l) > LONG_LINE_MAX) {
357 if (flags & CONFIG_PARSE_WARN)
358 log_error("%s:%u: Continuation line too long", filename, line);
362 if (!strextend(&continuation, l, NULL)) {
363 if (flags & CONFIG_PARSE_WARN)
372 for (e = p; *e; e++) {
383 continuation = strdup(l);
385 if (flags & CONFIG_PARSE_WARN)
407 if (flags & CONFIG_PARSE_WARN)
408 log_warning_errno(r, "%s:%u: Failed to parse file: %m", filename, line);
413 continuation = mfree(continuation);
419 static int config_parse_many_files(
420 const char *conf_file,
422 const char *sections,
423 ConfigItemLookup lookup,
425 ConfigParseFlags flags,
432 r = config_parse(NULL, conf_file, NULL, sections, lookup, table, flags, userdata);
437 STRV_FOREACH(fn, files) {
438 r = config_parse(NULL, *fn, NULL, sections, lookup, table, flags, userdata);
446 /* Parse each config file in the directories specified as nulstr. */
447 int config_parse_many_nulstr(
448 const char *conf_file,
449 const char *conf_file_dirs,
450 const char *sections,
451 ConfigItemLookup lookup,
453 ConfigParseFlags flags,
456 _cleanup_strv_free_ char **files = NULL;
459 r = conf_files_list_nulstr(&files, ".conf", NULL, 0, conf_file_dirs);
463 return config_parse_many_files(conf_file, files, sections, lookup, table, flags, userdata);
466 #if 0 /// UNNEEDED by elogind
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);
496 #define DEFINE_PARSER(type, vartype, conv_func) \
497 int config_parse_##type( \
499 const char *filename, \
501 const char *section, \
502 unsigned section_line, \
503 const char *lvalue, \
505 const char *rvalue, \
517 r = conv_func(rvalue, i); \
519 log_syntax(unit, LOG_ERR, filename, line, r, \
520 "Failed to parse %s value, ignoring: %s", \
525 struct __useless_struct_to_allow_trailing_semicolon__
527 DEFINE_PARSER(int, int, safe_atoi);
528 DEFINE_PARSER(long, long, safe_atoli);
529 #if 0 /// UNNEEDED by elogind
530 DEFINE_PARSER(uint8, uint8_t, safe_atou8);
531 DEFINE_PARSER(uint16, uint16_t, safe_atou16);
532 DEFINE_PARSER(uint32, uint32_t, safe_atou32);
534 DEFINE_PARSER(uint64, uint64_t, safe_atou64);
535 DEFINE_PARSER(unsigned, unsigned, safe_atou);
536 DEFINE_PARSER(double, double, safe_atod);
537 #if 0 /// UNNEEDED by elogind
538 DEFINE_PARSER(nsec, nsec_t, parse_nsec);
540 DEFINE_PARSER(sec, usec_t, parse_sec);
541 DEFINE_PARSER(mode, mode_t, parse_mode);
543 int config_parse_iec_size(const char* unit,
544 const char *filename,
547 unsigned section_line,
563 r = parse_size(rvalue, 1024, &v);
564 if (r < 0 || (uint64_t) (size_t) v != v) {
565 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue);
573 #if 0 /// UNNEEDED by elogind
574 int config_parse_si_size(
576 const char *filename,
579 unsigned section_line,
595 r = parse_size(rvalue, 1000, &v);
596 if (r < 0 || (uint64_t) (size_t) v != v) {
597 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue);
605 int config_parse_iec_uint64(
607 const char *filename,
610 unsigned section_line,
617 uint64_t *bytes = data;
625 r = parse_size(rvalue, 1024, bytes);
627 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 #if 0 /// UNNEEDED by elogind
666 int config_parse_tristate(
668 const char *filename,
671 unsigned section_line,
685 /* A tristate is pretty much a boolean, except that it can
686 * also take the special value -1, indicating "uninitialized",
687 * much like NULL is for a pointer type. */
689 k = parse_boolean(rvalue);
691 log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse boolean value, ignoring: %s", rvalue);
700 int config_parse_string(
702 const char *filename,
705 unsigned section_line,
719 if (!utf8_is_valid(rvalue)) {
720 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
738 int config_parse_path(
740 const char *filename,
743 unsigned section_line,
758 if (isempty(rvalue)) {
763 if (!utf8_is_valid(rvalue)) {
764 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
765 return fatal ? -ENOEXEC : 0;
768 if (!path_is_absolute(rvalue)) {
769 log_syntax(unit, LOG_ERR, filename, line, 0,
770 "Not an absolute path%s: %s",
771 fatal ? "" : ", ignoring", rvalue);
772 return fatal ? -ENOEXEC : 0;
779 path_kill_slashes(n);
788 int config_parse_strv(
790 const char *filename,
793 unsigned section_line,
808 if (isempty(rvalue)) {
809 *sv = strv_free(*sv);
816 r = extract_first_word(&rvalue, &word, NULL, EXTRACT_QUOTES|EXTRACT_RETAIN_ESCAPE);
822 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
826 if (!utf8_is_valid(word)) {
827 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, word);
832 r = strv_consume(sv, word);
840 #if 0 /// UNNEEDED by elogind
841 int config_parse_log_facility(
843 const char *filename,
846 unsigned section_line,
860 x = log_facility_unshifted_from_string(rvalue);
862 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse log facility, ignoring: %s", rvalue);
866 *o = (x << 3) | LOG_PRI(*o);
872 int config_parse_log_level(
874 const char *filename,
877 unsigned section_line,
891 x = log_level_from_string(rvalue);
893 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse log level, ignoring: %s", rvalue);
897 if (*o < 0) /* if it wasn't initialized so far, assume zero facility */
900 *o = (*o & LOG_FACMASK) | x;
905 int config_parse_signal(
907 const char *filename,
910 unsigned section_line,
924 r = signal_from_string_try_harder(rvalue);
926 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse signal name, ignoring: %s", rvalue);
934 #if 0 /// UNNEEDED by elogind
935 int config_parse_personality(
937 const char *filename,
940 unsigned section_line,
947 unsigned long *personality = data, p;
955 p = PERSONALITY_INVALID;
957 p = personality_from_string(rvalue);
958 if (p == PERSONALITY_INVALID) {
959 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse personality, ignoring: %s", rvalue);
968 int config_parse_ifname(
970 const char *filename,
973 unsigned section_line,
988 if (isempty(rvalue)) {
993 if (!ifname_valid(rvalue)) {
994 log_syntax(unit, LOG_ERR, filename, line, 0, "Interface name is not valid or too long, ignoring assignment: %s", rvalue);
998 r = free_and_strdup(s, rvalue);
1005 int config_parse_ip_port(
1007 const char *filename,
1009 const char *section,
1010 unsigned section_line,
1026 if (isempty(rvalue)) {
1031 r = parse_ip_port(rvalue, &port);
1033 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse port '%s'.", rvalue);