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 #define DEFINE_PARSER(type, vartype, conv_func) \
345 int config_parse_##type(const char *filename, \
347 const char *section, \
348 const char *lvalue, \
350 const char *rvalue, \
362 r = conv_func(rvalue, i); \
364 log_error("[%s:%u] Failed to parse %s value, ignoring: %s", \
365 filename, line, #vartype, rvalue); \
370 DEFINE_PARSER(int, int, safe_atoi)
371 DEFINE_PARSER(long, long, safe_atoli)
372 DEFINE_PARSER(uint64, uint64_t, safe_atou64)
373 DEFINE_PARSER(unsigned, unsigned, safe_atou)
374 DEFINE_PARSER(double, double, safe_atod)
375 DEFINE_PARSER(nsec, nsec_t, parse_nsec)
376 DEFINE_PARSER(sec, usec_t, parse_sec)
379 int config_parse_bytes_size(
380 const char *filename,
397 if (parse_bytes(rvalue, &o) < 0 || (off_t) (size_t) o != o) {
398 log_error("[%s:%u] Failed to parse byte value, ignoring: %s", filename, line, rvalue);
407 int config_parse_bytes_off(
408 const char *filename,
424 assert_cc(sizeof(off_t) == sizeof(uint64_t));
426 if (parse_bytes(rvalue, bytes) < 0) {
427 log_error("[%s:%u] Failed to parse bytes value, ignoring: %s", filename, line, rvalue);
434 int config_parse_bool(
435 const char *filename,
452 if ((k = parse_boolean(rvalue)) < 0) {
453 log_error("[%s:%u] Failed to parse boolean value, ignoring: %s", filename, line, rvalue);
461 int config_parse_tristate(
462 const char *filename,
479 /* Tristates are like booleans, but can also take the 'default' value, i.e. "-1" */
481 k = parse_boolean(rvalue);
483 log_error("[%s:%u] Failed to parse boolean value, ignoring: %s", filename, line, rvalue);
491 int config_parse_string(
492 const char *filename,
513 if (!utf8_is_valid(n)) {
514 log_error("[%s:%u] String is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
530 int config_parse_path(
531 const char *filename,
548 if (!utf8_is_valid(rvalue)) {
549 log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
553 if (!path_is_absolute(rvalue)) {
554 log_error("[%s:%u] Not an absolute path, ignoring: %s", filename, line, rvalue);
562 path_kill_slashes(n);
570 int config_parse_strv(
571 const char *filename,
580 char *** sv = data, *w, *state;
589 if (isempty(rvalue)) {
592 /* Empty assignment resets the list. As a special rule
593 * we actually fill in a real empty array here rather
594 * than NULL, since some code wants to know if
595 * something was set at all... */
596 empty = strv_new(NULL, NULL);
605 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
606 _cleanup_free_ char *n;
608 n = cunescape_length(w, l);
612 if (!utf8_is_valid(n)) {
613 log_error("[%s:%u] String is not UTF-8 clean, ignoring: %s", filename, line, rvalue);
617 r = strv_extend(sv, n);
625 int config_parse_path_strv(
626 const char *filename,
635 char*** sv = data, *w, *state;
644 if (isempty(rvalue)) {
645 /* Empty assignment resets the list */
651 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
652 _cleanup_free_ char *n;
658 if (!utf8_is_valid(n)) {
659 log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
663 if (!path_is_absolute(n)) {
664 log_error("[%s:%u] Not an absolute path, ignoring: %s", filename, line, rvalue);
668 path_kill_slashes(n);
669 r = strv_extend(sv, n);
677 int config_parse_mode(
678 const char *filename,
697 l = strtol(rvalue, &x, 8);
698 if (!x || x == rvalue || *x || errno) {
699 log_error("[%s:%u] Failed to parse mode value, ignoring: %s", filename, line, rvalue);
703 if (l < 0000 || l > 07777) {
704 log_error("[%s:%u] mode value out of range, ignoring: %s", filename, line, rvalue);
712 int config_parse_facility(
713 const char *filename,
730 x = log_facility_unshifted_from_string(rvalue);
732 log_error("[%s:%u] Failed to parse log facility, ignoring: %s", filename, line, rvalue);
736 *o = (x << 3) | LOG_PRI(*o);
741 int config_parse_level(
742 const char *filename,
759 x = log_level_from_string(rvalue);
761 log_error("[%s:%u] Failed to parse log level, ignoring: %s", filename, line, rvalue);
765 *o = (*o & LOG_FACMASK) | x;
769 int config_parse_set_status(
770 const char *filename,
783 ExitStatusSet *status_set = data;
790 if (isempty(rvalue)) {
791 /* Empty assignment resets the list */
793 set_free(status_set->signal);
794 set_free(status_set->code);
796 status_set->signal = status_set->code = NULL;
800 FOREACH_WORD(w, l, rvalue, state) {
804 temp = strndup(w, l);
808 r = safe_atoi(temp, &val);
810 val = signal_from_string_try_harder(temp);
814 r = set_ensure_allocated(&status_set->signal, trivial_hash_func, trivial_compare_func);
818 r = set_put(status_set->signal, INT_TO_PTR(val));
820 log_error("[%s:%u] Unable to store: %s", filename, line, w);
824 log_error("[%s:%u] Failed to parse value, ignoring: %s", filename, line, w);
830 if (val < 0 || val > 255)
831 log_warning("[%s:%u] Value %d is outside range 0-255, ignoring", filename, line, val);
833 r = set_ensure_allocated(&status_set->code, trivial_hash_func, trivial_compare_func);
837 r = set_put(status_set->code, INT_TO_PTR(val));
839 log_error("[%s:%u] Unable to store: %s", filename, line, w);