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,
609 if (!utf8_is_valid(rvalue)) {
610 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
611 "Path is not UTF-8 clean, ignoring assignment: %s", rvalue);
615 offset = rvalue[0] == '-' && (streq(lvalue, "InaccessibleDirectories") ||
616 streq(lvalue, "ReadOnlyDirectories"));
617 if (!path_is_absolute(rvalue + offset)) {
618 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
619 "Not an absolute path, ignoring: %s", rvalue);
627 path_kill_slashes(n);
635 int config_parse_strv(const char *unit,
636 const char *filename,
645 char *** sv = data, *w, *state;
654 if (isempty(rvalue)) {
657 /* Empty assignment resets the list. As a special rule
658 * we actually fill in a real empty array here rather
659 * than NULL, since some code wants to know if
660 * something was set at all... */
661 empty = strv_new(NULL, NULL);
670 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
671 _cleanup_free_ char *n;
673 n = cunescape_length(w, l);
677 if (!utf8_is_valid(n)) {
678 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
679 "String is not UTF-8 clean, ignoring: %s", rvalue);
683 r = strv_extend(sv, n);
691 int config_parse_path_strv(const char *unit,
692 const char *filename,
701 char*** sv = data, *w, *state;
710 if (isempty(rvalue)) {
711 /* Empty assignment resets the list */
717 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
718 _cleanup_free_ char *n;
725 if (!utf8_is_valid(n)) {
726 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
727 "Path is not UTF-8 clean, ignoring assignment: %s", rvalue);
731 offset = n[0] == '-' && (streq(lvalue, "InaccessibleDirectories") ||
732 streq(lvalue, "ReadOnlyDirectories"));
733 if (!path_is_absolute(n + offset)) {
734 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
735 "Not an absolute path, ignoring: %s", rvalue);
739 path_kill_slashes(n);
740 r = strv_extend(sv, n);
748 int config_parse_mode(const char *unit,
749 const char *filename,
768 l = strtol(rvalue, &x, 8);
769 if (!x || x == rvalue || *x || errno) {
770 log_syntax(unit, LOG_ERR, filename, line, errno,
771 "Failed to parse mode value, ignoring: %s", rvalue);
775 if (l < 0000 || l > 07777) {
776 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
777 "Mode value out of range, ignoring: %s", rvalue);
785 int config_parse_facility(const char *unit,
786 const char *filename,
803 x = log_facility_unshifted_from_string(rvalue);
805 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
806 "Failed to parse log facility, ignoring: %s", rvalue);
810 *o = (x << 3) | LOG_PRI(*o);
815 int config_parse_level(const char *unit,
816 const char *filename,
833 x = log_level_from_string(rvalue);
835 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
836 "Failed to parse log level, ignoring: %s", rvalue);
840 *o = (*o & LOG_FACMASK) | x;
844 int config_parse_set_status(const char *unit,
845 const char *filename,
858 ExitStatusSet *status_set = data;
865 if (isempty(rvalue)) {
866 /* Empty assignment resets the list */
868 set_free(status_set->signal);
869 set_free(status_set->code);
871 status_set->signal = status_set->code = NULL;
875 FOREACH_WORD(w, l, rvalue, state) {
879 temp = strndup(w, l);
883 r = safe_atoi(temp, &val);
885 val = signal_from_string_try_harder(temp);
889 r = set_ensure_allocated(&status_set->signal, trivial_hash_func, trivial_compare_func);
893 r = set_put(status_set->signal, INT_TO_PTR(val));
895 log_syntax(unit, LOG_ERR, filename, line, -r,
896 "Unable to store: %s", w);
900 log_syntax(unit, LOG_ERR, filename, line, -val,
901 "Failed to parse value, ignoring: %s", w);
907 if (val < 0 || val > 255)
908 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
909 "Value %d is outside range 0-255, ignoring", val);
911 r = set_ensure_allocated(&status_set->code, trivial_hash_func, trivial_compare_func);
915 r = set_put(status_set->code, INT_TO_PTR(val));
917 log_syntax(unit, LOG_ERR, filename, line, -r,
918 "Unable to store: %s", w);