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"
37 #include "sd-messages.h"
39 int log_syntax_internal(const char *unit, int level,
40 const char *file, unsigned line, const char *func,
41 const char *config_file, unsigned config_line,
42 int error, const char *format, ...) {
44 _cleanup_free_ char *msg = NULL;
49 r = vasprintf(&msg, format, ap);
55 r = log_struct_internal(level,
57 getpid() == 1 ? "UNIT=%s" : "USER_UNIT=%s", unit,
58 MESSAGE_ID(SD_MESSAGE_CONFIG_ERROR),
59 "CONFIG_FILE=%s", config_file,
60 "CONFIG_LINE=%u", config_line,
61 "ERRNO=%d", error > 0 ? error : EINVAL,
62 "MESSAGE=[%s:%u] %s", config_file, config_line, msg,
65 r = log_struct_internal(level,
67 MESSAGE_ID(SD_MESSAGE_CONFIG_ERROR),
68 "CONFIG_FILE=%s", config_file,
69 "CONFIG_LINE=%u", config_line,
70 "ERRNO=%d", error > 0 ? error : EINVAL,
71 "MESSAGE=[%s:%u] %s", config_file, config_line, msg,
77 int config_item_table_lookup(
81 ConfigParserCallback *func,
94 for (t = table; t->lvalue; t++) {
96 if (!streq(lvalue, t->lvalue))
99 if (!streq_ptr(section, t->section))
111 int config_item_perf_lookup(
115 ConfigParserCallback *func,
120 ConfigPerfItemLookup lookup = (ConfigPerfItemLookup) table;
121 const ConfigPerfItem *p;
130 p = lookup(lvalue, strlen(lvalue));
134 key = strjoin(section, ".", lvalue, NULL);
138 p = lookup(key, strlen(key));
147 *data = (uint8_t*) userdata + p->offset;
151 /* Run the user supplied parser for an assignment */
152 static int next_assignment(const char *unit,
153 const char *filename,
155 ConfigItemLookup lookup,
163 ConfigParserCallback func = NULL;
174 r = lookup(table, section, lvalue, &func, <ype, &data, userdata);
180 return func(unit, filename, line, section, lvalue, ltype,
181 rvalue, data, userdata);
186 /* Warn about unknown non-extension fields. */
187 if (!relaxed && !startswith(lvalue, "X-"))
188 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
189 "Unknown lvalue '%s' in section '%s'", lvalue, section);
194 /* Parse a variable assignment line */
195 static int parse_line(const char* unit,
196 const char *filename,
198 const char *sections,
199 ConfigItemLookup lookup,
219 if (strchr(COMMENTS "\n", *l))
222 if (startswith(l, ".include ")) {
223 _cleanup_free_ char *fn = NULL;
225 if (!allow_include) {
226 log_syntax(unit, LOG_ERR, filename, line, EBADMSG,
227 ".include not allowed here. Ignoring.");
231 fn = file_in_same_dir(filename, strstrip(l+9));
235 return config_parse(unit, fn, NULL, sections, lookup, table, relaxed, false, userdata);
246 log_syntax(unit, LOG_ERR, filename, line, EBADMSG,
247 "Invalid section header '%s'", l);
251 n = strndup(l+1, k-2);
255 if (sections && !nulstr_contains(sections, n)) {
258 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
259 "Unknown section '%s'. Ignoring.", n);
271 if (sections && !*section) {
274 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
275 "Assignment outside of section. Ignoring.");
282 log_syntax(unit, LOG_WARNING, filename, line, EINVAL, "Missing '='.");
289 return next_assignment(unit,
301 /* Go through the file and parse each line */
302 int config_parse(const char *unit,
303 const char *filename,
305 const char *sections,
306 ConfigItemLookup lookup,
312 _cleanup_free_ char *section = NULL, *continuation = NULL;
313 _cleanup_fclose_ FILE *ours = NULL;
321 f = ours = fopen(filename, "re");
323 log_error("Failed to open configuration file '%s': %m", filename);
329 char l[LINE_MAX], *p, *c = NULL, *e;
330 bool escaped = false;
332 if (!fgets(l, sizeof(l), f)) {
336 log_error("Failed to read configuration file '%s': %m", filename);
343 c = strappend(continuation, l);
353 for (e = p; *e; e++) {
366 continuation = strdup(l);
394 #define DEFINE_PARSER(type, vartype, conv_func) \
395 int config_parse_##type(const char *unit, \
396 const char *filename, \
398 const char *section, \
399 const char *lvalue, \
401 const char *rvalue, \
413 r = conv_func(rvalue, i); \
415 log_syntax(unit, LOG_ERR, filename, line, -r, \
416 "Failed to parse %s value, ignoring: %s", \
422 DEFINE_PARSER(int, int, safe_atoi)
423 DEFINE_PARSER(long, long, safe_atoli)
424 DEFINE_PARSER(uint64, uint64_t, safe_atou64)
425 DEFINE_PARSER(unsigned, unsigned, safe_atou)
426 DEFINE_PARSER(double, double, safe_atod)
427 DEFINE_PARSER(nsec, nsec_t, parse_nsec)
428 DEFINE_PARSER(sec, usec_t, parse_sec)
431 int config_parse_bytes_size(const char* unit,
432 const char *filename,
450 r = parse_bytes(rvalue, &o);
451 if (r < 0 || (off_t) (size_t) o != o) {
452 log_syntax(unit, LOG_ERR, filename, line, -r,
453 "Failed to parse byte value, ignoring: %s", rvalue);
462 int config_parse_bytes_off(const char* unit,
463 const char *filename,
480 assert_cc(sizeof(off_t) == sizeof(uint64_t));
482 r = parse_bytes(rvalue, bytes);
484 log_syntax(unit, LOG_ERR, filename, line, -r,
485 "Failed to parse bytes value, ignoring: %s", rvalue);
490 int config_parse_bool(const char* unit,
491 const char *filename,
508 k = parse_boolean(rvalue);
510 log_syntax(unit, LOG_ERR, filename, line, -k,
511 "Failed to parse boolean value, ignoring: %s", rvalue);
519 int config_parse_tristate(const char *unit,
520 const char *filename,
537 /* Tristates are like booleans, but can also take the 'default' value, i.e. "-1" */
539 k = parse_boolean(rvalue);
541 log_syntax(unit, LOG_ERR, filename, line, -k,
542 "Failed to parse boolean value, ignoring: %s", rvalue);
550 int config_parse_string(const char *unit,
551 const char *filename,
572 if (!utf8_is_valid(n)) {
573 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
574 "String is not UTF-8 clean, ignoring assignment: %s", rvalue);
590 int config_parse_path(const char *unit,
591 const char *filename,
608 if (!utf8_is_valid(rvalue)) {
609 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
610 "Path is not UTF-8 clean, ignoring assignment: %s", rvalue);
614 if (!path_is_absolute(rvalue)) {
615 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
616 "Not an absolute path, ignoring: %s", rvalue);
624 path_kill_slashes(n);
632 int config_parse_strv(const char *unit,
633 const char *filename,
642 char *** sv = data, *w, *state;
651 if (isempty(rvalue)) {
654 /* Empty assignment resets the list. As a special rule
655 * we actually fill in a real empty array here rather
656 * than NULL, since some code wants to know if
657 * something was set at all... */
658 empty = strv_new(NULL, NULL);
667 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
668 _cleanup_free_ char *n;
670 n = cunescape_length(w, l);
674 if (!utf8_is_valid(n)) {
675 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
676 "String is not UTF-8 clean, ignoring: %s", rvalue);
680 r = strv_extend(sv, n);
688 int config_parse_path_strv(const char *unit,
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;
721 if (!utf8_is_valid(n)) {
722 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
723 "Path is not UTF-8 clean, ignoring assignment: %s", rvalue);
727 if (!path_is_absolute(n)) {
728 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
729 "Not an absolute path, ignoring: %s", rvalue);
733 path_kill_slashes(n);
734 r = strv_extend(sv, n);
742 int config_parse_mode(const char *unit,
743 const char *filename,
762 l = strtol(rvalue, &x, 8);
763 if (!x || x == rvalue || *x || errno) {
764 log_syntax(unit, LOG_ERR, filename, line, errno,
765 "Failed to parse mode value, ignoring: %s", rvalue);
769 if (l < 0000 || l > 07777) {
770 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
771 "Mode value out of range, ignoring: %s", rvalue);
779 int config_parse_facility(const char *unit,
780 const char *filename,
797 x = log_facility_unshifted_from_string(rvalue);
799 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
800 "Failed to parse log facility, ignoring: %s", rvalue);
804 *o = (x << 3) | LOG_PRI(*o);
809 int config_parse_level(const char *unit,
810 const char *filename,
827 x = log_level_from_string(rvalue);
829 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
830 "Failed to parse log level, ignoring: %s", rvalue);
834 *o = (*o & LOG_FACMASK) | x;
838 int config_parse_set_status(const char *unit,
839 const char *filename,
852 ExitStatusSet *status_set = data;
859 if (isempty(rvalue)) {
860 /* Empty assignment resets the list */
862 set_free(status_set->signal);
863 set_free(status_set->code);
865 status_set->signal = status_set->code = NULL;
869 FOREACH_WORD(w, l, rvalue, state) {
873 temp = strndup(w, l);
877 r = safe_atoi(temp, &val);
879 val = signal_from_string_try_harder(temp);
883 r = set_ensure_allocated(&status_set->signal, trivial_hash_func, trivial_compare_func);
887 r = set_put(status_set->signal, INT_TO_PTR(val));
889 log_syntax(unit, LOG_ERR, filename, line, -r,
890 "Unable to store: %s", w);
894 log_syntax(unit, LOG_ERR, filename, line, -val,
895 "Failed to parse value, ignoring: %s", w);
901 if (val < 0 || val > 255)
902 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
903 "Value %d is outside range 0-255, ignoring", val);
905 r = set_ensure_allocated(&status_set->code, trivial_hash_func, trivial_compare_func);
909 r = set_put(status_set->code, INT_TO_PTR(val));
911 log_syntax(unit, LOG_ERR, filename, line, -r,
912 "Unable to store: %s", w);