1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
27 #include "sd-messages.h"
29 #include "alloc-util.h"
30 #include "conf-files.h"
31 #include "conf-parser.h"
36 #include "parse-util.h"
37 #include "path-util.h"
38 #include "process-util.h"
39 #include "signal-util.h"
40 #include "string-util.h"
42 #include "syslog-util.h"
46 int config_item_table_lookup(
50 ConfigParserCallback *func,
55 const ConfigTableItem *t;
63 for (t = table; t->lvalue; t++) {
65 if (!streq(lvalue, t->lvalue))
68 if (!streq_ptr(section, t->section))
80 int config_item_perf_lookup(
84 ConfigParserCallback *func,
89 ConfigPerfItemLookup lookup = (ConfigPerfItemLookup) table;
90 const ConfigPerfItem *p;
99 p = lookup(lvalue, strlen(lvalue));
103 key = strjoin(section, ".", lvalue, NULL);
107 p = lookup(key, strlen(key));
116 *data = (uint8_t*) userdata + p->offset;
120 /* Run the user supplied parser for an assignment */
121 static int next_assignment(const char *unit,
122 const char *filename,
124 ConfigItemLookup lookup,
127 unsigned section_line,
133 ConfigParserCallback func = NULL;
144 r = lookup(table, section, lvalue, &func, <ype, &data, userdata);
150 return func(unit, filename, line, section, section_line,
151 lvalue, ltype, rvalue, data, userdata);
156 /* Warn about unknown non-extension fields. */
157 if (!relaxed && !startswith(lvalue, "X-"))
158 log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown lvalue '%s' in section '%s'", lvalue, section);
163 /* Parse a variable assignment line */
164 static int parse_line(const char* unit,
165 const char *filename,
167 const char *sections,
168 ConfigItemLookup lookup,
173 unsigned *section_line,
174 bool *section_ignored,
190 if (strchr(COMMENTS "\n", *l))
193 if (startswith(l, ".include ")) {
194 _cleanup_free_ char *fn = NULL;
196 /* .includes are a bad idea, we only support them here
197 * for historical reasons. They create cyclic include
198 * problems and make it difficult to detect
199 * configuration file changes with an easy
200 * stat(). Better approaches, such as .d/ drop-in
203 * Support for them should be eventually removed. */
205 if (!allow_include) {
206 log_syntax(unit, LOG_ERR, filename, line, 0, ".include not allowed here. Ignoring.");
210 fn = file_in_same_dir(filename, strstrip(l+9));
214 return config_parse(unit, fn, NULL, sections, lookup, table, relaxed, false, false, userdata);
225 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid section header '%s'", l);
229 n = strndup(l+1, k-2);
233 if (sections && !nulstr_contains(sections, n)) {
235 if (!relaxed && !startswith(n, "X-"))
236 log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown section '%s'. Ignoring.", n);
239 *section = mfree(*section);
241 *section_ignored = true;
245 *section_line = line;
246 *section_ignored = false;
252 if (sections && !*section) {
254 if (!relaxed && !*section_ignored)
255 log_syntax(unit, LOG_WARNING, filename, line, 0, "Assignment outside of section. Ignoring.");
262 log_syntax(unit, LOG_WARNING, filename, line, 0, "Missing '='.");
269 return next_assignment(unit,
282 /* Go through the file and parse each line */
283 int config_parse(const char *unit,
284 const char *filename,
286 const char *sections,
287 ConfigItemLookup lookup,
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 (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 char l[LINE_MAX], *p, *c = NULL, *e;
319 bool escaped = false;
321 if (!fgets(l, sizeof(l), f)) {
325 log_error_errno(errno, "Failed to read configuration file '%s': %m", filename);
332 c = strappend(continuation, l);
339 continuation = mfree(continuation);
344 for (e = p; *e; e++) {
357 continuation = strdup(l);
385 log_warning_errno(r, "Failed to parse file '%s': %m",
394 /* Parse each config file in the specified directories. */
395 int config_parse_many(const char *conf_file,
396 const char *conf_file_dirs,
397 const char *sections,
398 ConfigItemLookup lookup,
402 _cleanup_strv_free_ char **files = NULL;
406 r = conf_files_list_nulstr(&files, ".conf", NULL, conf_file_dirs);
411 r = config_parse(NULL, conf_file, NULL, sections, lookup, table, relaxed, false, true, userdata);
416 STRV_FOREACH(fn, files) {
417 r = config_parse(NULL, *fn, NULL, sections, lookup, table, relaxed, false, true, userdata);
425 #define DEFINE_PARSER(type, vartype, conv_func) \
426 int config_parse_##type( \
428 const char *filename, \
430 const char *section, \
431 unsigned section_line, \
432 const char *lvalue, \
434 const char *rvalue, \
446 r = conv_func(rvalue, i); \
448 log_syntax(unit, LOG_ERR, filename, line, r, \
449 "Failed to parse %s value, ignoring: %s", \
454 struct __useless_struct_to_allow_trailing_semicolon__
456 DEFINE_PARSER(int, int, safe_atoi);
457 DEFINE_PARSER(long, long, safe_atoli);
458 DEFINE_PARSER(uint32, uint32_t, safe_atou32);
459 DEFINE_PARSER(uint64, uint64_t, safe_atou64);
460 DEFINE_PARSER(unsigned, unsigned, safe_atou);
461 DEFINE_PARSER(double, double, safe_atod);
462 /// UNNEEDED by elogind
464 DEFINE_PARSER(nsec, nsec_t, parse_nsec);
466 DEFINE_PARSER(sec, usec_t, parse_sec);
467 DEFINE_PARSER(mode, mode_t, parse_mode);
469 int config_parse_iec_size(const char* unit,
470 const char *filename,
473 unsigned section_line,
489 r = parse_size(rvalue, 1024, &v);
490 if (r < 0 || (uint64_t) (size_t) v != v) {
491 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue);
499 /// UNNEEDED by elogind
501 int config_parse_si_size(const char* unit,
502 const char *filename,
505 unsigned section_line,
521 r = parse_size(rvalue, 1000, &v);
522 if (r < 0 || (uint64_t) (size_t) v != v) {
523 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue);
531 int config_parse_iec_uint64(const char* unit,
532 const char *filename,
535 unsigned section_line,
542 uint64_t *bytes = data;
550 r = parse_size(rvalue, 1024, bytes);
552 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue);
558 int config_parse_bool(const char* unit,
559 const char *filename,
562 unsigned section_line,
577 k = parse_boolean(rvalue);
579 log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse boolean value, ignoring: %s", rvalue);
587 /// UNNEEDED by elogind
589 int config_parse_tristate(
591 const char *filename,
594 unsigned section_line,
608 /* A tristate is pretty much a boolean, except that it can
609 * also take the special value -1, indicating "uninitialized",
610 * much like NULL is for a pointer type. */
612 k = parse_boolean(rvalue);
614 log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse boolean value, ignoring: %s", rvalue);
623 int config_parse_string(
625 const char *filename,
628 unsigned section_line,
642 if (!utf8_is_valid(rvalue)) {
643 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
661 int config_parse_path(
663 const char *filename,
666 unsigned section_line,
680 if (!utf8_is_valid(rvalue)) {
681 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
685 if (!path_is_absolute(rvalue)) {
686 log_syntax(unit, LOG_ERR, filename, line, 0, "Not an absolute path, ignoring: %s", rvalue);
694 path_kill_slashes(n);
702 int config_parse_strv(const char *unit,
703 const char *filename,
706 unsigned section_line,
720 if (isempty(rvalue)) {
723 /* Empty assignment resets the list. As a special rule
724 * we actually fill in a real empty array here rather
725 * than NULL, since some code wants to know if
726 * something was set at all... */
727 empty = strv_new(NULL, NULL);
739 r = extract_first_word(&rvalue, &word, WHITESPACE, EXTRACT_QUOTES);
745 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
749 if (!utf8_is_valid(word)) {
750 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
754 r = strv_consume(sv, word);
762 /// UNNEEDED by elogind
764 int config_parse_log_facility(
766 const char *filename,
769 unsigned section_line,
784 x = log_facility_unshifted_from_string(rvalue);
786 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse log facility, ignoring: %s", rvalue);
790 *o = (x << 3) | LOG_PRI(*o);
796 int config_parse_log_level(
798 const char *filename,
801 unsigned section_line,
816 x = log_level_from_string(rvalue);
818 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse log level, ignoring: %s", rvalue);
822 *o = (*o & LOG_FACMASK) | x;
826 int config_parse_signal(
828 const char *filename,
831 unsigned section_line,
845 r = signal_from_string_try_harder(rvalue);
847 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse signal name, ignoring: %s", rvalue);
855 /// UNNEEDED by elogind
857 int config_parse_personality(
859 const char *filename,
862 unsigned section_line,
869 unsigned long *personality = data, p;
876 p = personality_from_string(rvalue);
877 if (p == PERSONALITY_INVALID) {
878 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse personality, ignoring: %s", rvalue);