1 /* SPDX-License-Identifier: LGPL-2.1+ */
11 #include "alloc-util.h"
12 #include "conf-files.h"
13 #include "conf-parser.h"
15 #include "extract-word.h"
21 #include "parse-util.h"
22 #include "path-util.h"
23 #include "process-util.h"
24 //#include "rlimit-util.h"
25 #include "signal-util.h"
26 #include "socket-util.h"
27 #include "string-util.h"
29 #include "syslog-util.h"
30 #include "time-util.h"
33 /// Additional includes needed by elogind
37 int config_item_table_lookup(
41 ConfigParserCallback *func,
46 const ConfigTableItem *t;
54 for (t = table; t->lvalue; t++) {
56 if (!streq(lvalue, t->lvalue))
59 if (!streq_ptr(section, t->section))
71 int config_item_perf_lookup(
75 ConfigParserCallback *func,
80 ConfigPerfItemLookup lookup = (ConfigPerfItemLookup) table;
81 const ConfigPerfItem *p;
90 p = lookup(lvalue, strlen(lvalue));
94 key = strjoin(section, ".", lvalue);
98 p = lookup(key, strlen(key));
107 *data = (uint8_t*) userdata + p->offset;
111 /* Run the user supplied parser for an assignment */
112 static int next_assignment(
114 const char *filename,
116 ConfigItemLookup lookup,
119 unsigned section_line,
122 ConfigParseFlags flags,
125 ConfigParserCallback func = NULL;
136 r = lookup(table, section, lvalue, &func, <ype, &data, userdata);
142 return func(unit, filename, line, section, section_line,
143 lvalue, ltype, rvalue, data, userdata);
148 /* Warn about unknown non-extension fields. */
149 if (!(flags & CONFIG_PARSE_RELAXED) && !startswith(lvalue, "X-"))
150 log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown lvalue '%s' in section '%s'", lvalue, section);
155 /* Parse a single logical line */
156 static int parse_line(
158 const char *filename,
160 const char *sections,
161 ConfigItemLookup lookup,
163 ConfigParseFlags flags,
165 unsigned *section_line,
166 bool *section_ignored,
181 if (strchr(COMMENTS "\n", *l))
184 include = first_word(l, ".include");
186 _cleanup_free_ char *fn = NULL;
188 /* .includes are a bad idea, we only support them here
189 * for historical reasons. They create cyclic include
190 * problems and make it difficult to detect
191 * configuration file changes with an easy
192 * stat(). Better approaches, such as .d/ drop-in
195 * Support for them should be eventually removed. */
197 if (!(flags & CONFIG_PARSE_ALLOW_INCLUDE)) {
198 log_syntax(unit, LOG_ERR, filename, line, 0, ".include not allowed here. Ignoring.");
202 log_syntax(unit, LOG_WARNING, filename, line, 0,
203 ".include directives are deprecated, and support for them will be removed in a future version of elogind. "
204 "Please use drop-in files instead.");
206 fn = file_in_same_dir(filename, strstrip(include));
210 return config_parse(unit, fn, NULL, sections, lookup, table, flags, userdata);
213 if (!utf8_is_valid(l))
214 return log_syntax_invalid_utf8(unit, LOG_WARNING, filename, line, l);
224 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid section header '%s'", l);
228 n = strndup(l+1, k-2);
232 if (sections && !nulstr_contains(sections, n)) {
234 if (!(flags & CONFIG_PARSE_RELAXED) && !startswith(n, "X-"))
235 log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown section '%s'. Ignoring.", n);
238 *section = mfree(*section);
240 *section_ignored = true;
242 free_and_replace(*section, n);
243 *section_line = line;
244 *section_ignored = false;
250 if (sections && !*section) {
252 if (!(flags & CONFIG_PARSE_RELAXED) && !*section_ignored)
253 log_syntax(unit, LOG_WARNING, filename, line, 0, "Assignment outside of section. Ignoring.");
260 log_syntax(unit, LOG_WARNING, filename, line, 0, "Missing '='.");
267 return next_assignment(unit,
280 /* Go through the file and parse each line */
281 int config_parse(const char *unit,
282 const char *filename,
284 const char *sections,
285 ConfigItemLookup lookup,
287 ConfigParseFlags flags,
290 _cleanup_free_ char *section = NULL, *continuation = NULL;
291 _cleanup_fclose_ FILE *ours = NULL;
292 unsigned line = 0, section_line = 0;
293 bool section_ignored = false;
300 f = ours = fopen(filename, "re");
302 /* Only log on request, except for ENOENT,
303 * since we return 0 to the caller. */
304 if ((flags & CONFIG_PARSE_WARN) || errno == ENOENT)
305 log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_ERR, errno,
306 "Failed to open configuration file '%s': %m", filename);
307 return errno == ENOENT ? 0 : -errno;
311 fd_warn_permissions(filename, fileno(f));
314 _cleanup_free_ char *buf = NULL;
315 bool escaped = false;
318 r = read_line(f, LONG_LINE_MAX, &buf);
322 if (flags & CONFIG_PARSE_WARN)
323 log_error_errno(r, "%s:%u: Line too long", filename, line);
328 if (CONFIG_PARSE_WARN)
329 log_error_errno(r, "%s:%u: Error while reading configuration file: %m", filename, line);
335 if (!(flags & CONFIG_PARSE_REFUSE_BOM)) {
338 q = startswith(buf, UTF8_BYTE_ORDER_MARK);
341 flags |= CONFIG_PARSE_REFUSE_BOM;
346 if (strlen(continuation) + strlen(l) > LONG_LINE_MAX) {
347 if (flags & CONFIG_PARSE_WARN)
348 log_error("%s:%u: Continuation line too long", filename, line);
352 if (!strextend(&continuation, l, NULL)) {
353 if (flags & CONFIG_PARSE_WARN)
362 for (e = p; *e; e++) {
373 continuation = strdup(l);
375 if (flags & CONFIG_PARSE_WARN)
397 if (flags & CONFIG_PARSE_WARN)
398 log_warning_errno(r, "%s:%u: Failed to parse file: %m", filename, line);
402 continuation = mfree(continuation);
419 if (flags & CONFIG_PARSE_WARN)
420 log_warning_errno(r, "%s:%u: Failed to parse file: %m", filename, line);
428 static int config_parse_many_files(
429 const char *conf_file,
431 const char *sections,
432 ConfigItemLookup lookup,
434 ConfigParseFlags flags,
441 r = config_parse(NULL, conf_file, NULL, sections, lookup, table, flags, userdata);
446 STRV_FOREACH(fn, files) {
447 r = config_parse(NULL, *fn, NULL, sections, lookup, table, flags, userdata);
455 /* Parse each config file in the directories specified as nulstr. */
456 int config_parse_many_nulstr(
457 const char *conf_file,
458 const char *conf_file_dirs,
459 const char *sections,
460 ConfigItemLookup lookup,
462 ConfigParseFlags flags,
465 _cleanup_strv_free_ char **files = NULL;
468 r = conf_files_list_nulstr(&files, ".conf", NULL, 0, conf_file_dirs);
472 return config_parse_many_files(conf_file, files, sections, lookup, table, flags, userdata);
475 #if 0 /// UNNEEDED by elogind
476 /* Parse each config file in the directories specified as strv. */
477 int config_parse_many(
478 const char *conf_file,
479 const char* const* conf_file_dirs,
480 const char *dropin_dirname,
481 const char *sections,
482 ConfigItemLookup lookup,
484 ConfigParseFlags flags,
487 _cleanup_strv_free_ char **dropin_dirs = NULL;
488 _cleanup_strv_free_ char **files = NULL;
492 suffix = strjoina("/", dropin_dirname);
493 r = strv_extend_strv_concat(&dropin_dirs, (char**) conf_file_dirs, suffix);
497 r = conf_files_list_strv(&files, ".conf", NULL, 0, (const char* const*) dropin_dirs);
501 return config_parse_many_files(conf_file, files, sections, lookup, table, flags, userdata);
505 #define DEFINE_PARSER(type, vartype, conv_func) \
506 DEFINE_CONFIG_PARSE_PTR(config_parse_##type, conv_func, vartype, "Failed to parse " #type " value")
508 DEFINE_PARSER(int, int, safe_atoi);
509 DEFINE_PARSER(long, long, safe_atoli);
510 #if 0 /// UNNEEDED by elogind
511 DEFINE_PARSER(uint8, uint8_t, safe_atou8);
512 DEFINE_PARSER(uint16, uint16_t, safe_atou16);
513 DEFINE_PARSER(uint32, uint32_t, safe_atou32);
515 DEFINE_PARSER(uint64, uint64_t, safe_atou64);
516 DEFINE_PARSER(unsigned, unsigned, safe_atou);
517 DEFINE_PARSER(double, double, safe_atod);
518 #if 0 /// UNNEEDED by elogind
519 DEFINE_PARSER(nsec, nsec_t, parse_nsec);
521 DEFINE_PARSER(sec, usec_t, parse_sec);
522 DEFINE_PARSER(mode, mode_t, parse_mode);
524 #if 0 /// UNNEEDED by elogind
525 int config_parse_iec_size(const char* unit,
526 const char *filename,
529 unsigned section_line,
545 r = parse_size(rvalue, 1024, &v);
546 if (r < 0 || (uint64_t) (size_t) v != v) {
547 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue);
555 int config_parse_si_size(
557 const char *filename,
560 unsigned section_line,
576 r = parse_size(rvalue, 1000, &v);
577 if (r < 0 || (uint64_t) (size_t) v != v) {
578 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue);
586 int config_parse_iec_uint64(
588 const char *filename,
591 unsigned section_line,
598 uint64_t *bytes = data;
606 r = parse_size(rvalue, 1024, bytes);
608 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue);
614 int config_parse_bool(const char* unit,
615 const char *filename,
618 unsigned section_line,
634 k = parse_boolean(rvalue);
636 log_syntax(unit, LOG_ERR, filename, line, k,
637 "Failed to parse boolean value%s: %s",
638 fatal ? "" : ", ignoring", rvalue);
639 return fatal ? -ENOEXEC : 0;
646 #if 0 /// UNNEEDED by elogind
647 int config_parse_tristate(
649 const char *filename,
652 unsigned section_line,
666 /* A tristate is pretty much a boolean, except that it can
667 * also take the special value -1, indicating "uninitialized",
668 * much like NULL is for a pointer type. */
670 k = parse_boolean(rvalue);
672 log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse boolean value, ignoring: %s", rvalue);
681 int config_parse_string(
683 const char *filename,
686 unsigned section_line,
700 if (free_and_strdup(s, empty_to_null(rvalue)) < 0)
706 #if 0 /// UNNEEDED by elogind
707 int config_parse_path(
709 const char *filename,
712 unsigned section_line,
719 _cleanup_free_ char *n = NULL;
736 r = path_simplify_and_warn(n, PATH_CHECK_ABSOLUTE | (fatal ? PATH_CHECK_FATAL : 0), unit, filename, line, lvalue);
738 return fatal ? -ENOEXEC : 0;
741 return free_and_replace(*s, n);
745 int config_parse_strv(
747 const char *filename,
750 unsigned section_line,
765 if (isempty(rvalue)) {
766 *sv = strv_free(*sv);
773 r = extract_first_word(&rvalue, &word, NULL, EXTRACT_QUOTES|EXTRACT_RETAIN_ESCAPE);
779 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
783 r = strv_consume(sv, word);
791 #if 0 /// UNNEEDED by elogind
792 int config_parse_warn_compat(
794 const char *filename,
797 unsigned section_line,
804 Disabled reason = ltype;
808 case DISABLED_CONFIGURATION:
809 log_syntax(unit, LOG_DEBUG, filename, line, 0,
810 "Support for option %s= has been disabled at compile time and it is ignored", lvalue);
813 case DISABLED_LEGACY:
814 log_syntax(unit, LOG_INFO, filename, line, 0,
815 "Support for option %s= has been removed and it is ignored", lvalue);
818 case DISABLED_EXPERIMENTAL:
819 log_syntax(unit, LOG_INFO, filename, line, 0,
820 "Support for option %s= has not yet been enabled and it is ignored", lvalue);
827 int config_parse_log_facility(
829 const char *filename,
832 unsigned section_line,
846 x = log_facility_unshifted_from_string(rvalue);
848 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse log facility, ignoring: %s", rvalue);
852 *o = (x << 3) | LOG_PRI(*o);
857 int config_parse_log_level(
859 const char *filename,
862 unsigned section_line,
876 x = log_level_from_string(rvalue);
878 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse log level, ignoring: %s", rvalue);
882 if (*o < 0) /* if it wasn't initialized so far, assume zero facility */
885 *o = (*o & LOG_FACMASK) | x;
890 int config_parse_signal(
892 const char *filename,
895 unsigned section_line,
909 r = signal_from_string(rvalue);
911 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse signal name, ignoring: %s", rvalue);
919 int config_parse_personality(
921 const char *filename,
924 unsigned section_line,
931 unsigned long *personality = data, p;
939 p = PERSONALITY_INVALID;
941 p = personality_from_string(rvalue);
942 if (p == PERSONALITY_INVALID) {
943 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse personality, ignoring: %s", rvalue);
952 int config_parse_ifname(
954 const char *filename,
957 unsigned section_line,
972 if (isempty(rvalue)) {
977 if (!ifname_valid(rvalue)) {
978 log_syntax(unit, LOG_ERR, filename, line, 0, "Interface name is not valid or too long, ignoring assignment: %s", rvalue);
982 r = free_and_strdup(s, rvalue);
989 int config_parse_ip_port(
991 const char *filename,
994 unsigned section_line,
1010 if (isempty(rvalue)) {
1015 r = parse_ip_port(rvalue, &port);
1017 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse port '%s'.", rvalue);
1026 int config_parse_join_controllers(
1028 const char *filename,
1030 const char *section,
1031 unsigned section_line,
1038 char ****ret = data;
1039 const char *whole_rvalue = rvalue;
1041 _cleanup_(strv_free_freep) char ***controllers = NULL;
1049 _cleanup_free_ char *word = NULL;
1053 r = extract_first_word(&rvalue, &word, NULL, EXTRACT_QUOTES);
1055 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid value for %s: %s", lvalue, whole_rvalue);
1061 l = strv_split(word, ",");
1066 if (strv_length(l) <= 1) {
1072 controllers = new(char**, 2);
1079 controllers[1] = NULL;
1086 t = new0(char**, n+2);
1094 for (a = controllers; *a; a++)
1095 if (strv_overlap(*a, l)) {
1096 if (strv_extend_strv(&l, *a, false) < 0) {
1115 t[n++] = strv_uniq(l);
1117 strv_free_free(controllers);
1121 if (!isempty(rvalue))
1122 log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
1124 /* As a special case, return a single empty strv, to override the default */
1126 controllers = new(char**, 2);
1129 controllers[0] = strv_new(NULL, NULL);
1130 if (!controllers[0])
1132 controllers[1] = NULL;
1135 strv_free_free(*ret);
1136 *ret = TAKE_PTR(controllers);
1141 int config_parse_mtu(
1143 const char *filename,
1145 const char *section,
1146 unsigned section_line,
1153 uint32_t *mtu = data;
1159 r = parse_mtu(ltype, rvalue, mtu);
1161 log_syntax(unit, LOG_ERR, filename, line, r,
1162 "Maximum transfer unit (MTU) value out of range. Permitted range is %" PRIu32 "…%" PRIu32 ", ignoring: %s",
1163 (uint32_t) (ltype == AF_INET6 ? IPV6_MIN_MTU : IPV4_MIN_MTU), (uint32_t) UINT32_MAX,
1168 log_syntax(unit, LOG_ERR, filename, line, r,
1169 "Failed to parse MTU value '%s', ignoring: %m", rvalue);
1176 int config_parse_rlimit(
1178 const char *filename,
1180 const char *section,
1181 unsigned section_line,
1188 struct rlimit **rl = data, d = {};
1194 r = rlimit_parse(ltype, rvalue, &d);
1196 log_syntax(unit, LOG_WARNING, filename, line, r, "Soft resource limit chosen higher than hard limit, ignoring: %s", rvalue);
1200 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue);
1207 rl[ltype] = newdup(struct rlimit, &d, 1);
1215 int config_parse_permille(const char* unit,
1216 const char *filename,
1218 const char *section,
1219 unsigned section_line,
1226 unsigned *permille = data;
1234 r = parse_permille(rvalue);
1236 log_syntax(unit, LOG_ERR, filename, line, r,
1237 "Failed to parse permille value, ignoring: %s", rvalue);
1241 *permille = (unsigned) r;