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 <netinet/ether.h>
29 #include "conf-parser.h"
30 #include "conf-files.h"
36 #include "path-util.h"
38 #include "exit-status.h"
39 #include "sd-messages.h"
41 int log_syntax_internal(const char *unit, int level,
42 const char *file, unsigned line, const char *func,
43 const char *config_file, unsigned config_line,
44 int error, const char *format, ...) {
46 _cleanup_free_ char *msg = NULL;
51 r = vasprintf(&msg, format, ap);
57 r = log_struct_internal(level,
59 getpid() == 1 ? "UNIT=%s" : "USER_UNIT=%s", unit,
60 MESSAGE_ID(SD_MESSAGE_CONFIG_ERROR),
61 "CONFIG_FILE=%s", config_file,
62 "CONFIG_LINE=%u", config_line,
63 "ERRNO=%d", error > 0 ? error : EINVAL,
64 "MESSAGE=[%s:%u] %s", config_file, config_line, msg,
67 r = log_struct_internal(level,
69 MESSAGE_ID(SD_MESSAGE_CONFIG_ERROR),
70 "CONFIG_FILE=%s", config_file,
71 "CONFIG_LINE=%u", config_line,
72 "ERRNO=%d", error > 0 ? error : EINVAL,
73 "MESSAGE=[%s:%u] %s", config_file, config_line, msg,
79 int config_item_table_lookup(
83 ConfigParserCallback *func,
88 const ConfigTableItem *t;
96 for (t = table; t->lvalue; t++) {
98 if (!streq(lvalue, t->lvalue))
101 if (!streq_ptr(section, t->section))
113 int config_item_perf_lookup(
117 ConfigParserCallback *func,
122 ConfigPerfItemLookup lookup = (ConfigPerfItemLookup) table;
123 const ConfigPerfItem *p;
132 p = lookup(lvalue, strlen(lvalue));
136 key = strjoin(section, ".", lvalue, NULL);
140 p = lookup(key, strlen(key));
149 *data = (uint8_t*) userdata + p->offset;
153 /* Run the user supplied parser for an assignment */
154 static int next_assignment(const char *unit,
155 const char *filename,
157 ConfigItemLookup lookup,
160 unsigned section_line,
166 ConfigParserCallback func = NULL;
177 r = lookup(table, section, lvalue, &func, <ype, &data, userdata);
183 return func(unit, filename, line, section, section_line,
184 lvalue, ltype, rvalue, data, userdata);
189 /* Warn about unknown non-extension fields. */
190 if (!relaxed && !startswith(lvalue, "X-"))
191 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
192 "Unknown lvalue '%s' in section '%s'", lvalue, section);
197 /* Parse a variable assignment line */
198 static int parse_line(const char* unit,
199 const char *filename,
201 const char *sections,
202 ConfigItemLookup lookup,
207 unsigned *section_line,
208 bool *section_ignored,
224 if (strchr(COMMENTS "\n", *l))
227 if (startswith(l, ".include ")) {
228 _cleanup_free_ char *fn = NULL;
230 /* .includes are a bad idea, we only support them here
231 * for historical reasons. They create cyclic include
232 * problems and make it difficult to detect
233 * configuration file changes with an easy
234 * stat(). Better approaches, such as .d/ drop-in
237 * Support for them should be eventually removed. */
239 if (!allow_include) {
240 log_syntax(unit, LOG_ERR, filename, line, EBADMSG,
241 ".include not allowed here. Ignoring.");
245 fn = file_in_same_dir(filename, strstrip(l+9));
249 return config_parse(unit, fn, NULL, sections, lookup, table, relaxed, false, false, userdata);
260 log_syntax(unit, LOG_ERR, filename, line, EBADMSG,
261 "Invalid section header '%s'", l);
265 n = strndup(l+1, k-2);
269 if (sections && !nulstr_contains(sections, n)) {
271 if (!relaxed && !startswith(n, "X-"))
272 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
273 "Unknown section '%s'. Ignoring.", n);
279 *section_ignored = true;
283 *section_line = line;
284 *section_ignored = false;
290 if (sections && !*section) {
292 if (!relaxed && !*section_ignored)
293 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
294 "Assignment outside of section. Ignoring.");
301 log_syntax(unit, LOG_WARNING, filename, line, EINVAL, "Missing '='.");
308 return next_assignment(unit,
321 /* Go through the file and parse each line */
322 int config_parse(const char *unit,
323 const char *filename,
325 const char *sections,
326 ConfigItemLookup lookup,
333 _cleanup_free_ char *section = NULL, *continuation = NULL;
334 _cleanup_fclose_ FILE *ours = NULL;
335 unsigned line = 0, section_line = 0;
336 bool section_ignored = false;
343 f = ours = fopen(filename, "re");
345 /* Only log on request, except for ENOENT,
346 * since we return 0 to the caller. */
347 if (warn || errno == ENOENT)
348 log_full(errno == ENOENT ? LOG_DEBUG : LOG_ERR,
349 "Failed to open configuration file '%s': %m", filename);
350 return errno == ENOENT ? 0 : -errno;
354 fd_warn_permissions(filename, fileno(f));
357 char l[LINE_MAX], *p, *c = NULL, *e;
358 bool escaped = false;
360 if (!fgets(l, sizeof(l), f)) {
364 log_error("Failed to read configuration file '%s': %m", filename);
371 c = strappend(continuation, l);
384 for (e = p; *e; e++) {
397 continuation = strdup(l);
425 log_warning("Failed to parse file '%s': %s",
426 filename, strerror(-r));
434 /* Parse each config file in the specified directories. */
435 int config_parse_many(const char *conf_file,
436 const char *conf_file_dirs,
437 const char *sections,
438 ConfigItemLookup lookup,
442 _cleanup_strv_free_ char **files = NULL;
446 r = conf_files_list_nulstr(&files, ".conf", NULL, conf_file_dirs);
451 r = config_parse(NULL, conf_file, NULL, sections, lookup, table, relaxed, false, true, userdata);
456 STRV_FOREACH(fn, files) {
457 r = config_parse(NULL, *fn, NULL, sections, lookup, table, relaxed, false, true, userdata);
465 #define DEFINE_PARSER(type, vartype, conv_func) \
466 int config_parse_##type(const char *unit, \
467 const char *filename, \
469 const char *section, \
470 unsigned section_line, \
471 const char *lvalue, \
473 const char *rvalue, \
485 r = conv_func(rvalue, i); \
487 log_syntax(unit, LOG_ERR, filename, line, -r, \
488 "Failed to parse %s value, ignoring: %s", \
494 DEFINE_PARSER(int, int, safe_atoi)
495 DEFINE_PARSER(long, long, safe_atoli)
496 DEFINE_PARSER(uint64, uint64_t, safe_atou64)
497 DEFINE_PARSER(unsigned, unsigned, safe_atou)
498 DEFINE_PARSER(double, double, safe_atod)
499 DEFINE_PARSER(nsec, nsec_t, parse_nsec)
500 DEFINE_PARSER(sec, usec_t, parse_sec)
502 int config_parse_iec_size(const char* unit,
503 const char *filename,
506 unsigned section_line,
522 r = parse_size(rvalue, 1024, &o);
523 if (r < 0 || (off_t) (size_t) o != o) {
524 log_syntax(unit, LOG_ERR, filename, line, r < 0 ? -r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue);
532 int config_parse_si_size(const char* unit,
533 const char *filename,
536 unsigned section_line,
552 r = parse_size(rvalue, 1000, &o);
553 if (r < 0 || (off_t) (size_t) o != o) {
554 log_syntax(unit, LOG_ERR, filename, line, r < 0 ? -r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue);
562 int config_parse_iec_off(const char* unit,
563 const char *filename,
566 unsigned section_line,
581 assert_cc(sizeof(off_t) == sizeof(uint64_t));
583 r = parse_size(rvalue, 1024, bytes);
585 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to parse size value, ignoring: %s", rvalue);
590 int config_parse_bool(const char* unit,
591 const char *filename,
594 unsigned section_line,
609 k = parse_boolean(rvalue);
611 log_syntax(unit, LOG_ERR, filename, line, -k,
612 "Failed to parse boolean value, ignoring: %s", rvalue);
620 int config_parse_string(
622 const char *filename,
625 unsigned section_line,
639 if (!utf8_is_valid(rvalue)) {
640 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
658 int config_parse_path(
660 const char *filename,
663 unsigned section_line,
677 if (!utf8_is_valid(rvalue)) {
678 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
682 if (!path_is_absolute(rvalue)) {
683 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Not an absolute path, ignoring: %s", rvalue);
691 path_kill_slashes(n);
699 int config_parse_strv(const char *unit,
700 const char *filename,
703 unsigned section_line,
711 const char *word, *state;
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);
736 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
739 n = strndup(word, l);
743 if (!utf8_is_valid(n)) {
744 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
749 r = strv_consume(sv, n);
754 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
755 "Trailing garbage, ignoring.");
760 int config_parse_mode(const char *unit,
761 const char *filename,
764 unsigned section_line,
781 l = strtol(rvalue, &x, 8);
782 if (!x || x == rvalue || *x || errno) {
783 log_syntax(unit, LOG_ERR, filename, line, errno,
784 "Failed to parse mode value, ignoring: %s", rvalue);
788 if (l < 0000 || l > 07777) {
789 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
790 "Mode value out of range, ignoring: %s", rvalue);
798 int config_parse_log_facility(
800 const char *filename,
803 unsigned section_line,
818 x = log_facility_unshifted_from_string(rvalue);
820 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
821 "Failed to parse log facility, ignoring: %s", rvalue);
825 *o = (x << 3) | LOG_PRI(*o);
830 int config_parse_log_level(
832 const char *filename,
835 unsigned section_line,
850 x = log_level_from_string(rvalue);
852 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
853 "Failed to parse log level, ignoring: %s", rvalue);
857 *o = (*o & LOG_FACMASK) | x;