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,
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, 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,
331 _cleanup_free_ char *section = NULL, *continuation = NULL;
332 _cleanup_fclose_ FILE *ours = NULL;
333 unsigned line = 0, section_line = 0;
334 bool section_ignored = false;
341 f = ours = fopen(filename, "re");
343 log_full(errno == ENOENT ? LOG_DEBUG : LOG_ERR, "Failed to open configuration file '%s': %m", filename);
344 return errno == ENOENT ? 0 : -errno;
348 fd_warn_permissions(filename, fileno(f));
351 char l[LINE_MAX], *p, *c = NULL, *e;
352 bool escaped = false;
354 if (!fgets(l, sizeof(l), f)) {
358 log_error("Failed to read configuration file '%s': %m", filename);
365 c = strappend(continuation, l);
375 for (e = p; *e; e++) {
388 continuation = strdup(l);
418 #define DEFINE_PARSER(type, vartype, conv_func) \
419 int config_parse_##type(const char *unit, \
420 const char *filename, \
422 const char *section, \
423 unsigned section_line, \
424 const char *lvalue, \
426 const char *rvalue, \
438 r = conv_func(rvalue, i); \
440 log_syntax(unit, LOG_ERR, filename, line, -r, \
441 "Failed to parse %s value, ignoring: %s", \
447 DEFINE_PARSER(int, int, safe_atoi)
448 DEFINE_PARSER(long, long, safe_atoli)
449 DEFINE_PARSER(uint64, uint64_t, safe_atou64)
450 DEFINE_PARSER(unsigned, unsigned, safe_atou)
451 DEFINE_PARSER(double, double, safe_atod)
452 DEFINE_PARSER(nsec, nsec_t, parse_nsec)
453 DEFINE_PARSER(sec, usec_t, parse_sec)
455 int config_parse_iec_size(const char* unit,
456 const char *filename,
459 unsigned section_line,
475 r = parse_size(rvalue, 1024, &o);
476 if (r < 0 || (off_t) (size_t) o != o) {
477 log_syntax(unit, LOG_ERR, filename, line, r < 0 ? -r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue);
485 int config_parse_si_size(const char* unit,
486 const char *filename,
489 unsigned section_line,
505 r = parse_size(rvalue, 1000, &o);
506 if (r < 0 || (off_t) (size_t) o != o) {
507 log_syntax(unit, LOG_ERR, filename, line, r < 0 ? -r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue);
515 int config_parse_iec_off(const char* unit,
516 const char *filename,
519 unsigned section_line,
534 assert_cc(sizeof(off_t) == sizeof(uint64_t));
536 r = parse_size(rvalue, 1024, bytes);
538 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to parse size value, ignoring: %s", rvalue);
543 int config_parse_bool(const char* unit,
544 const char *filename,
547 unsigned section_line,
562 k = parse_boolean(rvalue);
564 log_syntax(unit, LOG_ERR, filename, line, -k,
565 "Failed to parse boolean value, ignoring: %s", rvalue);
573 int config_parse_string(
575 const char *filename,
578 unsigned section_line,
592 if (!utf8_is_valid(rvalue)) {
593 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
611 int config_parse_path(
613 const char *filename,
616 unsigned section_line,
630 if (!utf8_is_valid(rvalue)) {
631 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
635 if (!path_is_absolute(rvalue)) {
636 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Not an absolute path, ignoring: %s", rvalue);
644 path_kill_slashes(n);
652 int config_parse_strv(const char *unit,
653 const char *filename,
656 unsigned section_line,
663 char *** sv = data, *w, *state;
672 if (isempty(rvalue)) {
675 /* Empty assignment resets the list. As a special rule
676 * we actually fill in a real empty array here rather
677 * than NULL, since some code wants to know if
678 * something was set at all... */
679 empty = strv_new(NULL, NULL);
688 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
695 if (!utf8_is_valid(n)) {
696 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
700 r = strv_consume(sv, n);
708 int config_parse_mode(const char *unit,
709 const char *filename,
712 unsigned section_line,
729 l = strtol(rvalue, &x, 8);
730 if (!x || x == rvalue || *x || errno) {
731 log_syntax(unit, LOG_ERR, filename, line, errno,
732 "Failed to parse mode value, ignoring: %s", rvalue);
736 if (l < 0000 || l > 07777) {
737 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
738 "Mode value out of range, ignoring: %s", rvalue);
746 int config_parse_log_facility(
748 const char *filename,
751 unsigned section_line,
766 x = log_facility_unshifted_from_string(rvalue);
768 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
769 "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,
801 "Failed to parse log level, ignoring: %s", rvalue);
805 *o = (*o & LOG_FACMASK) | x;