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/>.
27 #include <netinet/ether.h>
29 #include "conf-parser.h"
35 #include "path-util.h"
37 #include "exit-status.h"
38 #include "sd-messages.h"
40 int log_syntax_internal(const char *unit, int level,
41 const char *file, unsigned line, const char *func,
42 const char *config_file, unsigned config_line,
43 int error, const char *format, ...) {
45 _cleanup_free_ char *msg = NULL;
50 r = vasprintf(&msg, format, ap);
56 r = log_struct_internal(level,
58 getpid() == 1 ? "UNIT=%s" : "USER_UNIT=%s", unit,
59 MESSAGE_ID(SD_MESSAGE_CONFIG_ERROR),
60 "CONFIG_FILE=%s", config_file,
61 "CONFIG_LINE=%u", config_line,
62 "ERRNO=%d", error > 0 ? error : EINVAL,
63 "MESSAGE=[%s:%u] %s", config_file, config_line, msg,
66 r = log_struct_internal(level,
68 MESSAGE_ID(SD_MESSAGE_CONFIG_ERROR),
69 "CONFIG_FILE=%s", config_file,
70 "CONFIG_LINE=%u", config_line,
71 "ERRNO=%d", error > 0 ? error : EINVAL,
72 "MESSAGE=[%s:%u] %s", config_file, config_line, msg,
78 int config_item_table_lookup(
82 ConfigParserCallback *func,
95 for (t = table; t->lvalue; t++) {
97 if (!streq(lvalue, t->lvalue))
100 if (!streq_ptr(section, t->section))
112 int config_item_perf_lookup(
116 ConfigParserCallback *func,
121 ConfigPerfItemLookup lookup = (ConfigPerfItemLookup) table;
122 const ConfigPerfItem *p;
131 p = lookup(lvalue, strlen(lvalue));
135 key = strjoin(section, ".", lvalue, NULL);
139 p = lookup(key, strlen(key));
148 *data = (uint8_t*) userdata + p->offset;
152 /* Run the user supplied parser for an assignment */
153 static int next_assignment(const char *unit,
154 const char *filename,
156 ConfigItemLookup lookup,
159 unsigned section_line,
165 ConfigParserCallback func = NULL;
176 r = lookup(table, section, lvalue, &func, <ype, &data, userdata);
182 return func(unit, filename, line, section, section_line,
183 lvalue, ltype, rvalue, data, userdata);
188 /* Warn about unknown non-extension fields. */
189 if (!relaxed && !startswith(lvalue, "X-"))
190 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
191 "Unknown lvalue '%s' in section '%s'", lvalue, section);
196 /* Parse a variable assignment line */
197 static int parse_line(const char* unit,
198 const char *filename,
200 const char *sections,
201 ConfigItemLookup lookup,
206 unsigned *section_line,
222 if (strchr(COMMENTS "\n", *l))
225 if (startswith(l, ".include ")) {
226 _cleanup_free_ char *fn = NULL;
228 if (!allow_include) {
229 log_syntax(unit, LOG_ERR, filename, line, EBADMSG,
230 ".include not allowed here. Ignoring.");
234 fn = file_in_same_dir(filename, strstrip(l+9));
238 return config_parse(unit, fn, NULL, sections, lookup, table, relaxed, false, userdata);
249 log_syntax(unit, LOG_ERR, filename, line, EBADMSG,
250 "Invalid section header '%s'", l);
254 n = strndup(l+1, k-2);
258 if (sections && !nulstr_contains(sections, n)) {
261 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
262 "Unknown section '%s'. Ignoring.", n);
271 *section_line = line;
277 if (sections && !*section) {
280 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
281 "Assignment outside of section. Ignoring.");
288 log_syntax(unit, LOG_WARNING, filename, line, EINVAL, "Missing '='.");
295 return next_assignment(unit,
308 /* Go through the file and parse each line */
309 int config_parse(const char *unit,
310 const char *filename,
312 const char *sections,
313 ConfigItemLookup lookup,
319 _cleanup_free_ char *section = NULL, *continuation = NULL;
320 _cleanup_fclose_ FILE *ours = NULL;
321 unsigned line = 0, section_line = 0;
328 f = ours = fopen(filename, "re");
330 log_error("Failed to open configuration file '%s': %m", filename);
336 char l[LINE_MAX], *p, *c = NULL, *e;
337 bool escaped = false;
339 if (!fgets(l, sizeof(l), f)) {
343 log_error("Failed to read configuration file '%s': %m", filename);
350 c = strappend(continuation, l);
360 for (e = p; *e; e++) {
373 continuation = strdup(l);
402 #define DEFINE_PARSER(type, vartype, conv_func) \
403 int config_parse_##type(const char *unit, \
404 const char *filename, \
406 const char *section, \
407 unsigned section_line, \
408 const char *lvalue, \
410 const char *rvalue, \
422 r = conv_func(rvalue, i); \
424 log_syntax(unit, LOG_ERR, filename, line, -r, \
425 "Failed to parse %s value, ignoring: %s", \
431 DEFINE_PARSER(int, int, safe_atoi)
432 DEFINE_PARSER(long, long, safe_atoli)
433 DEFINE_PARSER(uint64, uint64_t, safe_atou64)
434 DEFINE_PARSER(unsigned, unsigned, safe_atou)
435 DEFINE_PARSER(double, double, safe_atod)
436 DEFINE_PARSER(nsec, nsec_t, parse_nsec)
437 DEFINE_PARSER(sec, usec_t, parse_sec)
440 int config_parse_bytes_size(const char* unit,
441 const char *filename,
444 unsigned section_line,
460 r = parse_bytes(rvalue, &o);
461 if (r < 0 || (off_t) (size_t) o != o) {
462 log_syntax(unit, LOG_ERR, filename, line, -r,
463 "Failed to parse byte value, ignoring: %s", rvalue);
472 int config_parse_bytes_off(const char* unit,
473 const char *filename,
476 unsigned section_line,
491 assert_cc(sizeof(off_t) == sizeof(uint64_t));
493 r = parse_bytes(rvalue, bytes);
495 log_syntax(unit, LOG_ERR, filename, line, -r,
496 "Failed to parse bytes value, ignoring: %s", rvalue);
501 int config_parse_bool(const char* unit,
502 const char *filename,
505 unsigned section_line,
520 k = parse_boolean(rvalue);
522 log_syntax(unit, LOG_ERR, filename, line, -k,
523 "Failed to parse boolean value, ignoring: %s", rvalue);
531 int config_parse_string(const char *unit,
532 const char *filename,
535 unsigned section_line,
554 if (!utf8_is_valid(n)) {
555 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
556 "String is not UTF-8 clean, ignoring assignment: %s", rvalue);
572 int config_parse_path(const char *unit,
573 const char *filename,
576 unsigned section_line,
592 if (!utf8_is_valid(rvalue)) {
593 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
594 "Path is not UTF-8 clean, ignoring assignment: %s", rvalue);
598 offset = rvalue[0] == '-' && (streq(lvalue, "InaccessibleDirectories") ||
599 streq(lvalue, "ReadOnlyDirectories"));
600 if (!path_is_absolute(rvalue + offset)) {
601 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
602 "Not an absolute path, ignoring: %s", rvalue);
610 path_kill_slashes(n);
618 int config_parse_strv(const char *unit,
619 const char *filename,
622 unsigned section_line,
629 char *** sv = data, *w, *state;
638 if (isempty(rvalue)) {
641 /* Empty assignment resets the list. As a special rule
642 * we actually fill in a real empty array here rather
643 * than NULL, since some code wants to know if
644 * something was set at all... */
645 empty = strv_new(NULL, NULL);
654 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
655 _cleanup_free_ char *n;
657 n = cunescape_length(w, l);
661 if (!utf8_is_valid(n)) {
662 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
663 "String is not UTF-8 clean, ignoring: %s", rvalue);
667 r = strv_extend(sv, n);
675 int config_parse_path_strv(const char *unit,
676 const char *filename,
679 unsigned section_line,
686 char*** sv = data, *w, *state;
695 if (isempty(rvalue)) {
696 /* Empty assignment resets the list */
702 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
703 _cleanup_free_ char *n;
710 if (!utf8_is_valid(n)) {
711 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
712 "Path is not UTF-8 clean, ignoring assignment: %s", rvalue);
716 offset = n[0] == '-' && (streq(lvalue, "InaccessibleDirectories") ||
717 streq(lvalue, "ReadOnlyDirectories"));
718 if (!path_is_absolute(n + offset)) {
719 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
720 "Not an absolute path, ignoring: %s", rvalue);
724 path_kill_slashes(n);
725 r = strv_extend(sv, n);
733 int config_parse_mode(const char *unit,
734 const char *filename,
737 unsigned section_line,
754 l = strtol(rvalue, &x, 8);
755 if (!x || x == rvalue || *x || errno) {
756 log_syntax(unit, LOG_ERR, filename, line, errno,
757 "Failed to parse mode value, ignoring: %s", rvalue);
761 if (l < 0000 || l > 07777) {
762 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
763 "Mode value out of range, ignoring: %s", rvalue);
771 int config_parse_facility(const char *unit,
772 const char *filename,
775 unsigned section_line,
790 x = log_facility_unshifted_from_string(rvalue);
792 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
793 "Failed to parse log facility, ignoring: %s", rvalue);
797 *o = (x << 3) | LOG_PRI(*o);
802 int config_parse_level(const char *unit,
803 const char *filename,
806 unsigned section_line,
821 x = log_level_from_string(rvalue);
823 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
824 "Failed to parse log level, ignoring: %s", rvalue);
828 *o = (*o & LOG_FACMASK) | x;
832 int config_parse_set_status(const char *unit,
833 const char *filename,
836 unsigned section_line,
847 ExitStatusSet *status_set = data;
854 if (isempty(rvalue)) {
855 /* Empty assignment resets the list */
857 set_free(status_set->signal);
858 set_free(status_set->code);
860 status_set->signal = status_set->code = NULL;
864 FOREACH_WORD(w, l, rvalue, state) {
868 temp = strndup(w, l);
872 r = safe_atoi(temp, &val);
874 val = signal_from_string_try_harder(temp);
878 r = set_ensure_allocated(&status_set->signal, trivial_hash_func, trivial_compare_func);
882 r = set_put(status_set->signal, INT_TO_PTR(val));
884 log_syntax(unit, LOG_ERR, filename, line, -r,
885 "Unable to store: %s", w);
889 log_syntax(unit, LOG_ERR, filename, line, -val,
890 "Failed to parse value, ignoring: %s", w);
896 if (val < 0 || val > 255)
897 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
898 "Value %d is outside range 0-255, ignoring", val);
900 r = set_ensure_allocated(&status_set->code, trivial_hash_func, trivial_compare_func);
904 r = set_put(status_set->code, INT_TO_PTR(val));
906 log_syntax(unit, LOG_ERR, filename, line, -r,
907 "Unable to store: %s", w);