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,
671 char *** sv = data, *w, *state;
680 if (isempty(rvalue)) {
681 /* Empty assignment resets the list */
687 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
688 _cleanup_free_ char *n;
690 n = cunescape_length(w, l);
694 if (!utf8_is_valid(n)) {
695 log_error("[%s:%u] String is not UTF-8 clean, ignoring: %s", filename, line, rvalue);
699 r = strv_extend(sv, n);
707 int config_parse_path_strv(
708 const char *filename,
717 char*** sv = data, *w, *state;
726 if (isempty(rvalue)) {
727 /* Empty assignment resets the list */
733 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
734 _cleanup_free_ char *n;
740 if (!utf8_is_valid(n)) {
741 log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
745 if (!path_is_absolute(n)) {
746 log_error("[%s:%u] Not an absolute path, ignoring: %s", filename, line, rvalue);
750 path_kill_slashes(n);
751 r = strv_extend(sv, n);
759 int config_parse_usec(
760 const char *filename,
776 if (parse_usec(rvalue, usec) < 0) {
777 log_error("[%s:%u] Failed to parse time value, ignoring: %s", filename, line, rvalue);
784 int config_parse_nsec(
785 const char *filename,
801 if (parse_nsec(rvalue, nsec) < 0) {
802 log_error("[%s:%u] Failed to parse time value, ignoring: %s", filename, line, rvalue);
809 int config_parse_mode(
810 const char *filename,
829 l = strtol(rvalue, &x, 8);
830 if (!x || x == rvalue || *x || errno) {
831 log_error("[%s:%u] Failed to parse mode value, ignoring: %s", filename, line, rvalue);
835 if (l < 0000 || l > 07777) {
836 log_error("[%s:%u] mode value out of range, ignoring: %s", filename, line, rvalue);
844 int config_parse_facility(
845 const char *filename,
862 x = log_facility_unshifted_from_string(rvalue);
864 log_error("[%s:%u] Failed to parse log facility, ignoring: %s", filename, line, rvalue);
868 *o = (x << 3) | LOG_PRI(*o);
873 int config_parse_level(
874 const char *filename,
891 x = log_level_from_string(rvalue);
893 log_error("[%s:%u] Failed to parse log level, ignoring: %s", filename, line, rvalue);
897 *o = (*o & LOG_FACMASK) | x;
901 int config_parse_set_status(
902 const char *filename,
915 ExitStatusSet *status_set = data;
922 if (isempty(rvalue)) {
923 /* Empty assignment resets the list */
925 set_free(status_set->signal);
926 set_free(status_set->code);
928 status_set->signal = status_set->code = NULL;
932 FOREACH_WORD(w, l, rvalue, state) {
936 temp = strndup(w, l);
940 r = safe_atoi(temp, &val);
942 val = signal_from_string_try_harder(temp);
946 r = set_ensure_allocated(&status_set->signal, trivial_hash_func, trivial_compare_func);
950 r = set_put(status_set->signal, INT_TO_PTR(val));
952 log_error("[%s:%u] Unable to store: %s", filename, line, w);
956 log_error("[%s:%u] Failed to parse value, ignoring: %s", filename, line, w);
962 if (val < 0 || val > 255)
963 log_warning("[%s:%u] Value %d is outside range 0-255, ignoring", filename, line, val);
965 r = set_ensure_allocated(&status_set->code, trivial_hash_func, trivial_compare_func);
969 r = set_put(status_set->code, INT_TO_PTR(val));
971 log_error("[%s:%u] Unable to store: %s", filename, line, w);