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 "conf-parser.h"
28 #include "conf-files.h"
34 #include "path-util.h"
35 #include "sd-messages.h"
37 int log_syntax_internal(
43 const char *config_file,
46 const char *format, ...) {
48 _cleanup_free_ char *msg = NULL;
53 r = vasprintf(&msg, format, ap);
59 r = log_struct_internal(level,
62 getpid() == 1 ? "UNIT=%s" : "USER_UNIT=%s", unit,
63 LOG_MESSAGE_ID(SD_MESSAGE_CONFIG_ERROR),
64 "CONFIG_FILE=%s", config_file,
65 "CONFIG_LINE=%u", config_line,
66 LOG_MESSAGE("[%s:%u] %s", config_file, config_line, msg),
69 r = log_struct_internal(level,
72 LOG_MESSAGE_ID(SD_MESSAGE_CONFIG_ERROR),
73 "CONFIG_FILE=%s", config_file,
74 "CONFIG_LINE=%u", config_line,
75 LOG_MESSAGE("[%s:%u] %s", config_file, config_line, msg),
81 int config_item_table_lookup(
85 ConfigParserCallback *func,
90 const ConfigTableItem *t;
98 for (t = table; t->lvalue; t++) {
100 if (!streq(lvalue, t->lvalue))
103 if (!streq_ptr(section, t->section))
115 int config_item_perf_lookup(
119 ConfigParserCallback *func,
124 ConfigPerfItemLookup lookup = (ConfigPerfItemLookup) table;
125 const ConfigPerfItem *p;
134 p = lookup(lvalue, strlen(lvalue));
138 key = strjoin(section, ".", lvalue, NULL);
142 p = lookup(key, strlen(key));
151 *data = (uint8_t*) userdata + p->offset;
155 /* Run the user supplied parser for an assignment */
156 static int next_assignment(const char *unit,
157 const char *filename,
159 ConfigItemLookup lookup,
162 unsigned section_line,
168 ConfigParserCallback func = NULL;
179 r = lookup(table, section, lvalue, &func, <ype, &data, userdata);
185 return func(unit, filename, line, section, section_line,
186 lvalue, ltype, rvalue, data, userdata);
191 /* Warn about unknown non-extension fields. */
192 if (!relaxed && !startswith(lvalue, "X-"))
193 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
194 "Unknown lvalue '%s' in section '%s'", lvalue, section);
199 /* Parse a variable assignment line */
200 static int parse_line(const char* unit,
201 const char *filename,
203 const char *sections,
204 ConfigItemLookup lookup,
209 unsigned *section_line,
210 bool *section_ignored,
226 if (strchr(COMMENTS "\n", *l))
229 if (startswith(l, ".include ")) {
230 _cleanup_free_ char *fn = NULL;
232 /* .includes are a bad idea, we only support them here
233 * for historical reasons. They create cyclic include
234 * problems and make it difficult to detect
235 * configuration file changes with an easy
236 * stat(). Better approaches, such as .d/ drop-in
239 * Support for them should be eventually removed. */
241 if (!allow_include) {
242 log_syntax(unit, LOG_ERR, filename, line, EBADMSG,
243 ".include not allowed here. Ignoring.");
247 fn = file_in_same_dir(filename, strstrip(l+9));
251 return config_parse(unit, fn, NULL, sections, lookup, table, relaxed, false, false, userdata);
262 log_syntax(unit, LOG_ERR, filename, line, EBADMSG,
263 "Invalid section header '%s'", l);
267 n = strndup(l+1, k-2);
271 if (sections && !nulstr_contains(sections, n)) {
273 if (!relaxed && !startswith(n, "X-"))
274 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
275 "Unknown section '%s'. Ignoring.", n);
281 *section_ignored = true;
285 *section_line = line;
286 *section_ignored = false;
292 if (sections && !*section) {
294 if (!relaxed && !*section_ignored)
295 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
296 "Assignment outside of section. Ignoring.");
303 log_syntax(unit, LOG_WARNING, filename, line, EINVAL, "Missing '='.");
310 return next_assignment(unit,
323 /* Go through the file and parse each line */
324 int config_parse(const char *unit,
325 const char *filename,
327 const char *sections,
328 ConfigItemLookup lookup,
335 _cleanup_free_ char *section = NULL, *continuation = NULL;
336 _cleanup_fclose_ FILE *ours = NULL;
337 unsigned line = 0, section_line = 0;
338 bool section_ignored = false;
345 f = ours = fopen(filename, "re");
347 /* Only log on request, except for ENOENT,
348 * since we return 0 to the caller. */
349 if (warn || errno == ENOENT)
350 log_full(errno == ENOENT ? LOG_DEBUG : LOG_ERR,
351 "Failed to open configuration file '%s': %m", filename);
352 return errno == ENOENT ? 0 : -errno;
356 fd_warn_permissions(filename, fileno(f));
359 char l[LINE_MAX], *p, *c = NULL, *e;
360 bool escaped = false;
362 if (!fgets(l, sizeof(l), f)) {
366 log_error_errno(errno, "Failed to read configuration file '%s': %m", filename);
373 c = strappend(continuation, l);
386 for (e = p; *e; e++) {
399 continuation = strdup(l);
427 log_warning_errno(r, "Failed to parse file '%s': %m",
436 /* Parse each config file in the specified directories. */
437 int config_parse_many(const char *conf_file,
438 const char *conf_file_dirs,
439 const char *sections,
440 ConfigItemLookup lookup,
444 _cleanup_strv_free_ char **files = NULL;
448 r = conf_files_list_nulstr(&files, ".conf", NULL, conf_file_dirs);
453 r = config_parse(NULL, conf_file, NULL, sections, lookup, table, relaxed, false, true, userdata);
458 STRV_FOREACH(fn, files) {
459 r = config_parse(NULL, *fn, NULL, sections, lookup, table, relaxed, false, true, userdata);
467 #define DEFINE_PARSER(type, vartype, conv_func) \
468 int config_parse_##type(const char *unit, \
469 const char *filename, \
471 const char *section, \
472 unsigned section_line, \
473 const char *lvalue, \
475 const char *rvalue, \
487 r = conv_func(rvalue, i); \
489 log_syntax(unit, LOG_ERR, filename, line, -r, \
490 "Failed to parse %s value, ignoring: %s", \
496 DEFINE_PARSER(int, int, safe_atoi)
497 DEFINE_PARSER(long, long, safe_atoli)
498 DEFINE_PARSER(uint64, uint64_t, safe_atou64)
499 DEFINE_PARSER(unsigned, unsigned, safe_atou)
500 DEFINE_PARSER(double, double, safe_atod)
501 DEFINE_PARSER(nsec, nsec_t, parse_nsec)
502 DEFINE_PARSER(sec, usec_t, parse_sec)
504 int config_parse_iec_size(const char* unit,
505 const char *filename,
508 unsigned section_line,
524 r = parse_size(rvalue, 1024, &o);
525 if (r < 0 || (off_t) (size_t) o != o) {
526 log_syntax(unit, LOG_ERR, filename, line, r < 0 ? -r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue);
534 int config_parse_si_size(const char* unit,
535 const char *filename,
538 unsigned section_line,
554 r = parse_size(rvalue, 1000, &o);
555 if (r < 0 || (off_t) (size_t) o != o) {
556 log_syntax(unit, LOG_ERR, filename, line, r < 0 ? -r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue);
564 int config_parse_iec_off(const char* unit,
565 const char *filename,
568 unsigned section_line,
583 assert_cc(sizeof(off_t) == sizeof(uint64_t));
585 r = parse_size(rvalue, 1024, bytes);
587 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to parse size value, ignoring: %s", rvalue);
592 int config_parse_bool(const char* unit,
593 const char *filename,
596 unsigned section_line,
611 k = parse_boolean(rvalue);
613 log_syntax(unit, LOG_ERR, filename, line, -k,
614 "Failed to parse boolean value, ignoring: %s", rvalue);
622 int config_parse_string(
624 const char *filename,
627 unsigned section_line,
641 if (!utf8_is_valid(rvalue)) {
642 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
660 int config_parse_path(
662 const char *filename,
665 unsigned section_line,
679 if (!utf8_is_valid(rvalue)) {
680 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
684 if (!path_is_absolute(rvalue)) {
685 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Not an absolute path, ignoring: %s", rvalue);
693 path_kill_slashes(n);
701 int config_parse_strv(const char *unit,
702 const char *filename,
705 unsigned section_line,
713 const char *word, *state;
722 if (isempty(rvalue)) {
725 /* Empty assignment resets the list. As a special rule
726 * we actually fill in a real empty array here rather
727 * than NULL, since some code wants to know if
728 * something was set at all... */
729 empty = strv_new(NULL, NULL);
738 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
741 n = strndup(word, l);
745 if (!utf8_is_valid(n)) {
746 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
751 r = strv_consume(sv, n);
756 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
757 "Trailing garbage, ignoring.");
762 int config_parse_mode(const char *unit,
763 const char *filename,
766 unsigned section_line,
783 l = strtol(rvalue, &x, 8);
784 if (!x || x == rvalue || *x || errno) {
785 log_syntax(unit, LOG_ERR, filename, line, errno,
786 "Failed to parse mode value, ignoring: %s", rvalue);
790 if (l < 0000 || l > 07777) {
791 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
792 "Mode value out of range, ignoring: %s", rvalue);
800 int config_parse_log_facility(
802 const char *filename,
805 unsigned section_line,
820 x = log_facility_unshifted_from_string(rvalue);
822 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse log facility, ignoring: %s", rvalue);
826 *o = (x << 3) | LOG_PRI(*o);
831 int config_parse_log_level(
833 const char *filename,
836 unsigned section_line,
851 x = log_level_from_string(rvalue);
853 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse log level, ignoring: %s", rvalue);
857 *o = (*o & LOG_FACMASK) | x;