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 "conf-parser.h"
28 #include "conf-files.h"
34 #include "path-util.h"
35 #include "sd-messages.h"
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, NULL);
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(const char *unit,
113 const char *filename,
115 ConfigItemLookup lookup,
118 unsigned section_line,
124 ConfigParserCallback func = NULL;
135 r = lookup(table, section, lvalue, &func, <ype, &data, userdata);
141 return func(unit, filename, line, section, section_line,
142 lvalue, ltype, rvalue, data, userdata);
147 /* Warn about unknown non-extension fields. */
148 if (!relaxed && !startswith(lvalue, "X-"))
149 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
150 "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, EBADMSG,
199 ".include not allowed here. Ignoring.");
203 fn = file_in_same_dir(filename, strstrip(l+9));
207 return config_parse(unit, fn, NULL, sections, lookup, table, relaxed, false, false, userdata);
218 log_syntax(unit, LOG_ERR, filename, line, EBADMSG,
219 "Invalid section header '%s'", l);
223 n = strndup(l+1, k-2);
227 if (sections && !nulstr_contains(sections, n)) {
229 if (!relaxed && !startswith(n, "X-"))
230 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
231 "Unknown section '%s'. Ignoring.", n);
237 *section_ignored = true;
241 *section_line = line;
242 *section_ignored = false;
248 if (sections && !*section) {
250 if (!relaxed && !*section_ignored)
251 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
252 "Assignment outside of section. Ignoring.");
259 log_syntax(unit, LOG_WARNING, filename, line, EINVAL, "Missing '='.");
266 return next_assignment(unit,
279 /* Go through the file and parse each line */
280 int config_parse(const char *unit,
281 const char *filename,
283 const char *sections,
284 ConfigItemLookup lookup,
291 _cleanup_free_ char *section = NULL, *continuation = NULL;
292 _cleanup_fclose_ FILE *ours = NULL;
293 unsigned line = 0, section_line = 0;
294 bool section_ignored = false;
301 f = ours = fopen(filename, "re");
303 /* Only log on request, except for ENOENT,
304 * since we return 0 to the caller. */
305 if (warn || errno == ENOENT)
306 log_full(errno == ENOENT ? LOG_DEBUG : LOG_ERR,
307 "Failed to open configuration file '%s': %m", filename);
308 return errno == ENOENT ? 0 : -errno;
312 fd_warn_permissions(filename, fileno(f));
315 char l[LINE_MAX], *p, *c = NULL, *e;
316 bool escaped = false;
318 if (!fgets(l, sizeof(l), f)) {
322 log_error_errno(errno, "Failed to read configuration file '%s': %m", filename);
329 c = strappend(continuation, l);
336 continuation = mfree(continuation);
341 for (e = p; *e; e++) {
354 continuation = strdup(l);
382 log_warning_errno(r, "Failed to parse file '%s': %m",
391 /* Parse each config file in the specified directories. */
392 int config_parse_many(const char *conf_file,
393 const char *conf_file_dirs,
394 const char *sections,
395 ConfigItemLookup lookup,
399 _cleanup_strv_free_ char **files = NULL;
403 r = conf_files_list_nulstr(&files, ".conf", NULL, conf_file_dirs);
408 r = config_parse(NULL, conf_file, NULL, sections, lookup, table, relaxed, false, true, userdata);
413 STRV_FOREACH(fn, files) {
414 r = config_parse(NULL, *fn, NULL, sections, lookup, table, relaxed, false, true, userdata);
422 #define DEFINE_PARSER(type, vartype, conv_func) \
423 int config_parse_##type(const char *unit, \
424 const char *filename, \
426 const char *section, \
427 unsigned section_line, \
428 const char *lvalue, \
430 const char *rvalue, \
442 r = conv_func(rvalue, i); \
444 log_syntax(unit, LOG_ERR, filename, line, -r, \
445 "Failed to parse %s value, ignoring: %s", \
451 DEFINE_PARSER(int, int, safe_atoi)
452 DEFINE_PARSER(long, long, safe_atoli)
453 DEFINE_PARSER(uint64, uint64_t, safe_atou64)
454 DEFINE_PARSER(unsigned, unsigned, safe_atou)
455 DEFINE_PARSER(double, double, safe_atod)
456 DEFINE_PARSER(nsec, nsec_t, parse_nsec)
457 DEFINE_PARSER(sec, usec_t, parse_sec)
459 int config_parse_iec_size(const char* unit,
460 const char *filename,
463 unsigned section_line,
479 r = parse_size(rvalue, 1024, &o);
480 if (r < 0 || (off_t) (size_t) o != o) {
481 log_syntax(unit, LOG_ERR, filename, line, r < 0 ? -r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue);
489 /// UNNEEDED by elogind
491 int config_parse_si_size(const char* unit,
492 const char *filename,
495 unsigned section_line,
511 r = parse_size(rvalue, 1000, &o);
512 if (r < 0 || (off_t) (size_t) o != o) {
513 log_syntax(unit, LOG_ERR, filename, line, r < 0 ? -r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue);
521 int config_parse_iec_off(const char* unit,
522 const char *filename,
525 unsigned section_line,
540 assert_cc(sizeof(off_t) == sizeof(uint64_t));
542 r = parse_size(rvalue, 1024, bytes);
544 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to parse size value, ignoring: %s", rvalue);
550 int config_parse_bool(const char* unit,
551 const char *filename,
554 unsigned section_line,
569 k = parse_boolean(rvalue);
571 log_syntax(unit, LOG_ERR, filename, line, -k,
572 "Failed to parse boolean value, ignoring: %s", rvalue);
580 int config_parse_string(
582 const char *filename,
585 unsigned section_line,
599 if (!utf8_is_valid(rvalue)) {
600 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
618 int config_parse_path(
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);
642 if (!path_is_absolute(rvalue)) {
643 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Not an absolute path, ignoring: %s", rvalue);
651 path_kill_slashes(n);
659 int config_parse_strv(const char *unit,
660 const char *filename,
663 unsigned section_line,
671 const char *word, *state;
680 if (isempty(rvalue)) {
683 /* Empty assignment resets the list. As a special rule
684 * we actually fill in a real empty array here rather
685 * than NULL, since some code wants to know if
686 * something was set at all... */
687 empty = strv_new(NULL, NULL);
696 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
699 n = strndup(word, l);
703 if (!utf8_is_valid(n)) {
704 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
709 r = strv_consume(sv, n);
714 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
715 "Trailing garbage, ignoring.");
720 int config_parse_mode(
722 const char *filename,
725 unsigned section_line,
739 if (parse_mode(rvalue, m) < 0) {
740 log_syntax(unit, LOG_ERR, filename, line, errno, "Failed to parse mode value, ignoring: %s", rvalue);
747 int config_parse_log_facility(
749 const char *filename,
752 unsigned section_line,
767 x = log_facility_unshifted_from_string(rvalue);
769 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse log facility, ignoring: %s", rvalue);
773 *o = (x << 3) | LOG_PRI(*o);
778 int config_parse_log_level(
780 const char *filename,
783 unsigned section_line,
798 x = log_level_from_string(rvalue);
800 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse log level, ignoring: %s", rvalue);
804 *o = (*o & LOG_FACMASK) | x;