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_bytes_size(
471 const char *filename,
488 if (parse_bytes(rvalue, &o) < 0 || (off_t) (size_t) o != o) {
489 log_error("[%s:%u] Failed to parse byte value, ignoring: %s", filename, line, rvalue);
498 int config_parse_bytes_off(
499 const char *filename,
515 assert_cc(sizeof(off_t) == sizeof(uint64_t));
517 if (parse_bytes(rvalue, bytes) < 0) {
518 log_error("[%s:%u] Failed to parse bytes value, ignoring: %s", filename, line, rvalue);
525 int config_parse_bool(
526 const char *filename,
543 if ((k = parse_boolean(rvalue)) < 0) {
544 log_error("[%s:%u] Failed to parse boolean value, ignoring: %s", filename, line, rvalue);
552 int config_parse_tristate(
553 const char *filename,
570 /* Tristates are like booleans, but can also take the 'default' value, i.e. "-1" */
572 k = parse_boolean(rvalue);
574 log_error("[%s:%u] Failed to parse boolean value, ignoring: %s", filename, line, rvalue);
582 int config_parse_string(
583 const char *filename,
604 if (!utf8_is_valid(n)) {
605 log_error("[%s:%u] String is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
621 int config_parse_path(
622 const char *filename,
639 if (!utf8_is_valid(rvalue)) {
640 log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
644 if (!path_is_absolute(rvalue)) {
645 log_error("[%s:%u] Not an absolute path, ignoring: %s", filename, line, rvalue);
653 path_kill_slashes(n);
661 int config_parse_strv(
662 const char *filename,
684 if (isempty(rvalue)) {
685 /* Empty assignment resets the list */
690 k = strv_length(*sv);
691 FOREACH_WORD_QUOTED(w, l, rvalue, state)
699 for (k = 0; (*sv)[k]; k++)
704 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
705 n[k] = cunescape_length(w, l);
711 if (!utf8_is_valid(n[k])) {
712 log_error("[%s:%u] String is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
734 int config_parse_path_strv(
735 const char *filename,
757 if (isempty(rvalue)) {
758 /* Empty assignment resets the list */
763 k = strv_length(*sv);
764 FOREACH_WORD_QUOTED(w, l, rvalue, state)
773 for (; (*sv)[k]; k++)
776 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
777 n[k] = strndup(w, l);
783 if (!utf8_is_valid(n[k])) {
784 log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
789 if (!path_is_absolute(n[k])) {
790 log_error("[%s:%u] Not an absolute path, ignoring: %s", filename, line, rvalue);
795 path_kill_slashes(n[k]);
813 int config_parse_usec(
814 const char *filename,
830 if (parse_usec(rvalue, usec) < 0) {
831 log_error("[%s:%u] Failed to parse time value, ignoring: %s", filename, line, rvalue);
838 int config_parse_nsec(
839 const char *filename,
855 if (parse_nsec(rvalue, nsec) < 0) {
856 log_error("[%s:%u] Failed to parse time value, ignoring: %s", filename, line, rvalue);
863 int config_parse_mode(
864 const char *filename,
883 l = strtol(rvalue, &x, 8);
884 if (!x || x == rvalue || *x || errno) {
885 log_error("[%s:%u] Failed to parse mode value, ignoring: %s", filename, line, rvalue);
889 if (l < 0000 || l > 07777) {
890 log_error("[%s:%u] mode value out of range, ignoring: %s", filename, line, rvalue);
898 int config_parse_facility(
899 const char *filename,
916 x = log_facility_unshifted_from_string(rvalue);
918 log_error("[%s:%u] Failed to parse log facility, ignoring: %s", filename, line, rvalue);
922 *o = (x << 3) | LOG_PRI(*o);
927 int config_parse_level(
928 const char *filename,
945 x = log_level_from_string(rvalue);
947 log_error("[%s:%u] Failed to parse log level, ignoring: %s", filename, line, rvalue);
951 *o = (*o & LOG_FACMASK) | x;
955 int config_parse_set_status(
956 const char *filename,
969 ExitStatusSet *status_set = data;
976 if (isempty(rvalue)) {
977 /* Empty assignment resets the list */
979 set_free(status_set->signal);
980 set_free(status_set->code);
982 status_set->signal = status_set->code = NULL;
986 FOREACH_WORD(w, l, rvalue, state) {
990 temp = strndup(w, l);
994 r = safe_atoi(temp, &val);
996 val = signal_from_string_try_harder(temp);
1000 r = set_ensure_allocated(&status_set->signal, trivial_hash_func, trivial_compare_func);
1004 r = set_put(status_set->signal, INT_TO_PTR(val));
1006 log_error("[%s:%u] Unable to store: %s", filename, line, w);
1010 log_error("[%s:%u] Failed to parse value, ignoring: %s", filename, line, w);
1016 if (val < 0 || val > 255)
1017 log_warning("[%s:%u] Value %d is outside range 0-255, ignoring", filename, line, val);
1019 r = set_ensure_allocated(&status_set->code, trivial_hash_func, trivial_compare_func);
1023 r = set_put(status_set->code, INT_TO_PTR(val));
1025 log_error("[%s:%u] Unable to store: %s", filename, line, w);