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 r = safe_atoi(rvalue, i);
382 log_error("[%s:%u] Failed to parse numeric value, ingoring: %s", filename, line, rvalue);
389 int config_parse_long(
390 const char *filename,
407 r = safe_atoli(rvalue, i);
409 log_error("[%s:%u] Failed to parse numeric value, ignoring: %s", filename, line, rvalue);
416 int config_parse_uint64(
417 const char *filename,
434 r = safe_atou64(rvalue, u);
436 log_error("[%s:%u] Failed to parse numeric value, ignoring: %s", filename, line, rvalue);
443 int config_parse_unsigned(
444 const char *filename,
461 r = safe_atou(rvalue, u);
463 log_error("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue);
470 int config_parse_double(
471 const char *filename,
488 r = safe_atod(rvalue, d);
490 log_error("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue);
497 int config_parse_bytes_size(
498 const char *filename,
515 if (parse_bytes(rvalue, &o) < 0 || (off_t) (size_t) o != o) {
516 log_error("[%s:%u] Failed to parse byte value, ignoring: %s", filename, line, rvalue);
525 int config_parse_bytes_off(
526 const char *filename,
542 assert_cc(sizeof(off_t) == sizeof(uint64_t));
544 if (parse_bytes(rvalue, bytes) < 0) {
545 log_error("[%s:%u] Failed to parse bytes value, ignoring: %s", filename, line, rvalue);
552 int config_parse_bool(
553 const char *filename,
570 if ((k = parse_boolean(rvalue)) < 0) {
571 log_error("[%s:%u] Failed to parse boolean value, ignoring: %s", filename, line, rvalue);
579 int config_parse_tristate(
580 const char *filename,
597 /* Tristates are like booleans, but can also take the 'default' value, i.e. "-1" */
599 k = parse_boolean(rvalue);
601 log_error("[%s:%u] Failed to parse boolean value, ignoring: %s", filename, line, rvalue);
609 int config_parse_string(
610 const char *filename,
631 if (!utf8_is_valid(n)) {
632 log_error("[%s:%u] String is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
648 int config_parse_path(
649 const char *filename,
666 if (!utf8_is_valid(rvalue)) {
667 log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
671 if (!path_is_absolute(rvalue)) {
672 log_error("[%s:%u] Not an absolute path, ignoring: %s", filename, line, rvalue);
680 path_kill_slashes(n);
688 int config_parse_strv(
689 const char *filename,
698 char *** sv = data, *w, *state;
707 if (isempty(rvalue)) {
708 /* Empty assignment resets the list */
714 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
715 _cleanup_free_ char *n;
717 n = cunescape_length(w, l);
721 if (!utf8_is_valid(n)) {
722 log_error("[%s:%u] String is not UTF-8 clean, ignoring: %s", filename, line, rvalue);
726 r = strv_extend(sv, n);
734 int config_parse_path_strv(
735 const char *filename,
744 char*** sv = data, *w, *state;
753 if (isempty(rvalue)) {
754 /* Empty assignment resets the list */
760 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
761 _cleanup_free_ char *n;
767 if (!utf8_is_valid(n)) {
768 log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
772 if (!path_is_absolute(n)) {
773 log_error("[%s:%u] Not an absolute path, ignoring: %s", filename, line, rvalue);
777 path_kill_slashes(n);
778 r = strv_extend(sv, n);
786 int config_parse_usec(
787 const char *filename,
803 if (parse_usec(rvalue, usec) < 0) {
804 log_error("[%s:%u] Failed to parse time value, ignoring: %s", filename, line, rvalue);
811 int config_parse_nsec(
812 const char *filename,
828 if (parse_nsec(rvalue, nsec) < 0) {
829 log_error("[%s:%u] Failed to parse time value, ignoring: %s", filename, line, rvalue);
836 int config_parse_mode(
837 const char *filename,
856 l = strtol(rvalue, &x, 8);
857 if (!x || x == rvalue || *x || errno) {
858 log_error("[%s:%u] Failed to parse mode value, ignoring: %s", filename, line, rvalue);
862 if (l < 0000 || l > 07777) {
863 log_error("[%s:%u] mode value out of range, ignoring: %s", filename, line, rvalue);
871 int config_parse_facility(
872 const char *filename,
889 x = log_facility_unshifted_from_string(rvalue);
891 log_error("[%s:%u] Failed to parse log facility, ignoring: %s", filename, line, rvalue);
895 *o = (x << 3) | LOG_PRI(*o);
900 int config_parse_level(
901 const char *filename,
918 x = log_level_from_string(rvalue);
920 log_error("[%s:%u] Failed to parse log level, ignoring: %s", filename, line, rvalue);
924 *o = (*o & LOG_FACMASK) | x;
928 int config_parse_set_status(
929 const char *filename,
942 ExitStatusSet *status_set = data;
949 if (isempty(rvalue)) {
950 /* Empty assignment resets the list */
952 set_free(status_set->signal);
953 set_free(status_set->code);
955 status_set->signal = status_set->code = NULL;
959 FOREACH_WORD(w, l, rvalue, state) {
963 temp = strndup(w, l);
967 r = safe_atoi(temp, &val);
969 val = signal_from_string_try_harder(temp);
973 r = set_ensure_allocated(&status_set->signal, trivial_hash_func, trivial_compare_func);
977 r = set_put(status_set->signal, INT_TO_PTR(val));
979 log_error("[%s:%u] Unable to store: %s", filename, line, w);
983 log_error("[%s:%u] Failed to parse value, ignoring: %s", filename, line, w);
989 if (val < 0 || val > 255)
990 log_warning("[%s:%u] Value %d is outside range 0-255, ignoring", filename, line, val);
992 r = set_ensure_allocated(&status_set->code, trivial_hash_func, trivial_compare_func);
996 r = set_put(status_set->code, INT_TO_PTR(val));
998 log_error("[%s:%u] Unable to store: %s", filename, line, w);