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, EINVAL,
151 "Unknown lvalue '%s' in section '%s'", lvalue, section);
156 /* Parse a variable assignment line */
157 static int parse_line(const char* unit,
158 const char *filename,
160 const char *sections,
161 ConfigItemLookup lookup,
166 unsigned *section_line,
167 bool *section_ignored,
183 if (strchr(COMMENTS "\n", *l))
186 if (startswith(l, ".include ")) {
187 _cleanup_free_ char *fn = NULL;
189 /* .includes are a bad idea, we only support them here
190 * for historical reasons. They create cyclic include
191 * problems and make it difficult to detect
192 * configuration file changes with an easy
193 * stat(). Better approaches, such as .d/ drop-in
196 * Support for them should be eventually removed. */
198 if (!allow_include) {
199 log_syntax(unit, LOG_ERR, filename, line, EBADMSG,
200 ".include not allowed here. Ignoring.");
204 fn = file_in_same_dir(filename, strstrip(l+9));
208 return config_parse(unit, fn, NULL, sections, lookup, table, relaxed, false, false, userdata);
219 log_syntax(unit, LOG_ERR, filename, line, EBADMSG,
220 "Invalid section header '%s'", l);
224 n = strndup(l+1, k-2);
228 if (sections && !nulstr_contains(sections, n)) {
230 if (!relaxed && !startswith(n, "X-"))
231 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
232 "Unknown section '%s'. Ignoring.", n);
238 *section_ignored = true;
242 *section_line = line;
243 *section_ignored = false;
249 if (sections && !*section) {
251 if (!relaxed && !*section_ignored)
252 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
253 "Assignment outside of section. Ignoring.");
260 log_syntax(unit, LOG_WARNING, filename, line, EINVAL, "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,
292 _cleanup_free_ char *section = NULL, *continuation = NULL;
293 _cleanup_fclose_ FILE *ours = NULL;
294 unsigned line = 0, section_line = 0;
295 bool section_ignored = false;
302 f = ours = fopen(filename, "re");
304 /* Only log on request, except for ENOENT,
305 * since we return 0 to the caller. */
306 if (warn || errno == ENOENT)
307 log_full(errno == ENOENT ? LOG_DEBUG : LOG_ERR,
308 "Failed to open configuration file '%s': %m", filename);
309 return errno == ENOENT ? 0 : -errno;
313 fd_warn_permissions(filename, fileno(f));
316 char l[LINE_MAX], *p, *c = NULL, *e;
317 bool escaped = false;
319 if (!fgets(l, sizeof(l), f)) {
323 log_error_errno(errno, "Failed to read configuration file '%s': %m", filename);
330 c = strappend(continuation, l);
337 continuation = mfree(continuation);
342 for (e = p; *e; e++) {
355 continuation = strdup(l);
383 log_warning_errno(r, "Failed to parse file '%s': %m",
392 /* Parse each config file in the specified directories. */
393 int config_parse_many(const char *conf_file,
394 const char *conf_file_dirs,
395 const char *sections,
396 ConfigItemLookup lookup,
400 _cleanup_strv_free_ char **files = NULL;
404 r = conf_files_list_nulstr(&files, ".conf", NULL, conf_file_dirs);
409 r = config_parse(NULL, conf_file, NULL, sections, lookup, table, relaxed, false, true, userdata);
414 STRV_FOREACH(fn, files) {
415 r = config_parse(NULL, *fn, NULL, sections, lookup, table, relaxed, false, true, userdata);
423 #define DEFINE_PARSER(type, vartype, conv_func) \
424 int config_parse_##type(const char *unit, \
425 const char *filename, \
427 const char *section, \
428 unsigned section_line, \
429 const char *lvalue, \
431 const char *rvalue, \
443 r = conv_func(rvalue, i); \
445 log_syntax(unit, LOG_ERR, filename, line, -r, \
446 "Failed to parse %s value, ignoring: %s", \
452 DEFINE_PARSER(int, int, safe_atoi)
453 DEFINE_PARSER(long, long, safe_atoli)
454 DEFINE_PARSER(uint32, uint32_t, safe_atou32)
455 DEFINE_PARSER(uint64, uint64_t, safe_atou64)
456 DEFINE_PARSER(unsigned, unsigned, safe_atou)
457 DEFINE_PARSER(double, double, safe_atod)
458 DEFINE_PARSER(nsec, nsec_t, parse_nsec)
459 DEFINE_PARSER(sec, usec_t, parse_sec)
461 int config_parse_iec_size(const char* unit,
462 const char *filename,
465 unsigned section_line,
481 r = parse_size(rvalue, 1024, &o);
482 if (r < 0 || (off_t) (size_t) o != o) {
483 log_syntax(unit, LOG_ERR, filename, line, r < 0 ? -r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue);
491 /// UNNEEDED by elogind
493 int config_parse_si_size(const char* unit,
494 const char *filename,
497 unsigned section_line,
513 r = parse_size(rvalue, 1000, &o);
514 if (r < 0 || (off_t) (size_t) o != o) {
515 log_syntax(unit, LOG_ERR, filename, line, r < 0 ? -r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue);
523 int config_parse_iec_off(const char* unit,
524 const char *filename,
527 unsigned section_line,
542 assert_cc(sizeof(off_t) == sizeof(uint64_t));
544 r = parse_size(rvalue, 1024, bytes);
546 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to parse size value, ignoring: %s", rvalue);
552 int config_parse_bool(const char* unit,
553 const char *filename,
556 unsigned section_line,
571 k = parse_boolean(rvalue);
573 log_syntax(unit, LOG_ERR, filename, line, -k,
574 "Failed to parse boolean value, ignoring: %s", rvalue);
582 /// UNNEEDED by elogind
584 int config_parse_tristate(
586 const char *filename,
589 unsigned section_line,
603 /* A tristate is pretty much a boolean, except that it can
604 * also take the special value -1, indicating "uninitialized",
605 * much like NULL is for a pointer type. */
607 k = parse_boolean(rvalue);
609 log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse boolean value, ignoring: %s", rvalue);
618 int config_parse_string(
620 const char *filename,
623 unsigned section_line,
637 if (!utf8_is_valid(rvalue)) {
638 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
656 int config_parse_path(
658 const char *filename,
661 unsigned section_line,
675 if (!utf8_is_valid(rvalue)) {
676 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
680 if (!path_is_absolute(rvalue)) {
681 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Not an absolute path, ignoring: %s", rvalue);
689 path_kill_slashes(n);
697 int config_parse_strv(const char *unit,
698 const char *filename,
701 unsigned section_line,
709 const char *word, *state;
718 if (isempty(rvalue)) {
721 /* Empty assignment resets the list. As a special rule
722 * we actually fill in a real empty array here rather
723 * than NULL, since some code wants to know if
724 * something was set at all... */
725 empty = strv_new(NULL, NULL);
734 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
737 n = strndup(word, l);
741 if (!utf8_is_valid(n)) {
742 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
747 r = strv_consume(sv, n);
752 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
753 "Trailing garbage, ignoring.");
758 int config_parse_mode(
760 const char *filename,
763 unsigned section_line,
777 if (parse_mode(rvalue, m) < 0) {
778 log_syntax(unit, LOG_ERR, filename, line, errno, "Failed to parse mode value, ignoring: %s", rvalue);
785 int config_parse_log_facility(
787 const char *filename,
790 unsigned section_line,
805 x = log_facility_unshifted_from_string(rvalue);
807 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse log facility, ignoring: %s", rvalue);
811 *o = (x << 3) | LOG_PRI(*o);
816 int config_parse_log_level(
818 const char *filename,
821 unsigned section_line,
836 x = log_level_from_string(rvalue);
838 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse log level, ignoring: %s", rvalue);
842 *o = (*o & LOG_FACMASK) | x;
846 int config_parse_signal(
848 const char *filename,
851 unsigned section_line,
865 r = signal_from_string_try_harder(rvalue);
867 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse signal name, ignoring: %s", rvalue);
875 /// UNNEEDED by elogind
877 int config_parse_personality(
879 const char *filename,
882 unsigned section_line,
889 unsigned long *personality = data, p;
896 p = personality_from_string(rvalue);
897 if (p == PERSONALITY_INVALID) {
898 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse personality, ignoring: %s", rvalue);