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/>.
28 #include <sys/types.h>
30 #include "alloc-util.h"
31 #include "conf-files.h"
32 #include "conf-parser.h"
33 #include "extract-word.h"
38 #include "parse-util.h"
39 #include "path-util.h"
40 #include "process-util.h"
41 #include "signal-util.h"
42 #include "string-util.h"
44 #include "syslog-util.h"
45 #include "time-util.h"
48 int config_item_table_lookup(
52 ConfigParserCallback *func,
57 const ConfigTableItem *t;
65 for (t = table; t->lvalue; t++) {
67 if (!streq(lvalue, t->lvalue))
70 if (!streq_ptr(section, t->section))
82 int config_item_perf_lookup(
86 ConfigParserCallback *func,
91 ConfigPerfItemLookup lookup = (ConfigPerfItemLookup) table;
92 const ConfigPerfItem *p;
101 p = lookup(lvalue, strlen(lvalue));
105 key = strjoin(section, ".", lvalue, NULL);
109 p = lookup(key, strlen(key));
118 *data = (uint8_t*) userdata + p->offset;
122 /* Run the user supplied parser for an assignment */
123 static int next_assignment(const char *unit,
124 const char *filename,
126 ConfigItemLookup lookup,
129 unsigned section_line,
135 ConfigParserCallback func = NULL;
146 r = lookup(table, section, lvalue, &func, <ype, &data, userdata);
152 return func(unit, filename, line, section, section_line,
153 lvalue, ltype, rvalue, data, userdata);
158 /* Warn about unknown non-extension fields. */
159 if (!relaxed && !startswith(lvalue, "X-"))
160 log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown lvalue '%s' in section '%s'", lvalue, section);
165 /* Parse a variable assignment line */
166 static int parse_line(const char* unit,
167 const char *filename,
169 const char *sections,
170 ConfigItemLookup lookup,
175 unsigned *section_line,
176 bool *section_ignored,
192 if (strchr(COMMENTS "\n", *l))
195 if (startswith(l, ".include ")) {
196 _cleanup_free_ char *fn = NULL;
198 /* .includes are a bad idea, we only support them here
199 * for historical reasons. They create cyclic include
200 * problems and make it difficult to detect
201 * configuration file changes with an easy
202 * stat(). Better approaches, such as .d/ drop-in
205 * Support for them should be eventually removed. */
207 if (!allow_include) {
208 log_syntax(unit, LOG_ERR, filename, line, 0, ".include not allowed here. Ignoring.");
212 fn = file_in_same_dir(filename, strstrip(l+9));
216 return config_parse(unit, fn, NULL, sections, lookup, table, relaxed, false, false, 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 (!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 (!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,
296 _cleanup_free_ char *section = NULL, *continuation = NULL;
297 _cleanup_fclose_ FILE *ours = NULL;
298 unsigned line = 0, section_line = 0;
299 bool section_ignored = false;
306 f = ours = fopen(filename, "re");
308 /* Only log on request, except for ENOENT,
309 * since we return 0 to the caller. */
310 if (warn || errno == ENOENT)
311 log_full(errno == ENOENT ? LOG_DEBUG : LOG_ERR,
312 "Failed to open configuration file '%s': %m", filename);
313 return errno == ENOENT ? 0 : -errno;
317 fd_warn_permissions(filename, fileno(f));
320 char l[LINE_MAX], *p, *c = NULL, *e;
321 bool escaped = false;
323 if (!fgets(l, sizeof(l), f)) {
327 log_error_errno(errno, "Failed to read configuration file '%s': %m", filename);
334 c = strappend(continuation, l);
341 continuation = mfree(continuation);
346 for (e = p; *e; e++) {
359 continuation = strdup(l);
387 log_warning_errno(r, "Failed to parse file '%s': %m",
396 /* Parse each config file in the specified directories. */
397 int config_parse_many(const char *conf_file,
398 const char *conf_file_dirs,
399 const char *sections,
400 ConfigItemLookup lookup,
404 _cleanup_strv_free_ char **files = NULL;
408 r = conf_files_list_nulstr(&files, ".conf", NULL, conf_file_dirs);
413 r = config_parse(NULL, conf_file, NULL, sections, lookup, table, relaxed, false, true, userdata);
418 STRV_FOREACH(fn, files) {
419 r = config_parse(NULL, *fn, NULL, sections, lookup, table, relaxed, false, true, userdata);
427 #define DEFINE_PARSER(type, vartype, conv_func) \
428 int config_parse_##type( \
430 const char *filename, \
432 const char *section, \
433 unsigned section_line, \
434 const char *lvalue, \
436 const char *rvalue, \
448 r = conv_func(rvalue, i); \
450 log_syntax(unit, LOG_ERR, filename, line, r, \
451 "Failed to parse %s value, ignoring: %s", \
456 struct __useless_struct_to_allow_trailing_semicolon__
458 DEFINE_PARSER(int, int, safe_atoi);
459 DEFINE_PARSER(long, long, safe_atoli);
460 DEFINE_PARSER(uint32, uint32_t, safe_atou32);
461 DEFINE_PARSER(uint64, uint64_t, safe_atou64);
462 DEFINE_PARSER(unsigned, unsigned, safe_atou);
463 DEFINE_PARSER(double, double, safe_atod);
464 #if 0 /// UNNEEDED by elogind
465 DEFINE_PARSER(nsec, nsec_t, parse_nsec);
467 DEFINE_PARSER(sec, usec_t, parse_sec);
468 DEFINE_PARSER(mode, mode_t, parse_mode);
470 int config_parse_iec_size(const char* unit,
471 const char *filename,
474 unsigned section_line,
490 r = parse_size(rvalue, 1024, &v);
491 if (r < 0 || (uint64_t) (size_t) v != v) {
492 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue);
500 #if 0 /// 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 #if 0 /// UNNEEDED by elogind
588 int config_parse_tristate(
590 const char *filename,
593 unsigned section_line,
607 /* A tristate is pretty much a boolean, except that it can
608 * also take the special value -1, indicating "uninitialized",
609 * much like NULL is for a pointer type. */
611 k = parse_boolean(rvalue);
613 log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse boolean value, ignoring: %s", rvalue);
622 int config_parse_string(
624 const char *filename,
627 unsigned section_line,
641 if (!utf8_is_valid(rvalue)) {
642 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
660 int config_parse_path(
662 const char *filename,
665 unsigned section_line,
679 if (!utf8_is_valid(rvalue)) {
680 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
684 if (!path_is_absolute(rvalue)) {
685 log_syntax(unit, LOG_ERR, filename, line, 0, "Not an absolute path, ignoring: %s", rvalue);
693 path_kill_slashes(n);
701 int config_parse_strv(const char *unit,
702 const char *filename,
705 unsigned section_line,
719 if (isempty(rvalue)) {
722 /* Empty assignment resets the list. As a special rule
723 * we actually fill in a real empty array here rather
724 * than NULL, since some code wants to know if
725 * something was set at all... */
726 empty = strv_new(NULL, NULL);
738 r = extract_first_word(&rvalue, &word, WHITESPACE, EXTRACT_QUOTES);
744 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
748 if (!utf8_is_valid(word)) {
749 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
753 r = strv_consume(sv, word);
761 #if 0 /// UNNEEDED by elogind
762 int config_parse_log_facility(
764 const char *filename,
767 unsigned section_line,
782 x = log_facility_unshifted_from_string(rvalue);
784 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse log facility, ignoring: %s", rvalue);
788 *o = (x << 3) | LOG_PRI(*o);
794 int config_parse_log_level(
796 const char *filename,
799 unsigned section_line,
814 x = log_level_from_string(rvalue);
816 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse log level, ignoring: %s", rvalue);
820 *o = (*o & LOG_FACMASK) | x;
824 int config_parse_signal(
826 const char *filename,
829 unsigned section_line,
843 r = signal_from_string_try_harder(rvalue);
845 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse signal name, ignoring: %s", rvalue);
853 #if 0 /// UNNEEDED by elogind
854 int config_parse_personality(
856 const char *filename,
859 unsigned section_line,
866 unsigned long *personality = data, p;
873 p = personality_from_string(rvalue);
874 if (p == PERSONALITY_INVALID) {
875 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse personality, ignoring: %s", rvalue);