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 "\n", *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 _cleanup_free_ *section = NULL, *continuation = NULL;
266 FILE _cleanup_fclose_ *ours = NULL;
273 f = ours = fopen(filename, "re");
275 log_error("Failed to open configuration file '%s': %m", filename);
281 char l[LINE_MAX], *p, *c = NULL, *e;
282 bool escaped = false;
284 if (!fgets(l, sizeof(l), f)) {
288 log_error("Failed to read configuration file '%s': %m", filename);
295 c = strappend(continuation, l);
305 for (e = p; *e; e++) {
318 continuation = strdup(l);
326 r = parse_line(filename,
344 int config_parse_int(
345 const char *filename,
362 r = safe_atoi(rvalue, i);
364 log_error("[%s:%u] Failed to parse numeric value, ingoring: %s", filename, line, rvalue);
371 int config_parse_long(
372 const char *filename,
389 r = safe_atoli(rvalue, i);
391 log_error("[%s:%u] Failed to parse numeric value, ignoring: %s", filename, line, rvalue);
398 int config_parse_uint64(
399 const char *filename,
416 r = safe_atou64(rvalue, u);
418 log_error("[%s:%u] Failed to parse numeric value, ignoring: %s", filename, line, rvalue);
425 int config_parse_unsigned(
426 const char *filename,
443 r = safe_atou(rvalue, u);
445 log_error("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue);
452 int config_parse_double(
453 const char *filename,
470 r = safe_atod(rvalue, d);
472 log_error("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue);
479 int config_parse_bytes_size(
480 const char *filename,
497 if (parse_bytes(rvalue, &o) < 0 || (off_t) (size_t) o != o) {
498 log_error("[%s:%u] Failed to parse byte value, ignoring: %s", filename, line, rvalue);
507 int config_parse_bytes_off(
508 const char *filename,
524 assert_cc(sizeof(off_t) == sizeof(uint64_t));
526 if (parse_bytes(rvalue, bytes) < 0) {
527 log_error("[%s:%u] Failed to parse bytes value, ignoring: %s", filename, line, rvalue);
534 int config_parse_bool(
535 const char *filename,
552 if ((k = parse_boolean(rvalue)) < 0) {
553 log_error("[%s:%u] Failed to parse boolean value, ignoring: %s", filename, line, rvalue);
561 int config_parse_tristate(
562 const char *filename,
579 /* Tristates are like booleans, but can also take the 'default' value, i.e. "-1" */
581 k = parse_boolean(rvalue);
583 log_error("[%s:%u] Failed to parse boolean value, ignoring: %s", filename, line, rvalue);
591 int config_parse_string(
592 const char *filename,
613 if (!utf8_is_valid(n)) {
614 log_error("[%s:%u] String is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
630 int config_parse_path(
631 const char *filename,
648 if (!utf8_is_valid(rvalue)) {
649 log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
653 if (!path_is_absolute(rvalue)) {
654 log_error("[%s:%u] Not an absolute path, ignoring: %s", filename, line, rvalue);
662 path_kill_slashes(n);
670 int config_parse_strv(
671 const char *filename,
680 char *** sv = data, *w, *state;
689 if (isempty(rvalue)) {
692 /* Empty assignment resets the list. As a special rule
693 * we actually fill in a real empty array here rather
694 * than NULL, since some code wants to know if
695 * something was set at all... */
696 empty = strv_new(NULL, NULL);
705 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
706 _cleanup_free_ char *n;
708 n = cunescape_length(w, l);
712 if (!utf8_is_valid(n)) {
713 log_error("[%s:%u] String is not UTF-8 clean, ignoring: %s", filename, line, rvalue);
717 r = strv_extend(sv, n);
725 int config_parse_path_strv(
726 const char *filename,
735 char*** sv = data, *w, *state;
744 if (isempty(rvalue)) {
745 /* Empty assignment resets the list */
751 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
752 _cleanup_free_ char *n;
758 if (!utf8_is_valid(n)) {
759 log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
763 if (!path_is_absolute(n)) {
764 log_error("[%s:%u] Not an absolute path, ignoring: %s", filename, line, rvalue);
768 path_kill_slashes(n);
769 r = strv_extend(sv, n);
777 int config_parse_sec(
778 const char *filename,
794 if (parse_sec(rvalue, usec) < 0) {
795 log_error("[%s:%u] Failed to parse time value, ignoring: %s", filename, line, rvalue);
802 int config_parse_nsec(
803 const char *filename,
819 if (parse_nsec(rvalue, nsec) < 0) {
820 log_error("[%s:%u] Failed to parse time value, ignoring: %s", filename, line, rvalue);
827 int config_parse_mode(
828 const char *filename,
847 l = strtol(rvalue, &x, 8);
848 if (!x || x == rvalue || *x || errno) {
849 log_error("[%s:%u] Failed to parse mode value, ignoring: %s", filename, line, rvalue);
853 if (l < 0000 || l > 07777) {
854 log_error("[%s:%u] mode value out of range, ignoring: %s", filename, line, rvalue);
862 int config_parse_facility(
863 const char *filename,
880 x = log_facility_unshifted_from_string(rvalue);
882 log_error("[%s:%u] Failed to parse log facility, ignoring: %s", filename, line, rvalue);
886 *o = (x << 3) | LOG_PRI(*o);
891 int config_parse_level(
892 const char *filename,
909 x = log_level_from_string(rvalue);
911 log_error("[%s:%u] Failed to parse log level, ignoring: %s", filename, line, rvalue);
915 *o = (*o & LOG_FACMASK) | x;
919 int config_parse_set_status(
920 const char *filename,
933 ExitStatusSet *status_set = data;
940 if (isempty(rvalue)) {
941 /* Empty assignment resets the list */
943 set_free(status_set->signal);
944 set_free(status_set->code);
946 status_set->signal = status_set->code = NULL;
950 FOREACH_WORD(w, l, rvalue, state) {
954 temp = strndup(w, l);
958 r = safe_atoi(temp, &val);
960 val = signal_from_string_try_harder(temp);
964 r = set_ensure_allocated(&status_set->signal, trivial_hash_func, trivial_compare_func);
968 r = set_put(status_set->signal, INT_TO_PTR(val));
970 log_error("[%s:%u] Unable to store: %s", filename, line, w);
974 log_error("[%s:%u] Failed to parse value, ignoring: %s", filename, line, w);
980 if (val < 0 || val > 255)
981 log_warning("[%s:%u] Value %d is outside range 0-255, ignoring", filename, line, val);
983 r = set_ensure_allocated(&status_set->code, trivial_hash_func, trivial_compare_func);
987 r = set_put(status_set->code, INT_TO_PTR(val));
989 log_error("[%s:%u] Unable to store: %s", filename, line, w);