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"
28 #include "conf-files.h"
34 #include "path-util.h"
35 #include "signal-util.h"
36 #include "conf-parser.h"
38 int config_item_table_lookup(
42 ConfigParserCallback *func,
47 const ConfigTableItem *t;
55 for (t = table; t->lvalue; t++) {
57 if (!streq(lvalue, t->lvalue))
60 if (!streq_ptr(section, t->section))
72 int config_item_perf_lookup(
76 ConfigParserCallback *func,
81 ConfigPerfItemLookup lookup = (ConfigPerfItemLookup) table;
82 const ConfigPerfItem *p;
91 p = lookup(lvalue, strlen(lvalue));
95 key = strjoin(section, ".", lvalue, NULL);
99 p = lookup(key, strlen(key));
108 *data = (uint8_t*) userdata + p->offset;
112 /* Run the user supplied parser for an assignment */
113 static int next_assignment(const char *unit,
114 const char *filename,
116 ConfigItemLookup lookup,
119 unsigned section_line,
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 (!relaxed && !startswith(lvalue, "X-"))
150 log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown lvalue '%s' in section '%s'", lvalue, section);
155 /* Parse a variable assignment line */
156 static int parse_line(const char* unit,
157 const char *filename,
159 const char *sections,
160 ConfigItemLookup lookup,
165 unsigned *section_line,
166 bool *section_ignored,
182 if (strchr(COMMENTS "\n", *l))
185 if (startswith(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 (!allow_include) {
198 log_syntax(unit, LOG_ERR, filename, line, 0, ".include not allowed here. Ignoring.");
202 fn = file_in_same_dir(filename, strstrip(l+9));
206 return config_parse(unit, fn, NULL, sections, lookup, table, relaxed, false, false, userdata);
217 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid section header '%s'", l);
221 n = strndup(l+1, k-2);
225 if (sections && !nulstr_contains(sections, n)) {
227 if (!relaxed && !startswith(n, "X-"))
228 log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown section '%s'. Ignoring.", n);
231 *section = mfree(*section);
233 *section_ignored = true;
237 *section_line = line;
238 *section_ignored = false;
244 if (sections && !*section) {
246 if (!relaxed && !*section_ignored)
247 log_syntax(unit, LOG_WARNING, filename, line, 0, "Assignment outside of section. Ignoring.");
254 log_syntax(unit, LOG_WARNING, filename, line, 0, "Missing '='.");
261 return next_assignment(unit,
274 /* Go through the file and parse each line */
275 int config_parse(const char *unit,
276 const char *filename,
278 const char *sections,
279 ConfigItemLookup lookup,
286 _cleanup_free_ char *section = NULL, *continuation = NULL;
287 _cleanup_fclose_ FILE *ours = NULL;
288 unsigned line = 0, section_line = 0;
289 bool section_ignored = false;
296 f = ours = fopen(filename, "re");
298 /* Only log on request, except for ENOENT,
299 * since we return 0 to the caller. */
300 if (warn || errno == ENOENT)
301 log_full(errno == ENOENT ? LOG_DEBUG : LOG_ERR,
302 "Failed to open configuration file '%s': %m", filename);
303 return errno == ENOENT ? 0 : -errno;
307 fd_warn_permissions(filename, fileno(f));
310 char l[LINE_MAX], *p, *c = NULL, *e;
311 bool escaped = false;
313 if (!fgets(l, sizeof(l), f)) {
317 log_error_errno(errno, "Failed to read configuration file '%s': %m", filename);
324 c = strappend(continuation, l);
331 continuation = mfree(continuation);
336 for (e = p; *e; e++) {
349 continuation = strdup(l);
377 log_warning_errno(r, "Failed to parse file '%s': %m",
386 /* Parse each config file in the specified directories. */
387 int config_parse_many(const char *conf_file,
388 const char *conf_file_dirs,
389 const char *sections,
390 ConfigItemLookup lookup,
394 _cleanup_strv_free_ char **files = NULL;
398 r = conf_files_list_nulstr(&files, ".conf", NULL, conf_file_dirs);
403 r = config_parse(NULL, conf_file, NULL, sections, lookup, table, relaxed, false, true, userdata);
408 STRV_FOREACH(fn, files) {
409 r = config_parse(NULL, *fn, NULL, sections, lookup, table, relaxed, false, true, userdata);
417 #define DEFINE_PARSER(type, vartype, conv_func) \
418 int config_parse_##type( \
420 const char *filename, \
422 const char *section, \
423 unsigned section_line, \
424 const char *lvalue, \
426 const char *rvalue, \
438 r = conv_func(rvalue, i); \
440 log_syntax(unit, LOG_ERR, filename, line, r, \
441 "Failed to parse %s value, ignoring: %s", \
446 struct __useless_struct_to_allow_trailing_semicolon__
448 DEFINE_PARSER(int, int, safe_atoi);
449 DEFINE_PARSER(long, long, safe_atoli);
450 DEFINE_PARSER(uint32, uint32_t, safe_atou32);
451 DEFINE_PARSER(uint64, uint64_t, safe_atou64);
452 DEFINE_PARSER(unsigned, unsigned, safe_atou);
453 DEFINE_PARSER(double, double, safe_atod);
454 // UNNEEDED DEFINE_PARSER(nsec, nsec_t, parse_nsec);
455 DEFINE_PARSER(sec, usec_t, parse_sec);
456 DEFINE_PARSER(mode, mode_t, parse_mode);
458 int config_parse_iec_size(const char* unit,
459 const char *filename,
462 unsigned section_line,
478 r = parse_size(rvalue, 1024, &v);
479 if (r < 0 || (uint64_t) (size_t) v != v) {
480 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue);
488 /// UNNEEDED by elogind
490 int config_parse_si_size(const char* unit,
491 const char *filename,
494 unsigned section_line,
510 r = parse_size(rvalue, 1000, &v);
511 if (r < 0 || (uint64_t) (size_t) v != v) {
512 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue);
520 int config_parse_iec_uint64(const char* unit,
521 const char *filename,
524 unsigned section_line,
531 uint64_t *bytes = data;
539 r = parse_size(rvalue, 1024, bytes);
541 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue);
547 int config_parse_bool(const char* unit,
548 const char *filename,
551 unsigned section_line,
566 k = parse_boolean(rvalue);
568 log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse boolean value, ignoring: %s", rvalue);
576 /// UNNEEDED by elogind
578 int config_parse_tristate(
580 const char *filename,
583 unsigned section_line,
597 /* A tristate is pretty much a boolean, except that it can
598 * also take the special value -1, indicating "uninitialized",
599 * much like NULL is for a pointer type. */
601 k = parse_boolean(rvalue);
603 log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse boolean value, ignoring: %s", rvalue);
612 int config_parse_string(
614 const char *filename,
617 unsigned section_line,
631 if (!utf8_is_valid(rvalue)) {
632 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
650 int config_parse_path(
652 const char *filename,
655 unsigned section_line,
669 if (!utf8_is_valid(rvalue)) {
670 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
674 if (!path_is_absolute(rvalue)) {
675 log_syntax(unit, LOG_ERR, filename, line, 0, "Not an absolute path, ignoring: %s", rvalue);
683 path_kill_slashes(n);
691 int config_parse_strv(const char *unit,
692 const char *filename,
695 unsigned section_line,
703 const char *word, *state;
712 if (isempty(rvalue)) {
715 /* Empty assignment resets the list. As a special rule
716 * we actually fill in a real empty array here rather
717 * than NULL, since some code wants to know if
718 * something was set at all... */
719 empty = strv_new(NULL, NULL);
728 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
731 n = strndup(word, l);
735 if (!utf8_is_valid(n)) {
736 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
741 r = strv_consume(sv, n);
746 log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
751 /// UNNEEDED by elogind
753 int config_parse_log_facility(
755 const char *filename,
758 unsigned section_line,
773 x = log_facility_unshifted_from_string(rvalue);
775 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse log facility, ignoring: %s", rvalue);
779 *o = (x << 3) | LOG_PRI(*o);
785 int config_parse_log_level(
787 const char *filename,
790 unsigned section_line,
805 x = log_level_from_string(rvalue);
807 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse log level, ignoring: %s", rvalue);
811 *o = (*o & LOG_FACMASK) | x;
815 int config_parse_signal(
817 const char *filename,
820 unsigned section_line,
834 r = signal_from_string_try_harder(rvalue);
836 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse signal name, ignoring: %s", rvalue);
844 /// UNNEEDED by elogind
846 int config_parse_personality(
848 const char *filename,
851 unsigned section_line,
858 unsigned long *personality = data, p;
865 p = personality_from_string(rvalue);
866 if (p == PERSONALITY_INVALID) {
867 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse personality, ignoring: %s", rvalue);