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(
47 const char *config_file,
50 const char *format, ...) {
52 _cleanup_free_ char *msg = NULL;
57 r = vasprintf(&msg, format, ap);
63 r = log_struct_internal(level,
64 error > 0 ? error : EINVAL,
66 getpid() == 1 ? "UNIT=%s" : "USER_UNIT=%s", unit,
67 LOG_MESSAGE_ID(SD_MESSAGE_CONFIG_ERROR),
68 "CONFIG_FILE=%s", config_file,
69 "CONFIG_LINE=%u", config_line,
70 LOG_MESSAGE("[%s:%u] %s", config_file, config_line, msg),
73 r = log_struct_internal(level,
74 error > 0 ? error : EINVAL,
76 LOG_MESSAGE_ID(SD_MESSAGE_CONFIG_ERROR),
77 "CONFIG_FILE=%s", config_file,
78 "CONFIG_LINE=%u", config_line,
79 LOG_MESSAGE("[%s:%u] %s", config_file, config_line, msg),
85 int config_item_table_lookup(
89 ConfigParserCallback *func,
94 const ConfigTableItem *t;
102 for (t = table; t->lvalue; t++) {
104 if (!streq(lvalue, t->lvalue))
107 if (!streq_ptr(section, t->section))
119 int config_item_perf_lookup(
123 ConfigParserCallback *func,
128 ConfigPerfItemLookup lookup = (ConfigPerfItemLookup) table;
129 const ConfigPerfItem *p;
138 p = lookup(lvalue, strlen(lvalue));
142 key = strjoin(section, ".", lvalue, NULL);
146 p = lookup(key, strlen(key));
155 *data = (uint8_t*) userdata + p->offset;
159 /* Run the user supplied parser for an assignment */
160 static int next_assignment(const char *unit,
161 const char *filename,
163 ConfigItemLookup lookup,
166 unsigned section_line,
172 ConfigParserCallback func = NULL;
183 r = lookup(table, section, lvalue, &func, <ype, &data, userdata);
189 return func(unit, filename, line, section, section_line,
190 lvalue, ltype, rvalue, data, userdata);
195 /* Warn about unknown non-extension fields. */
196 if (!relaxed && !startswith(lvalue, "X-"))
197 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
198 "Unknown lvalue '%s' in section '%s'", lvalue, section);
203 /* Parse a variable assignment line */
204 static int parse_line(const char* unit,
205 const char *filename,
207 const char *sections,
208 ConfigItemLookup lookup,
213 unsigned *section_line,
214 bool *section_ignored,
230 if (strchr(COMMENTS "\n", *l))
233 if (startswith(l, ".include ")) {
234 _cleanup_free_ char *fn = NULL;
236 /* .includes are a bad idea, we only support them here
237 * for historical reasons. They create cyclic include
238 * problems and make it difficult to detect
239 * configuration file changes with an easy
240 * stat(). Better approaches, such as .d/ drop-in
243 * Support for them should be eventually removed. */
245 if (!allow_include) {
246 log_syntax(unit, LOG_ERR, filename, line, EBADMSG,
247 ".include not allowed here. Ignoring.");
251 fn = file_in_same_dir(filename, strstrip(l+9));
255 return config_parse(unit, fn, NULL, sections, lookup, table, relaxed, false, false, userdata);
266 log_syntax(unit, LOG_ERR, filename, line, EBADMSG,
267 "Invalid section header '%s'", l);
271 n = strndup(l+1, k-2);
275 if (sections && !nulstr_contains(sections, n)) {
277 if (!relaxed && !startswith(n, "X-"))
278 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
279 "Unknown section '%s'. Ignoring.", n);
285 *section_ignored = true;
289 *section_line = line;
290 *section_ignored = false;
296 if (sections && !*section) {
298 if (!relaxed && !*section_ignored)
299 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
300 "Assignment outside of section. Ignoring.");
307 log_syntax(unit, LOG_WARNING, filename, line, EINVAL, "Missing '='.");
314 return next_assignment(unit,
327 /* Go through the file and parse each line */
328 int config_parse(const char *unit,
329 const char *filename,
331 const char *sections,
332 ConfigItemLookup lookup,
339 _cleanup_free_ char *section = NULL, *continuation = NULL;
340 _cleanup_fclose_ FILE *ours = NULL;
341 unsigned line = 0, section_line = 0;
342 bool section_ignored = false;
349 f = ours = fopen(filename, "re");
351 /* Only log on request, except for ENOENT,
352 * since we return 0 to the caller. */
353 if (warn || errno == ENOENT)
354 log_full(errno == ENOENT ? LOG_DEBUG : LOG_ERR,
355 "Failed to open configuration file '%s': %m", filename);
356 return errno == ENOENT ? 0 : -errno;
360 fd_warn_permissions(filename, fileno(f));
363 char l[LINE_MAX], *p, *c = NULL, *e;
364 bool escaped = false;
366 if (!fgets(l, sizeof(l), f)) {
370 log_error_errno(errno, "Failed to read configuration file '%s': %m", filename);
377 c = strappend(continuation, l);
390 for (e = p; *e; e++) {
403 continuation = strdup(l);
431 log_warning_errno(r, "Failed to parse file '%s': %m",
440 /* Parse each config file in the specified directories. */
441 int config_parse_many(const char *conf_file,
442 const char *conf_file_dirs,
443 const char *sections,
444 ConfigItemLookup lookup,
448 _cleanup_strv_free_ char **files = NULL;
452 r = conf_files_list_nulstr(&files, ".conf", NULL, conf_file_dirs);
457 r = config_parse(NULL, conf_file, NULL, sections, lookup, table, relaxed, false, true, userdata);
462 STRV_FOREACH(fn, files) {
463 r = config_parse(NULL, *fn, NULL, sections, lookup, table, relaxed, false, true, userdata);
471 #define DEFINE_PARSER(type, vartype, conv_func) \
472 int config_parse_##type(const char *unit, \
473 const char *filename, \
475 const char *section, \
476 unsigned section_line, \
477 const char *lvalue, \
479 const char *rvalue, \
491 r = conv_func(rvalue, i); \
493 log_syntax(unit, LOG_ERR, filename, line, -r, \
494 "Failed to parse %s value, ignoring: %s", \
500 DEFINE_PARSER(int, int, safe_atoi)
501 DEFINE_PARSER(long, long, safe_atoli)
502 DEFINE_PARSER(uint64, uint64_t, safe_atou64)
503 DEFINE_PARSER(unsigned, unsigned, safe_atou)
504 DEFINE_PARSER(double, double, safe_atod)
505 DEFINE_PARSER(nsec, nsec_t, parse_nsec)
506 DEFINE_PARSER(sec, usec_t, parse_sec)
508 int config_parse_iec_size(const char* unit,
509 const char *filename,
512 unsigned section_line,
528 r = parse_size(rvalue, 1024, &o);
529 if (r < 0 || (off_t) (size_t) o != o) {
530 log_syntax(unit, LOG_ERR, filename, line, r < 0 ? -r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue);
538 int config_parse_si_size(const char* unit,
539 const char *filename,
542 unsigned section_line,
558 r = parse_size(rvalue, 1000, &o);
559 if (r < 0 || (off_t) (size_t) o != o) {
560 log_syntax(unit, LOG_ERR, filename, line, r < 0 ? -r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue);
568 int config_parse_iec_off(const char* unit,
569 const char *filename,
572 unsigned section_line,
587 assert_cc(sizeof(off_t) == sizeof(uint64_t));
589 r = parse_size(rvalue, 1024, bytes);
591 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to parse size value, ignoring: %s", rvalue);
596 int config_parse_bool(const char* unit,
597 const char *filename,
600 unsigned section_line,
615 k = parse_boolean(rvalue);
617 log_syntax(unit, LOG_ERR, filename, line, -k,
618 "Failed to parse boolean value, ignoring: %s", rvalue);
626 int config_parse_string(
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);
664 int config_parse_path(
666 const char *filename,
669 unsigned section_line,
683 if (!utf8_is_valid(rvalue)) {
684 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
688 if (!path_is_absolute(rvalue)) {
689 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Not an absolute path, ignoring: %s", rvalue);
697 path_kill_slashes(n);
705 int config_parse_strv(const char *unit,
706 const char *filename,
709 unsigned section_line,
717 const char *word, *state;
726 if (isempty(rvalue)) {
729 /* Empty assignment resets the list. As a special rule
730 * we actually fill in a real empty array here rather
731 * than NULL, since some code wants to know if
732 * something was set at all... */
733 empty = strv_new(NULL, NULL);
742 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
745 n = strndup(word, l);
749 if (!utf8_is_valid(n)) {
750 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
755 r = strv_consume(sv, n);
760 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
761 "Trailing garbage, ignoring.");
766 int config_parse_mode(const char *unit,
767 const char *filename,
770 unsigned section_line,
787 l = strtol(rvalue, &x, 8);
788 if (!x || x == rvalue || *x || errno) {
789 log_syntax(unit, LOG_ERR, filename, line, errno,
790 "Failed to parse mode value, ignoring: %s", rvalue);
794 if (l < 0000 || l > 07777) {
795 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
796 "Mode value out of range, ignoring: %s", rvalue);
804 int config_parse_log_facility(
806 const char *filename,
809 unsigned section_line,
824 x = log_facility_unshifted_from_string(rvalue);
826 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
827 "Failed to parse log facility, ignoring: %s", rvalue);
831 *o = (x << 3) | LOG_PRI(*o);
836 int config_parse_log_level(
838 const char *filename,
841 unsigned section_line,
856 x = log_level_from_string(rvalue);
858 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
859 "Failed to parse log level, ignoring: %s", rvalue);
863 *o = (*o & LOG_FACMASK) | x;