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,
222 if (strchr(COMMENTS "\n", *l))
225 if (startswith(l, ".include ")) {
226 _cleanup_free_ char *fn = NULL;
228 /* .includes are a bad idea, we only support them here
229 * for historical reasons. They create cyclic include
230 * problems and make it difficult to detect
231 * configuration file changes with an easy
232 * stat(). Better approaches, such as .d/ drop-in
235 * Support for them should be eventually removed. */
237 if (!allow_include) {
238 log_syntax(unit, LOG_ERR, filename, line, EBADMSG,
239 ".include not allowed here. Ignoring.");
243 fn = file_in_same_dir(filename, strstrip(l+9));
247 return config_parse(unit, fn, NULL, sections, lookup, table, relaxed, false, userdata);
258 log_syntax(unit, LOG_ERR, filename, line, EBADMSG,
259 "Invalid section header '%s'", l);
263 n = strndup(l+1, k-2);
267 if (sections && !nulstr_contains(sections, n)) {
270 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
271 "Unknown section '%s'. Ignoring.", n);
280 *section_line = line;
286 if (sections && !*section) {
289 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
290 "Assignment outside of section. Ignoring.");
297 log_syntax(unit, LOG_WARNING, filename, line, EINVAL, "Missing '='.");
304 return next_assignment(unit,
317 /* Go through the file and parse each line */
318 int config_parse(const char *unit,
319 const char *filename,
321 const char *sections,
322 ConfigItemLookup lookup,
328 _cleanup_free_ char *section = NULL, *continuation = NULL;
329 _cleanup_fclose_ FILE *ours = NULL;
330 unsigned line = 0, section_line = 0;
337 f = ours = fopen(filename, "re");
339 log_error("Failed to open configuration file '%s': %m", filename);
344 fd_warn_permissions(filename, fileno(f));
347 char l[LINE_MAX], *p, *c = NULL, *e;
348 bool escaped = false;
350 if (!fgets(l, sizeof(l), f)) {
354 log_error("Failed to read configuration file '%s': %m", filename);
361 c = strappend(continuation, l);
371 for (e = p; *e; e++) {
384 continuation = strdup(l);
413 #define DEFINE_PARSER(type, vartype, conv_func) \
414 int config_parse_##type(const char *unit, \
415 const char *filename, \
417 const char *section, \
418 unsigned section_line, \
419 const char *lvalue, \
421 const char *rvalue, \
433 r = conv_func(rvalue, i); \
435 log_syntax(unit, LOG_ERR, filename, line, -r, \
436 "Failed to parse %s value, ignoring: %s", \
442 DEFINE_PARSER(int, int, safe_atoi)
443 DEFINE_PARSER(long, long, safe_atoli)
444 DEFINE_PARSER(uint64, uint64_t, safe_atou64)
445 DEFINE_PARSER(unsigned, unsigned, safe_atou)
446 DEFINE_PARSER(double, double, safe_atod)
447 DEFINE_PARSER(nsec, nsec_t, parse_nsec)
448 DEFINE_PARSER(sec, usec_t, parse_sec)
450 int config_parse_iec_size(const char* unit,
451 const char *filename,
454 unsigned section_line,
470 r = parse_size(rvalue, 1024, &o);
471 if (r < 0 || (off_t) (size_t) o != o) {
472 log_syntax(unit, LOG_ERR, filename, line, r < 0 ? -r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue);
480 int config_parse_si_size(const char* unit,
481 const char *filename,
484 unsigned section_line,
500 r = parse_size(rvalue, 1000, &o);
501 if (r < 0 || (off_t) (size_t) o != o) {
502 log_syntax(unit, LOG_ERR, filename, line, r < 0 ? -r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue);
510 int config_parse_iec_off(const char* unit,
511 const char *filename,
514 unsigned section_line,
529 assert_cc(sizeof(off_t) == sizeof(uint64_t));
531 r = parse_size(rvalue, 1024, bytes);
533 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to parse size value, ignoring: %s", rvalue);
538 int config_parse_bool(const char* unit,
539 const char *filename,
542 unsigned section_line,
557 k = parse_boolean(rvalue);
559 log_syntax(unit, LOG_ERR, filename, line, -k,
560 "Failed to parse boolean value, ignoring: %s", rvalue);
568 int config_parse_string(
570 const char *filename,
573 unsigned section_line,
587 if (!utf8_is_valid(rvalue)) {
588 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
606 int config_parse_path(
608 const char *filename,
611 unsigned section_line,
625 if (!utf8_is_valid(rvalue)) {
626 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
630 if (!path_is_absolute(rvalue)) {
631 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Not an absolute path, ignoring: %s", rvalue);
639 path_kill_slashes(n);
647 int config_parse_strv(const char *unit,
648 const char *filename,
651 unsigned section_line,
658 char *** sv = data, *w, *state;
667 if (isempty(rvalue)) {
670 /* Empty assignment resets the list. As a special rule
671 * we actually fill in a real empty array here rather
672 * than NULL, since some code wants to know if
673 * something was set at all... */
674 empty = strv_new(NULL, NULL);
683 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
686 n = cunescape_length(w, l);
690 if (!utf8_is_valid(n)) {
691 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
695 r = strv_consume(sv, n);
703 int config_parse_mode(const char *unit,
704 const char *filename,
707 unsigned section_line,
724 l = strtol(rvalue, &x, 8);
725 if (!x || x == rvalue || *x || errno) {
726 log_syntax(unit, LOG_ERR, filename, line, errno,
727 "Failed to parse mode value, ignoring: %s", rvalue);
731 if (l < 0000 || l > 07777) {
732 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
733 "Mode value out of range, ignoring: %s", rvalue);
741 int config_parse_log_facility(
743 const char *filename,
746 unsigned section_line,
761 x = log_facility_unshifted_from_string(rvalue);
763 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
764 "Failed to parse log facility, ignoring: %s", rvalue);
768 *o = (x << 3) | LOG_PRI(*o);
773 int config_parse_log_level(
775 const char *filename,
778 unsigned section_line,
793 x = log_level_from_string(rvalue);
795 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
796 "Failed to parse log level, ignoring: %s", rvalue);
800 *o = (*o & LOG_FACMASK) | x;