1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2010 Lennart Poettering
14 #include <sys/types.h>
16 #include "alloc-util.h"
17 #include "conf-files.h"
18 #include "conf-parser.h"
20 #include "extract-word.h"
26 #include "parse-util.h"
27 #include "path-util.h"
28 #include "process-util.h"
29 #include "signal-util.h"
30 #include "socket-util.h"
31 #include "string-util.h"
33 #include "syslog-util.h"
34 #include "time-util.h"
37 /// Additional includes needed by elogind
40 //#include "rlimit-util.h"
41 //#include "rlimit-util.h"
43 int config_item_table_lookup(
47 ConfigParserCallback *func,
52 const ConfigTableItem *t;
60 for (t = table; t->lvalue; t++) {
62 if (!streq(lvalue, t->lvalue))
65 if (!streq_ptr(section, t->section))
77 int config_item_perf_lookup(
81 ConfigParserCallback *func,
86 ConfigPerfItemLookup lookup = (ConfigPerfItemLookup) table;
87 const ConfigPerfItem *p;
96 p = lookup(lvalue, strlen(lvalue));
100 key = strjoin(section, ".", lvalue);
104 p = lookup(key, strlen(key));
113 *data = (uint8_t*) userdata + p->offset;
117 /* Run the user supplied parser for an assignment */
118 static int next_assignment(
120 const char *filename,
122 ConfigItemLookup lookup,
125 unsigned section_line,
128 ConfigParseFlags flags,
131 ConfigParserCallback func = NULL;
142 r = lookup(table, section, lvalue, &func, <ype, &data, userdata);
148 return func(unit, filename, line, section, section_line,
149 lvalue, ltype, rvalue, data, userdata);
154 /* Warn about unknown non-extension fields. */
155 if (!(flags & CONFIG_PARSE_RELAXED) && !startswith(lvalue, "X-"))
156 log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown lvalue '%s' in section '%s'", lvalue, section);
161 /* Parse a single logical line */
162 static int parse_line(
164 const char *filename,
166 const char *sections,
167 ConfigItemLookup lookup,
169 ConfigParseFlags flags,
171 unsigned *section_line,
172 bool *section_ignored,
187 if (strchr(COMMENTS "\n", *l))
190 include = first_word(l, ".include");
192 _cleanup_free_ char *fn = NULL;
194 /* .includes are a bad idea, we only support them here
195 * for historical reasons. They create cyclic include
196 * problems and make it difficult to detect
197 * configuration file changes with an easy
198 * stat(). Better approaches, such as .d/ drop-in
201 * Support for them should be eventually removed. */
203 if (!(flags & CONFIG_PARSE_ALLOW_INCLUDE)) {
204 log_syntax(unit, LOG_ERR, filename, line, 0, ".include not allowed here. Ignoring.");
208 log_syntax(unit, LOG_WARNING, filename, line, 0,
209 ".include directives are deprecated, and support for them will be removed in a future version of elogind. "
210 "Please use drop-in files instead.");
212 fn = file_in_same_dir(filename, strstrip(include));
216 return config_parse(unit, fn, NULL, sections, lookup, table, flags, userdata);
227 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid section header '%s'", l);
231 n = strndup(l+1, k-2);
235 if (sections && !nulstr_contains(sections, n)) {
237 if (!(flags & CONFIG_PARSE_RELAXED) && !startswith(n, "X-"))
238 log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown section '%s'. Ignoring.", n);
241 *section = mfree(*section);
243 *section_ignored = true;
247 *section_line = line;
248 *section_ignored = false;
254 if (sections && !*section) {
256 if (!(flags & CONFIG_PARSE_RELAXED) && !*section_ignored)
257 log_syntax(unit, LOG_WARNING, filename, line, 0, "Assignment outside of section. Ignoring.");
264 log_syntax(unit, LOG_WARNING, filename, line, 0, "Missing '='.");
271 return next_assignment(unit,
284 /* Go through the file and parse each line */
285 int config_parse(const char *unit,
286 const char *filename,
288 const char *sections,
289 ConfigItemLookup lookup,
291 ConfigParseFlags flags,
294 _cleanup_free_ char *section = NULL, *continuation = NULL;
295 _cleanup_fclose_ FILE *ours = NULL;
296 unsigned line = 0, section_line = 0;
297 bool section_ignored = false;
304 f = ours = fopen(filename, "re");
306 /* Only log on request, except for ENOENT,
307 * since we return 0 to the caller. */
308 if ((flags & CONFIG_PARSE_WARN) || errno == ENOENT)
309 log_full(errno == ENOENT ? LOG_DEBUG : LOG_ERR,
310 "Failed to open configuration file '%s': %m", filename);
311 return errno == ENOENT ? 0 : -errno;
315 fd_warn_permissions(filename, fileno(f));
318 _cleanup_free_ char *buf = NULL;
319 bool escaped = false;
322 r = read_line(f, LONG_LINE_MAX, &buf);
326 if (flags & CONFIG_PARSE_WARN)
327 log_error_errno(r, "%s:%u: Line too long", filename, line);
332 if (CONFIG_PARSE_WARN)
333 log_error_errno(r, "%s:%u: Error while reading configuration file: %m", filename, line);
339 if (!(flags & CONFIG_PARSE_REFUSE_BOM)) {
342 q = startswith(buf, UTF8_BYTE_ORDER_MARK);
345 flags |= CONFIG_PARSE_REFUSE_BOM;
350 if (strlen(continuation) + strlen(l) > LONG_LINE_MAX) {
351 if (flags & CONFIG_PARSE_WARN)
352 log_error("%s:%u: Continuation line too long", filename, line);
356 if (!strextend(&continuation, l, NULL)) {
357 if (flags & CONFIG_PARSE_WARN)
366 for (e = p; *e; e++) {
377 continuation = strdup(l);
379 if (flags & CONFIG_PARSE_WARN)
401 if (flags & CONFIG_PARSE_WARN)
402 log_warning_errno(r, "%s:%u: Failed to parse file: %m", filename, line);
407 continuation = mfree(continuation);
424 if (flags & CONFIG_PARSE_WARN)
425 log_warning_errno(r, "%s:%u: Failed to parse file: %m", filename, line);
434 static int config_parse_many_files(
435 const char *conf_file,
437 const char *sections,
438 ConfigItemLookup lookup,
440 ConfigParseFlags flags,
447 r = config_parse(NULL, conf_file, NULL, sections, lookup, table, flags, userdata);
452 STRV_FOREACH(fn, files) {
453 r = config_parse(NULL, *fn, NULL, sections, lookup, table, flags, userdata);
461 /* Parse each config file in the directories specified as nulstr. */
462 int config_parse_many_nulstr(
463 const char *conf_file,
464 const char *conf_file_dirs,
465 const char *sections,
466 ConfigItemLookup lookup,
468 ConfigParseFlags flags,
471 _cleanup_strv_free_ char **files = NULL;
474 r = conf_files_list_nulstr(&files, ".conf", NULL, 0, conf_file_dirs);
478 return config_parse_many_files(conf_file, files, sections, lookup, table, flags, userdata);
481 #if 0 /// UNNEEDED by elogind
482 /* Parse each config file in the directories specified as strv. */
483 int config_parse_many(
484 const char *conf_file,
485 const char* const* conf_file_dirs,
486 const char *dropin_dirname,
487 const char *sections,
488 ConfigItemLookup lookup,
490 ConfigParseFlags flags,
493 _cleanup_strv_free_ char **dropin_dirs = NULL;
494 _cleanup_strv_free_ char **files = NULL;
498 suffix = strjoina("/", dropin_dirname);
499 r = strv_extend_strv_concat(&dropin_dirs, (char**) conf_file_dirs, suffix);
503 r = conf_files_list_strv(&files, ".conf", NULL, 0, (const char* const*) dropin_dirs);
507 return config_parse_many_files(conf_file, files, sections, lookup, table, flags, userdata);
511 #define DEFINE_PARSER(type, vartype, conv_func) \
512 int config_parse_##type( \
514 const char *filename, \
516 const char *section, \
517 unsigned section_line, \
518 const char *lvalue, \
520 const char *rvalue, \
532 r = conv_func(rvalue, i); \
534 log_syntax(unit, LOG_ERR, filename, line, r, \
535 "Failed to parse %s value, ignoring: %s", \
541 DEFINE_PARSER(int, int, safe_atoi);
542 DEFINE_PARSER(long, long, safe_atoli);
543 #if 0 /// UNNEEDED by elogind
544 DEFINE_PARSER(uint8, uint8_t, safe_atou8);
545 DEFINE_PARSER(uint16, uint16_t, safe_atou16);
546 DEFINE_PARSER(uint32, uint32_t, safe_atou32);
548 DEFINE_PARSER(uint64, uint64_t, safe_atou64);
549 DEFINE_PARSER(unsigned, unsigned, safe_atou);
550 DEFINE_PARSER(double, double, safe_atod);
551 #if 0 /// UNNEEDED by elogind
552 DEFINE_PARSER(nsec, nsec_t, parse_nsec);
554 DEFINE_PARSER(sec, usec_t, parse_sec);
555 DEFINE_PARSER(mode, mode_t, parse_mode);
557 int config_parse_iec_size(const char* unit,
558 const char *filename,
561 unsigned section_line,
577 r = parse_size(rvalue, 1024, &v);
578 if (r < 0 || (uint64_t) (size_t) v != v) {
579 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue);
587 #if 0 /// UNNEEDED by elogind
588 int config_parse_si_size(
590 const char *filename,
593 unsigned section_line,
609 r = parse_size(rvalue, 1000, &v);
610 if (r < 0 || (uint64_t) (size_t) v != v) {
611 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue);
619 int config_parse_iec_uint64(
621 const char *filename,
624 unsigned section_line,
631 uint64_t *bytes = data;
639 r = parse_size(rvalue, 1024, bytes);
641 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue);
647 int config_parse_bool(const char* unit,
648 const char *filename,
651 unsigned section_line,
667 k = parse_boolean(rvalue);
669 log_syntax(unit, LOG_ERR, filename, line, k,
670 "Failed to parse boolean value%s: %s",
671 fatal ? "" : ", ignoring", rvalue);
672 return fatal ? -ENOEXEC : 0;
679 #if 0 /// UNNEEDED by elogind
680 int config_parse_tristate(
682 const char *filename,
685 unsigned section_line,
699 /* A tristate is pretty much a boolean, except that it can
700 * also take the special value -1, indicating "uninitialized",
701 * much like NULL is for a pointer type. */
703 k = parse_boolean(rvalue);
705 log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse boolean value, ignoring: %s", rvalue);
714 int config_parse_string(
716 const char *filename,
719 unsigned section_line,
733 if (!utf8_is_valid(rvalue)) {
734 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
738 if (free_and_strdup(s, empty_to_null(rvalue)) < 0)
744 int config_parse_path(
746 const char *filename,
749 unsigned section_line,
764 if (isempty(rvalue)) {
769 if (!utf8_is_valid(rvalue)) {
770 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
771 return fatal ? -ENOEXEC : 0;
774 if (!path_is_absolute(rvalue)) {
775 log_syntax(unit, LOG_ERR, filename, line, 0,
776 "Not an absolute path%s: %s",
777 fatal ? "" : ", ignoring", rvalue);
778 return fatal ? -ENOEXEC : 0;
785 path_kill_slashes(n);
794 int config_parse_strv(
796 const char *filename,
799 unsigned section_line,
814 if (isempty(rvalue)) {
815 *sv = strv_free(*sv);
822 r = extract_first_word(&rvalue, &word, NULL, EXTRACT_QUOTES|EXTRACT_RETAIN_ESCAPE);
828 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
832 if (!utf8_is_valid(word)) {
833 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, word);
838 r = strv_consume(sv, word);
846 int config_parse_warn_compat(
848 const char *filename,
851 unsigned section_line,
857 Disabled reason = ltype;
860 case DISABLED_CONFIGURATION:
861 log_syntax(unit, LOG_DEBUG, filename, line, 0,
862 "Support for option %s= has been disabled at compile time and it is ignored", lvalue);
864 case DISABLED_LEGACY:
865 log_syntax(unit, LOG_INFO, filename, line, 0,
866 "Support for option %s= has been removed and it is ignored", lvalue);
868 case DISABLED_EXPERIMENTAL:
869 log_syntax(unit, LOG_INFO, filename, line, 0,
870 "Support for option %s= has not yet been enabled and it is ignored", lvalue);
877 #if 0 /// UNNEEDED by elogind
878 int config_parse_log_facility(
880 const char *filename,
883 unsigned section_line,
897 x = log_facility_unshifted_from_string(rvalue);
899 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse log facility, ignoring: %s", rvalue);
903 *o = (x << 3) | LOG_PRI(*o);
909 int config_parse_log_level(
911 const char *filename,
914 unsigned section_line,
928 x = log_level_from_string(rvalue);
930 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse log level, ignoring: %s", rvalue);
934 if (*o < 0) /* if it wasn't initialized so far, assume zero facility */
937 *o = (*o & LOG_FACMASK) | x;
942 int config_parse_signal(
944 const char *filename,
947 unsigned section_line,
961 r = signal_from_string(rvalue);
963 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse signal name, ignoring: %s", rvalue);
971 #if 0 /// UNNEEDED by elogind
972 int config_parse_personality(
974 const char *filename,
977 unsigned section_line,
984 unsigned long *personality = data, p;
992 p = PERSONALITY_INVALID;
994 p = personality_from_string(rvalue);
995 if (p == PERSONALITY_INVALID) {
996 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse personality, ignoring: %s", rvalue);
1005 int config_parse_ifname(
1007 const char *filename,
1009 const char *section,
1010 unsigned section_line,
1025 if (isempty(rvalue)) {
1030 if (!ifname_valid(rvalue)) {
1031 log_syntax(unit, LOG_ERR, filename, line, 0, "Interface name is not valid or too long, ignoring assignment: %s", rvalue);
1035 r = free_and_strdup(s, rvalue);
1042 int config_parse_ip_port(
1044 const char *filename,
1046 const char *section,
1047 unsigned section_line,
1063 if (isempty(rvalue)) {
1068 r = parse_ip_port(rvalue, &port);
1070 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse port '%s'.", rvalue);
1079 int config_parse_join_controllers(
1081 const char *filename,
1083 const char *section,
1084 unsigned section_line,
1091 char ****ret = data;
1092 const char *whole_rvalue = rvalue;
1094 _cleanup_(strv_free_freep) char ***controllers = NULL;
1102 _cleanup_free_ char *word = NULL;
1106 r = extract_first_word(&rvalue, &word, NULL, EXTRACT_QUOTES);
1108 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid value for %s: %s", lvalue, whole_rvalue);
1114 l = strv_split(word, ",");
1119 if (strv_length(l) <= 1) {
1125 controllers = new(char**, 2);
1132 controllers[1] = NULL;
1139 t = new0(char**, n+2);
1147 for (a = controllers; *a; a++)
1148 if (strv_overlap(*a, l)) {
1149 if (strv_extend_strv(&l, *a, false) < 0) {
1168 t[n++] = strv_uniq(l);
1170 strv_free_free(controllers);
1174 if (!isempty(rvalue))
1175 log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
1177 /* As a special case, return a single empty strv, to override the default */
1179 controllers = new(char**, 2);
1182 controllers[0] = strv_new(NULL, NULL);
1183 if (!controllers[0])
1185 controllers[1] = NULL;
1188 strv_free_free(*ret);
1189 *ret = TAKE_PTR(controllers);
1195 int config_parse_mtu(
1197 const char *filename,
1199 const char *section,
1200 unsigned section_line,
1207 uint32_t *mtu = data;
1213 r = parse_mtu(ltype, rvalue, mtu);
1215 log_syntax(unit, LOG_ERR, filename, line, r,
1216 "Maximum transfer unit (MTU) value out of range. Permitted range is %" PRIu32 "…%" PRIu32 ", ignoring: %s",
1217 (uint32_t) (ltype == AF_INET6 ? IPV6_MIN_MTU : IPV4_MIN_MTU), (uint32_t) UINT32_MAX,
1222 log_syntax(unit, LOG_ERR, filename, line, r,
1223 "Failed to parse MTU value '%s', ignoring: %m", rvalue);
1230 int config_parse_rlimit(
1232 const char *filename,
1234 const char *section,
1235 unsigned section_line,
1242 struct rlimit **rl = data, d = {};
1248 r = rlimit_parse(ltype, rvalue, &d);
1250 log_syntax(unit, LOG_WARNING, filename, line, r, "Soft resource limit chosen higher than hard limit, ignoring: %s", rvalue);
1254 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue);
1261 rl[ltype] = newdup(struct rlimit, &d, 1);