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/>.
28 #include "conf-parser.h"
34 #include "path-util.h"
36 #include "exit-status.h"
38 int config_item_table_lookup(
42 ConfigParserCallback *func,
55 for (t = table; t->lvalue; t++) {
57 if (!streq(lvalue, t->lvalue))
60 if (!streq_ptr(section, t->section))
72 int config_item_perf_lookup(
76 ConfigParserCallback *func,
81 ConfigPerfItemLookup lookup = (ConfigPerfItemLookup) table;
82 const ConfigPerfItem *p;
91 p = lookup(lvalue, strlen(lvalue));
95 key = strjoin(section, ".", lvalue, NULL);
99 p = lookup(key, strlen(key));
108 *data = (uint8_t*) userdata + p->offset;
112 /* Run the user supplied parser for an assignment */
113 static int next_assignment(
114 const char *filename,
116 ConfigItemLookup lookup,
124 ConfigParserCallback func = NULL;
135 r = lookup(table, section, lvalue, &func, <ype, &data, userdata);
141 return func(filename, line, section, lvalue, ltype, rvalue, data, userdata);
146 /* Warn about unknown non-extension fields. */
147 if (!relaxed && !startswith(lvalue, "X-"))
148 log_info("[%s:%u] Unknown lvalue '%s' in section '%s'. Ignoring.", filename, line, lvalue, section);
153 /* Parse a variable assignment line */
154 static int parse_line(
155 const char *filename,
157 const char *sections,
158 ConfigItemLookup lookup,
177 if (strchr(COMMENTS, *l))
180 if (startswith(l, ".include ")) {
184 fn = file_in_same_dir(filename, strstrip(l+9));
188 r = config_parse(fn, NULL, sections, lookup, table, relaxed, userdata);
202 log_error("[%s:%u] Invalid section header.", filename, line);
206 n = strndup(l+1, k-2);
210 if (sections && !nulstr_contains(sections, n)) {
213 log_info("[%s:%u] Unknown section '%s'. Ignoring.", filename, line, n);
225 if (sections && !*section) {
228 log_info("[%s:%u] Assignment outside of section. Ignoring.", filename, line);
235 log_error("[%s:%u] Missing '='.", filename, line);
242 return next_assignment(
254 /* Go through the file and parse each line */
256 const char *filename,
258 const char *sections,
259 ConfigItemLookup lookup,
265 char *section = NULL;
268 char *continuation = NULL;
274 f = fopen(filename, "re");
277 log_error("Failed to open configuration file '%s': %s", filename, strerror(-r));
285 char l[LINE_MAX], *p, *c = NULL, *e;
286 bool escaped = false;
288 if (!fgets(l, sizeof(l), f)) {
293 log_error("Failed to read configuration file '%s': %s", filename, strerror(-r));
300 c = strappend(continuation, l);
312 for (e = p; *e; e++) {
325 continuation = strdup(l);
335 r = parse_line(filename,
362 int config_parse_int(
363 const char *filename,
380 if ((r = safe_atoi(rvalue, i)) < 0) {
381 log_error("[%s:%u] Failed to parse numeric value, ingoring: %s", filename, line, rvalue);
388 int config_parse_long(
389 const char *filename,
406 if ((r = safe_atoli(rvalue, i)) < 0) {
407 log_error("[%s:%u] Failed to parse numeric value, ignoring: %s", filename, line, rvalue);
414 int config_parse_uint64(
415 const char *filename,
432 if ((r = safe_atou64(rvalue, u)) < 0) {
433 log_error("[%s:%u] Failed to parse numeric value, ignoring: %s", filename, line, rvalue);
440 int config_parse_unsigned(
441 const char *filename,
458 if ((r = safe_atou(rvalue, u)) < 0) {
459 log_error("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue);
466 int config_parse_bytes_size(
467 const char *filename,
484 if (parse_bytes(rvalue, &o) < 0 || (off_t) (size_t) o != o) {
485 log_error("[%s:%u] Failed to parse byte value, ignoring: %s", filename, line, rvalue);
494 int config_parse_bytes_off(
495 const char *filename,
511 assert_cc(sizeof(off_t) == sizeof(uint64_t));
513 if (parse_bytes(rvalue, bytes) < 0) {
514 log_error("[%s:%u] Failed to parse bytes value, ignoring: %s", filename, line, rvalue);
521 int config_parse_bool(
522 const char *filename,
539 if ((k = parse_boolean(rvalue)) < 0) {
540 log_error("[%s:%u] Failed to parse boolean value, ignoring: %s", filename, line, rvalue);
548 int config_parse_tristate(
549 const char *filename,
566 /* Tristates are like booleans, but can also take the 'default' value, i.e. "-1" */
568 k = parse_boolean(rvalue);
570 log_error("[%s:%u] Failed to parse boolean value, ignoring: %s", filename, line, rvalue);
578 int config_parse_string(
579 const char *filename,
600 if (!utf8_is_valid(n)) {
601 log_error("[%s:%u] String is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
617 int config_parse_path(
618 const char *filename,
635 if (!utf8_is_valid(rvalue)) {
636 log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
640 if (!path_is_absolute(rvalue)) {
641 log_error("[%s:%u] Not an absolute path, ignoring: %s", filename, line, rvalue);
649 path_kill_slashes(n);
657 int config_parse_strv(
658 const char *filename,
680 k = strv_length(*sv);
681 FOREACH_WORD_QUOTED(w, l, rvalue, state)
689 for (k = 0; (*sv)[k]; k++)
694 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
695 n[k] = cunescape_length(w, l);
701 if (!utf8_is_valid(n[k])) {
702 log_error("[%s:%u] String is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
724 int config_parse_path_strv(
725 const char *filename,
747 k = strv_length(*sv);
748 FOREACH_WORD_QUOTED(w, l, rvalue, state)
757 for (; (*sv)[k]; k++)
760 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
761 n[k] = strndup(w, l);
767 if (!utf8_is_valid(n[k])) {
768 log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
773 if (!path_is_absolute(n[k])) {
774 log_error("[%s:%u] Not an absolute path, ignoring: %s", filename, line, rvalue);
779 path_kill_slashes(n[k]);
797 int config_parse_usec(
798 const char *filename,
814 if (parse_usec(rvalue, usec) < 0) {
815 log_error("[%s:%u] Failed to parse time value, ignoring: %s", filename, line, rvalue);
822 int config_parse_nsec(
823 const char *filename,
839 if (parse_nsec(rvalue, nsec) < 0) {
840 log_error("[%s:%u] Failed to parse time value, ignoring: %s", filename, line, rvalue);
847 int config_parse_mode(
848 const char *filename,
867 l = strtol(rvalue, &x, 8);
868 if (!x || x == rvalue || *x || errno) {
869 log_error("[%s:%u] Failed to parse mode value, ignoring: %s", filename, line, rvalue);
873 if (l < 0000 || l > 07777) {
874 log_error("[%s:%u] mode value out of range, ignoring: %s", filename, line, rvalue);
882 int config_parse_facility(
883 const char *filename,
900 x = log_facility_unshifted_from_string(rvalue);
902 log_error("[%s:%u] Failed to parse log facility, ignoring: %s", filename, line, rvalue);
906 *o = (x << 3) | LOG_PRI(*o);
911 int config_parse_level(
912 const char *filename,
929 x = log_level_from_string(rvalue);
931 log_error("[%s:%u] Failed to parse log level, ignoring: %s", filename, line, rvalue);
935 *o = (*o & LOG_FACMASK) | x;
939 int config_parse_set_status(
940 const char *filename,
953 ExitStatusSet *status_set = data;
960 FOREACH_WORD(w, l, rvalue, state) {
964 temp = strndup(w, l);
968 r = safe_atoi(temp, &val);
970 val = signal_from_string_try_harder(temp);
974 r = set_ensure_allocated(&status_set->signal, trivial_hash_func, trivial_compare_func);
978 r = set_put(status_set->signal, INT_TO_PTR(val));
980 log_error("[%s:%u] Unable to store: %s", filename, line, w);
984 log_error("[%s:%u] Failed to parse value, ignoring: %s", filename, line, w);
990 if (val < 0 || val > 255)
991 log_warning("[%s:%u] Value %d is outside range 0-255, ignoring", filename, line, val);
993 r = set_ensure_allocated(&status_set->code, trivial_hash_func, trivial_compare_func);
997 r = set_put(status_set->code, INT_TO_PTR(val));
999 log_error("[%s:%u] Unable to store: %s", filename, line, w);