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 "sd-messages.h"
29 #include "alloc-util.h"
30 #include "conf-files.h"
31 #include "conf-parser.h"
36 #include "parse-util.h"
37 #include "path-util.h"
38 #include "process-util.h"
39 #include "signal-util.h"
40 #include "string-util.h"
42 #include "syslog-util.h"
46 int config_item_table_lookup(
50 ConfigParserCallback *func,
55 const ConfigTableItem *t;
63 for (t = table; t->lvalue; t++) {
65 if (!streq(lvalue, t->lvalue))
68 if (!streq_ptr(section, t->section))
80 int config_item_perf_lookup(
84 ConfigParserCallback *func,
89 ConfigPerfItemLookup lookup = (ConfigPerfItemLookup) table;
90 const ConfigPerfItem *p;
99 p = lookup(lvalue, strlen(lvalue));
103 key = strjoin(section, ".", lvalue, NULL);
107 p = lookup(key, strlen(key));
116 *data = (uint8_t*) userdata + p->offset;
120 /* Run the user supplied parser for an assignment */
121 static int next_assignment(const char *unit,
122 const char *filename,
124 ConfigItemLookup lookup,
127 unsigned section_line,
133 ConfigParserCallback func = NULL;
144 r = lookup(table, section, lvalue, &func, <ype, &data, userdata);
150 return func(unit, filename, line, section, section_line,
151 lvalue, ltype, rvalue, data, userdata);
156 /* Warn about unknown non-extension fields. */
157 if (!relaxed && !startswith(lvalue, "X-"))
158 log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown lvalue '%s' in section '%s'", lvalue, section);
163 /* Parse a variable assignment line */
164 static int parse_line(const char* unit,
165 const char *filename,
167 const char *sections,
168 ConfigItemLookup lookup,
173 unsigned *section_line,
174 bool *section_ignored,
190 if (strchr(COMMENTS "\n", *l))
193 if (startswith(l, ".include ")) {
194 _cleanup_free_ char *fn = NULL;
196 /* .includes are a bad idea, we only support them here
197 * for historical reasons. They create cyclic include
198 * problems and make it difficult to detect
199 * configuration file changes with an easy
200 * stat(). Better approaches, such as .d/ drop-in
203 * Support for them should be eventually removed. */
205 if (!allow_include) {
206 log_syntax(unit, LOG_ERR, filename, line, 0, ".include not allowed here. Ignoring.");
210 fn = file_in_same_dir(filename, strstrip(l+9));
214 return config_parse(unit, fn, NULL, sections, lookup, table, relaxed, false, false, userdata);
225 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid section header '%s'", l);
229 n = strndup(l+1, k-2);
233 if (sections && !nulstr_contains(sections, n)) {
235 if (!relaxed && !startswith(n, "X-"))
236 log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown section '%s'. Ignoring.", n);
239 *section = mfree(*section);
241 *section_ignored = true;
245 *section_line = line;
246 *section_ignored = false;
252 if (sections && !*section) {
254 if (!relaxed && !*section_ignored)
255 log_syntax(unit, LOG_WARNING, filename, line, 0, "Assignment outside of section. Ignoring.");
262 log_syntax(unit, LOG_WARNING, filename, line, 0, "Missing '='.");
269 return next_assignment(unit,
282 /* Go through the file and parse each line */
283 int config_parse(const char *unit,
284 const char *filename,
286 const char *sections,
287 ConfigItemLookup lookup,
294 _cleanup_free_ char *section = NULL, *continuation = NULL;
295 _cleanup_fclose_ FILE *ours = NULL;
296 unsigned line = 0, section_line = 0;
297 bool section_ignored = false;
304 f = ours = fopen(filename, "re");
306 /* Only log on request, except for ENOENT,
307 * since we return 0 to the caller. */
308 if (warn || errno == ENOENT)
309 log_full(errno == ENOENT ? LOG_DEBUG : LOG_ERR,
310 "Failed to open configuration file '%s': %m", filename);
311 return errno == ENOENT ? 0 : -errno;
315 fd_warn_permissions(filename, fileno(f));
318 char l[LINE_MAX], *p, *c = NULL, *e;
319 bool escaped = false;
321 if (!fgets(l, sizeof(l), f)) {
325 log_error_errno(errno, "Failed to read configuration file '%s': %m", filename);
332 c = strappend(continuation, l);
339 continuation = mfree(continuation);
344 for (e = p; *e; e++) {
357 continuation = strdup(l);
385 log_warning_errno(r, "Failed to parse file '%s': %m",
394 /* Parse each config file in the specified directories. */
395 int config_parse_many(const char *conf_file,
396 const char *conf_file_dirs,
397 const char *sections,
398 ConfigItemLookup lookup,
402 _cleanup_strv_free_ char **files = NULL;
406 r = conf_files_list_nulstr(&files, ".conf", NULL, conf_file_dirs);
411 r = config_parse(NULL, conf_file, NULL, sections, lookup, table, relaxed, false, true, userdata);
416 STRV_FOREACH(fn, files) {
417 r = config_parse(NULL, *fn, NULL, sections, lookup, table, relaxed, false, true, userdata);
425 #define DEFINE_PARSER(type, vartype, conv_func) \
426 int config_parse_##type( \
428 const char *filename, \
430 const char *section, \
431 unsigned section_line, \
432 const char *lvalue, \
434 const char *rvalue, \
446 r = conv_func(rvalue, i); \
448 log_syntax(unit, LOG_ERR, filename, line, r, \
449 "Failed to parse %s value, ignoring: %s", \
454 struct __useless_struct_to_allow_trailing_semicolon__
456 DEFINE_PARSER(int, int, safe_atoi);
457 DEFINE_PARSER(long, long, safe_atoli);
458 DEFINE_PARSER(uint32, uint32_t, safe_atou32);
459 DEFINE_PARSER(uint64, uint64_t, safe_atou64);
460 DEFINE_PARSER(unsigned, unsigned, safe_atou);
461 DEFINE_PARSER(double, double, safe_atod);
462 #if 0 /// UNNEEDED by elogind
463 DEFINE_PARSER(nsec, nsec_t, parse_nsec);
465 DEFINE_PARSER(sec, usec_t, parse_sec);
466 DEFINE_PARSER(mode, mode_t, parse_mode);
468 int config_parse_iec_size(const char* unit,
469 const char *filename,
472 unsigned section_line,
488 r = parse_size(rvalue, 1024, &v);
489 if (r < 0 || (uint64_t) (size_t) v != v) {
490 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue);
498 #if 0 /// UNNEEDED by elogind
499 int config_parse_si_size(const char* unit,
500 const char *filename,
503 unsigned section_line,
519 r = parse_size(rvalue, 1000, &v);
520 if (r < 0 || (uint64_t) (size_t) v != v) {
521 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue);
529 int config_parse_iec_uint64(const char* unit,
530 const char *filename,
533 unsigned section_line,
540 uint64_t *bytes = data;
548 r = parse_size(rvalue, 1024, bytes);
550 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue);
556 int config_parse_bool(const char* unit,
557 const char *filename,
560 unsigned section_line,
575 k = parse_boolean(rvalue);
577 log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse boolean value, ignoring: %s", rvalue);
585 #if 0 /// UNNEEDED by elogind
586 int config_parse_tristate(
588 const char *filename,
591 unsigned section_line,
605 /* A tristate is pretty much a boolean, except that it can
606 * also take the special value -1, indicating "uninitialized",
607 * much like NULL is for a pointer type. */
609 k = parse_boolean(rvalue);
611 log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse boolean value, ignoring: %s", rvalue);
620 int config_parse_string(
622 const char *filename,
625 unsigned section_line,
639 if (!utf8_is_valid(rvalue)) {
640 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
658 int config_parse_path(
660 const char *filename,
663 unsigned section_line,
677 if (!utf8_is_valid(rvalue)) {
678 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
682 if (!path_is_absolute(rvalue)) {
683 log_syntax(unit, LOG_ERR, filename, line, 0, "Not an absolute path, ignoring: %s", rvalue);
691 path_kill_slashes(n);
699 int config_parse_strv(const char *unit,
700 const char *filename,
703 unsigned section_line,
717 if (isempty(rvalue)) {
720 /* Empty assignment resets the list. As a special rule
721 * we actually fill in a real empty array here rather
722 * than NULL, since some code wants to know if
723 * something was set at all... */
724 empty = strv_new(NULL, NULL);
736 r = extract_first_word(&rvalue, &word, WHITESPACE, EXTRACT_QUOTES);
742 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
746 if (!utf8_is_valid(word)) {
747 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
751 r = strv_consume(sv, word);
759 #if 0 /// UNNEEDED by elogind
760 int config_parse_log_facility(
762 const char *filename,
765 unsigned section_line,
780 x = log_facility_unshifted_from_string(rvalue);
782 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse log facility, ignoring: %s", rvalue);
786 *o = (x << 3) | LOG_PRI(*o);
792 int config_parse_log_level(
794 const char *filename,
797 unsigned section_line,
812 x = log_level_from_string(rvalue);
814 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse log level, ignoring: %s", rvalue);
818 *o = (*o & LOG_FACMASK) | x;
822 int config_parse_signal(
824 const char *filename,
827 unsigned section_line,
841 r = signal_from_string_try_harder(rvalue);
843 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse signal name, ignoring: %s", rvalue);
851 #if 0 /// UNNEEDED by elogind
852 int config_parse_personality(
854 const char *filename,
857 unsigned section_line,
864 unsigned long *personality = data, p;
871 p = personality_from_string(rvalue);
872 if (p == PERSONALITY_INVALID) {
873 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse personality, ignoring: %s", rvalue);