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 config_item_table_lookup(
41 ConfigParserCallback *func,
46 const ConfigTableItem *t;
54 for (t = table; t->lvalue; t++) {
56 if (!streq(lvalue, t->lvalue))
59 if (!streq_ptr(section, t->section))
71 int config_item_perf_lookup(
75 ConfigParserCallback *func,
80 ConfigPerfItemLookup lookup = (ConfigPerfItemLookup) table;
81 const ConfigPerfItem *p;
90 p = lookup(lvalue, strlen(lvalue));
94 key = strjoin(section, ".", lvalue, NULL);
98 p = lookup(key, strlen(key));
107 *data = (uint8_t*) userdata + p->offset;
111 /* Run the user supplied parser for an assignment */
112 static int next_assignment(const char *unit,
113 const char *filename,
115 ConfigItemLookup lookup,
118 unsigned section_line,
124 ConfigParserCallback func = NULL;
135 r = lookup(table, section, lvalue, &func, <ype, &data, userdata);
141 return func(unit, filename, line, section, section_line,
142 lvalue, ltype, rvalue, data, userdata);
147 /* Warn about unknown non-extension fields. */
148 if (!relaxed && !startswith(lvalue, "X-"))
149 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
150 "Unknown lvalue '%s' in section '%s'", lvalue, section);
155 /* Parse a variable assignment line */
156 static int parse_line(const char* unit,
157 const char *filename,
159 const char *sections,
160 ConfigItemLookup lookup,
165 unsigned *section_line,
166 bool *section_ignored,
182 if (strchr(COMMENTS "\n", *l))
185 if (startswith(l, ".include ")) {
186 _cleanup_free_ char *fn = NULL;
188 /* .includes are a bad idea, we only support them here
189 * for historical reasons. They create cyclic include
190 * problems and make it difficult to detect
191 * configuration file changes with an easy
192 * stat(). Better approaches, such as .d/ drop-in
195 * Support for them should be eventually removed. */
197 if (!allow_include) {
198 log_syntax(unit, LOG_ERR, filename, line, EBADMSG,
199 ".include not allowed here. Ignoring.");
203 fn = file_in_same_dir(filename, strstrip(l+9));
207 return config_parse(unit, fn, NULL, sections, lookup, table, relaxed, false, false, userdata);
218 log_syntax(unit, LOG_ERR, filename, line, EBADMSG,
219 "Invalid section header '%s'", l);
223 n = strndup(l+1, k-2);
227 if (sections && !nulstr_contains(sections, n)) {
229 if (!relaxed && !startswith(n, "X-"))
230 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
231 "Unknown section '%s'. Ignoring.", n);
237 *section_ignored = true;
241 *section_line = line;
242 *section_ignored = false;
248 if (sections && !*section) {
250 if (!relaxed && !*section_ignored)
251 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
252 "Assignment outside of section. Ignoring.");
259 log_syntax(unit, LOG_WARNING, filename, line, EINVAL, "Missing '='.");
266 return next_assignment(unit,
279 /* Go through the file and parse each line */
280 int config_parse(const char *unit,
281 const char *filename,
283 const char *sections,
284 ConfigItemLookup lookup,
291 _cleanup_free_ char *section = NULL, *continuation = NULL;
292 _cleanup_fclose_ FILE *ours = NULL;
293 unsigned line = 0, section_line = 0;
294 bool section_ignored = false;
301 f = ours = fopen(filename, "re");
303 /* Only log on request, except for ENOENT,
304 * since we return 0 to the caller. */
305 if (warn || errno == ENOENT)
306 log_full(errno == ENOENT ? LOG_DEBUG : LOG_ERR,
307 "Failed to open configuration file '%s': %m", filename);
308 return errno == ENOENT ? 0 : -errno;
312 fd_warn_permissions(filename, fileno(f));
315 char l[LINE_MAX], *p, *c = NULL, *e;
316 bool escaped = false;
318 if (!fgets(l, sizeof(l), f)) {
322 log_error_errno(errno, "Failed to read configuration file '%s': %m", filename);
329 c = strappend(continuation, l);
342 for (e = p; *e; e++) {
355 continuation = strdup(l);
383 log_warning_errno(r, "Failed to parse file '%s': %m",
392 /* Parse each config file in the specified directories. */
393 int config_parse_many(const char *conf_file,
394 const char *conf_file_dirs,
395 const char *sections,
396 ConfigItemLookup lookup,
400 _cleanup_strv_free_ char **files = NULL;
404 r = conf_files_list_nulstr(&files, ".conf", NULL, conf_file_dirs);
409 r = config_parse(NULL, conf_file, NULL, sections, lookup, table, relaxed, false, true, userdata);
414 STRV_FOREACH(fn, files) {
415 r = config_parse(NULL, *fn, NULL, sections, lookup, table, relaxed, false, true, userdata);
423 #define DEFINE_PARSER(type, vartype, conv_func) \
424 int config_parse_##type(const char *unit, \
425 const char *filename, \
427 const char *section, \
428 unsigned section_line, \
429 const char *lvalue, \
431 const char *rvalue, \
443 r = conv_func(rvalue, i); \
445 log_syntax(unit, LOG_ERR, filename, line, -r, \
446 "Failed to parse %s value, ignoring: %s", \
452 DEFINE_PARSER(int, int, safe_atoi)
453 DEFINE_PARSER(long, long, safe_atoli)
454 DEFINE_PARSER(uint64, uint64_t, safe_atou64)
455 DEFINE_PARSER(unsigned, unsigned, safe_atou)
456 DEFINE_PARSER(double, double, safe_atod)
457 DEFINE_PARSER(nsec, nsec_t, parse_nsec)
458 DEFINE_PARSER(sec, usec_t, parse_sec)
460 int config_parse_iec_size(const char* unit,
461 const char *filename,
464 unsigned section_line,
480 r = parse_size(rvalue, 1024, &o);
481 if (r < 0 || (off_t) (size_t) o != o) {
482 log_syntax(unit, LOG_ERR, filename, line, r < 0 ? -r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue);
490 /// UNNEEDED by elogind
492 int config_parse_si_size(const char* unit,
493 const char *filename,
496 unsigned section_line,
512 r = parse_size(rvalue, 1000, &o);
513 if (r < 0 || (off_t) (size_t) o != o) {
514 log_syntax(unit, LOG_ERR, filename, line, r < 0 ? -r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue);
522 int config_parse_iec_off(const char* unit,
523 const char *filename,
526 unsigned section_line,
541 assert_cc(sizeof(off_t) == sizeof(uint64_t));
543 r = parse_size(rvalue, 1024, bytes);
545 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to parse size value, ignoring: %s", rvalue);
551 int config_parse_bool(const char* unit,
552 const char *filename,
555 unsigned section_line,
570 k = parse_boolean(rvalue);
572 log_syntax(unit, LOG_ERR, filename, line, -k,
573 "Failed to parse boolean value, ignoring: %s", rvalue);
581 int config_parse_string(
583 const char *filename,
586 unsigned section_line,
600 if (!utf8_is_valid(rvalue)) {
601 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
619 int config_parse_path(
621 const char *filename,
624 unsigned section_line,
638 if (!utf8_is_valid(rvalue)) {
639 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
643 if (!path_is_absolute(rvalue)) {
644 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Not an absolute path, ignoring: %s", rvalue);
652 path_kill_slashes(n);
660 int config_parse_strv(const char *unit,
661 const char *filename,
664 unsigned section_line,
672 const char *word, *state;
681 if (isempty(rvalue)) {
684 /* Empty assignment resets the list. As a special rule
685 * we actually fill in a real empty array here rather
686 * than NULL, since some code wants to know if
687 * something was set at all... */
688 empty = strv_new(NULL, NULL);
697 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
700 n = strndup(word, l);
704 if (!utf8_is_valid(n)) {
705 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
710 r = strv_consume(sv, n);
715 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
716 "Trailing garbage, ignoring.");
721 int config_parse_mode(
723 const char *filename,
726 unsigned section_line,
740 if (parse_mode(rvalue, m) < 0) {
741 log_syntax(unit, LOG_ERR, filename, line, errno, "Failed to parse mode value, ignoring: %s", rvalue);
748 int config_parse_log_facility(
750 const char *filename,
753 unsigned section_line,
768 x = log_facility_unshifted_from_string(rvalue);
770 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse log facility, ignoring: %s", rvalue);
774 *o = (x << 3) | LOG_PRI(*o);
779 int config_parse_log_level(
781 const char *filename,
784 unsigned section_line,
799 x = log_level_from_string(rvalue);
801 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse log level, ignoring: %s", rvalue);
805 *o = (*o & LOG_FACMASK) | x;