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"
35 #include "path-util.h"
37 #include "exit-status.h"
38 #include "sd-messages.h"
40 int log_syntax_internal(const char *unit, int level,
41 const char *file, unsigned line, const char *func,
42 const char *config_file, unsigned config_line,
43 int error, const char *format, ...) {
45 _cleanup_free_ char *msg = NULL;
50 r = vasprintf(&msg, format, ap);
56 r = log_struct_internal(level,
58 getpid() == 1 ? "UNIT=%s" : "USER_UNIT=%s", unit,
59 MESSAGE_ID(SD_MESSAGE_CONFIG_ERROR),
60 "CONFIG_FILE=%s", config_file,
61 "CONFIG_LINE=%u", config_line,
62 "ERRNO=%d", error > 0 ? error : EINVAL,
63 "MESSAGE=[%s:%u] %s", config_file, config_line, msg,
66 r = log_struct_internal(level,
68 MESSAGE_ID(SD_MESSAGE_CONFIG_ERROR),
69 "CONFIG_FILE=%s", config_file,
70 "CONFIG_LINE=%u", config_line,
71 "ERRNO=%d", error > 0 ? error : EINVAL,
72 "MESSAGE=[%s:%u] %s", config_file, config_line, msg,
78 int config_item_table_lookup(
82 ConfigParserCallback *func,
87 const ConfigTableItem *t;
95 for (t = table; t->lvalue; t++) {
97 if (!streq(lvalue, t->lvalue))
100 if (!streq_ptr(section, t->section))
112 int config_item_perf_lookup(
116 ConfigParserCallback *func,
121 ConfigPerfItemLookup lookup = (ConfigPerfItemLookup) table;
122 const ConfigPerfItem *p;
131 p = lookup(lvalue, strlen(lvalue));
135 key = strjoin(section, ".", lvalue, NULL);
139 p = lookup(key, strlen(key));
148 *data = (uint8_t*) userdata + p->offset;
152 /* Run the user supplied parser for an assignment */
153 static int next_assignment(const char *unit,
154 const char *filename,
156 ConfigItemLookup lookup,
159 unsigned section_line,
165 ConfigParserCallback func = NULL;
176 r = lookup(table, section, lvalue, &func, <ype, &data, userdata);
182 return func(unit, filename, line, section, section_line,
183 lvalue, ltype, rvalue, data, userdata);
188 /* Warn about unknown non-extension fields. */
189 if (!relaxed && !startswith(lvalue, "X-"))
190 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
191 "Unknown lvalue '%s' in section '%s'", lvalue, section);
196 /* Parse a variable assignment line */
197 static int parse_line(const char* unit,
198 const char *filename,
200 const char *sections,
201 ConfigItemLookup lookup,
206 unsigned *section_line,
207 bool *section_ignored,
223 if (strchr(COMMENTS "\n", *l))
226 if (startswith(l, ".include ")) {
227 _cleanup_free_ char *fn = NULL;
229 /* .includes are a bad idea, we only support them here
230 * for historical reasons. They create cyclic include
231 * problems and make it difficult to detect
232 * configuration file changes with an easy
233 * stat(). Better approaches, such as .d/ drop-in
236 * Support for them should be eventually removed. */
238 if (!allow_include) {
239 log_syntax(unit, LOG_ERR, filename, line, EBADMSG,
240 ".include not allowed here. Ignoring.");
244 fn = file_in_same_dir(filename, strstrip(l+9));
248 return config_parse(unit, fn, NULL, sections, lookup, table, relaxed, false, false, userdata);
259 log_syntax(unit, LOG_ERR, filename, line, EBADMSG,
260 "Invalid section header '%s'", l);
264 n = strndup(l+1, k-2);
268 if (sections && !nulstr_contains(sections, n)) {
270 if (!relaxed && !startswith(n, "X-"))
271 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
272 "Unknown section '%s'. Ignoring.", n);
278 *section_ignored = true;
282 *section_line = line;
283 *section_ignored = false;
289 if (sections && !*section) {
291 if (!relaxed && !*section_ignored)
292 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
293 "Assignment outside of section. Ignoring.");
300 log_syntax(unit, LOG_WARNING, filename, line, EINVAL, "Missing '='.");
307 return next_assignment(unit,
320 /* Go through the file and parse each line */
321 int config_parse(const char *unit,
322 const char *filename,
324 const char *sections,
325 ConfigItemLookup lookup,
332 _cleanup_free_ char *section = NULL, *continuation = NULL;
333 _cleanup_fclose_ FILE *ours = NULL;
334 unsigned line = 0, section_line = 0;
335 bool section_ignored = false;
342 f = ours = fopen(filename, "re");
344 /* Only log on request, except for ENOENT,
345 * since we return 0 to the caller. */
346 if (warn || errno == ENOENT)
347 log_full(errno == ENOENT ? LOG_DEBUG : LOG_ERR,
348 "Failed to open configuration file '%s': %m", filename);
349 return errno == ENOENT ? 0 : -errno;
353 fd_warn_permissions(filename, fileno(f));
356 char l[LINE_MAX], *p, *c = NULL, *e;
357 bool escaped = false;
359 if (!fgets(l, sizeof(l), f)) {
363 log_error("Failed to read configuration file '%s': %m", filename);
370 c = strappend(continuation, l);
383 for (e = p; *e; e++) {
396 continuation = strdup(l);
424 log_warning("Failed to parse file '%s': %s",
425 filename, strerror(-r));
433 #define DEFINE_PARSER(type, vartype, conv_func) \
434 int config_parse_##type(const char *unit, \
435 const char *filename, \
437 const char *section, \
438 unsigned section_line, \
439 const char *lvalue, \
441 const char *rvalue, \
453 r = conv_func(rvalue, i); \
455 log_syntax(unit, LOG_ERR, filename, line, -r, \
456 "Failed to parse %s value, ignoring: %s", \
462 DEFINE_PARSER(int, int, safe_atoi)
463 DEFINE_PARSER(long, long, safe_atoli)
464 DEFINE_PARSER(uint64, uint64_t, safe_atou64)
465 DEFINE_PARSER(unsigned, unsigned, safe_atou)
466 DEFINE_PARSER(double, double, safe_atod)
467 DEFINE_PARSER(nsec, nsec_t, parse_nsec)
468 DEFINE_PARSER(sec, usec_t, parse_sec)
470 int config_parse_iec_size(const char* unit,
471 const char *filename,
474 unsigned section_line,
490 r = parse_size(rvalue, 1024, &o);
491 if (r < 0 || (off_t) (size_t) o != o) {
492 log_syntax(unit, LOG_ERR, filename, line, r < 0 ? -r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue);
500 int config_parse_si_size(const char* unit,
501 const char *filename,
504 unsigned section_line,
520 r = parse_size(rvalue, 1000, &o);
521 if (r < 0 || (off_t) (size_t) o != o) {
522 log_syntax(unit, LOG_ERR, filename, line, r < 0 ? -r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue);
530 int config_parse_iec_off(const char* unit,
531 const char *filename,
534 unsigned section_line,
549 assert_cc(sizeof(off_t) == sizeof(uint64_t));
551 r = parse_size(rvalue, 1024, bytes);
553 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,
580 "Failed to parse boolean value, ignoring: %s", rvalue);
588 int config_parse_string(
590 const char *filename,
593 unsigned section_line,
607 if (!utf8_is_valid(rvalue)) {
608 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
626 int config_parse_path(
628 const char *filename,
631 unsigned section_line,
645 if (!utf8_is_valid(rvalue)) {
646 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
650 if (!path_is_absolute(rvalue)) {
651 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Not an absolute path, ignoring: %s", rvalue);
659 path_kill_slashes(n);
667 int config_parse_strv(const char *unit,
668 const char *filename,
671 unsigned section_line,
679 const char *word, *state;
688 if (isempty(rvalue)) {
691 /* Empty assignment resets the list. As a special rule
692 * we actually fill in a real empty array here rather
693 * than NULL, since some code wants to know if
694 * something was set at all... */
695 empty = strv_new(NULL, NULL);
704 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
707 n = strndup(word, l);
711 if (!utf8_is_valid(n)) {
712 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
717 r = strv_consume(sv, n);
722 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
723 "Trailing garbage, ignoring.");
728 int config_parse_mode(const char *unit,
729 const char *filename,
732 unsigned section_line,
749 l = strtol(rvalue, &x, 8);
750 if (!x || x == rvalue || *x || errno) {
751 log_syntax(unit, LOG_ERR, filename, line, errno,
752 "Failed to parse mode value, ignoring: %s", rvalue);
756 if (l < 0000 || l > 07777) {
757 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
758 "Mode value out of range, ignoring: %s", rvalue);
766 int config_parse_log_facility(
768 const char *filename,
771 unsigned section_line,
786 x = log_facility_unshifted_from_string(rvalue);
788 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
789 "Failed to parse log facility, ignoring: %s", rvalue);
793 *o = (x << 3) | LOG_PRI(*o);
798 int config_parse_log_level(
800 const char *filename,
803 unsigned section_line,
818 x = log_level_from_string(rvalue);
820 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
821 "Failed to parse log level, ignoring: %s", rvalue);
825 *o = (*o & LOG_FACMASK) | x;