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,
164 ConfigParserCallback func = NULL;
175 r = lookup(table, section, lvalue, &func, <ype, &data, userdata);
181 return func(unit, filename, line, section, lvalue, ltype,
182 rvalue, data, userdata);
187 /* Warn about unknown non-extension fields. */
188 if (!relaxed && !startswith(lvalue, "X-"))
189 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
190 "Unknown lvalue '%s' in section '%s'", lvalue, section);
195 /* Parse a variable assignment line */
196 static int parse_line(const char* unit,
197 const char *filename,
199 const char *sections,
200 ConfigItemLookup lookup,
220 if (strchr(COMMENTS "\n", *l))
223 if (startswith(l, ".include ")) {
224 _cleanup_free_ char *fn = NULL;
226 if (!allow_include) {
227 log_syntax(unit, LOG_ERR, filename, line, EBADMSG,
228 ".include not allowed here. Ignoring.");
232 fn = file_in_same_dir(filename, strstrip(l+9));
236 return config_parse(unit, fn, NULL, sections, lookup, table, relaxed, false, userdata);
247 log_syntax(unit, LOG_ERR, filename, line, EBADMSG,
248 "Invalid section header '%s'", l);
252 n = strndup(l+1, k-2);
256 if (sections && !nulstr_contains(sections, n)) {
259 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
260 "Unknown section '%s'. Ignoring.", n);
272 if (sections && !*section) {
275 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
276 "Assignment outside of section. Ignoring.");
283 log_syntax(unit, LOG_WARNING, filename, line, EINVAL, "Missing '='.");
290 return next_assignment(unit,
302 /* Go through the file and parse each line */
303 int config_parse(const char *unit,
304 const char *filename,
306 const char *sections,
307 ConfigItemLookup lookup,
313 _cleanup_free_ char *section = NULL, *continuation = NULL;
314 _cleanup_fclose_ FILE *ours = NULL;
322 f = ours = fopen(filename, "re");
324 log_error("Failed to open configuration file '%s': %m", filename);
330 char l[LINE_MAX], *p, *c = NULL, *e;
331 bool escaped = false;
333 if (!fgets(l, sizeof(l), f)) {
337 log_error("Failed to read configuration file '%s': %m", filename);
344 c = strappend(continuation, l);
354 for (e = p; *e; e++) {
367 continuation = strdup(l);
395 #define DEFINE_PARSER(type, vartype, conv_func) \
396 int config_parse_##type(const char *unit, \
397 const char *filename, \
399 const char *section, \
400 const char *lvalue, \
402 const char *rvalue, \
414 r = conv_func(rvalue, i); \
416 log_syntax(unit, LOG_ERR, filename, line, -r, \
417 "Failed to parse %s value, ignoring: %s", \
423 DEFINE_PARSER(int, int, safe_atoi)
424 DEFINE_PARSER(long, long, safe_atoli)
425 DEFINE_PARSER(uint64, uint64_t, safe_atou64)
426 DEFINE_PARSER(unsigned, unsigned, safe_atou)
427 DEFINE_PARSER(double, double, safe_atod)
428 DEFINE_PARSER(nsec, nsec_t, parse_nsec)
429 DEFINE_PARSER(sec, usec_t, parse_sec)
432 int config_parse_bytes_size(const char* unit,
433 const char *filename,
451 r = parse_bytes(rvalue, &o);
452 if (r < 0 || (off_t) (size_t) o != o) {
453 log_syntax(unit, LOG_ERR, filename, line, -r,
454 "Failed to parse byte value, ignoring: %s", rvalue);
463 int config_parse_bytes_off(const char* unit,
464 const char *filename,
481 assert_cc(sizeof(off_t) == sizeof(uint64_t));
483 r = parse_bytes(rvalue, bytes);
485 log_syntax(unit, LOG_ERR, filename, line, -r,
486 "Failed to parse bytes value, ignoring: %s", rvalue);
491 int config_parse_bool(const char* unit,
492 const char *filename,
509 k = parse_boolean(rvalue);
511 log_syntax(unit, LOG_ERR, filename, line, -k,
512 "Failed to parse boolean value, ignoring: %s", rvalue);
520 int config_parse_string(const char *unit,
521 const char *filename,
542 if (!utf8_is_valid(n)) {
543 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
544 "String is not UTF-8 clean, ignoring assignment: %s", rvalue);
560 int config_parse_path(const char *unit,
561 const char *filename,
579 if (!utf8_is_valid(rvalue)) {
580 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
581 "Path is not UTF-8 clean, ignoring assignment: %s", rvalue);
585 offset = rvalue[0] == '-' && (streq(lvalue, "InaccessibleDirectories") ||
586 streq(lvalue, "ReadOnlyDirectories"));
587 if (!path_is_absolute(rvalue + offset)) {
588 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
589 "Not an absolute path, ignoring: %s", rvalue);
597 path_kill_slashes(n);
605 int config_parse_strv(const char *unit,
606 const char *filename,
615 char *** sv = data, *w, *state;
624 if (isempty(rvalue)) {
627 /* Empty assignment resets the list. As a special rule
628 * we actually fill in a real empty array here rather
629 * than NULL, since some code wants to know if
630 * something was set at all... */
631 empty = strv_new(NULL, NULL);
640 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
641 _cleanup_free_ char *n;
643 n = cunescape_length(w, l);
647 if (!utf8_is_valid(n)) {
648 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
649 "String is not UTF-8 clean, ignoring: %s", rvalue);
653 r = strv_extend(sv, n);
661 int config_parse_path_strv(const char *unit,
662 const char *filename,
671 char*** sv = data, *w, *state;
680 if (isempty(rvalue)) {
681 /* Empty assignment resets the list */
687 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
688 _cleanup_free_ char *n;
695 if (!utf8_is_valid(n)) {
696 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
697 "Path is not UTF-8 clean, ignoring assignment: %s", rvalue);
701 offset = n[0] == '-' && (streq(lvalue, "InaccessibleDirectories") ||
702 streq(lvalue, "ReadOnlyDirectories"));
703 if (!path_is_absolute(n + offset)) {
704 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
705 "Not an absolute path, ignoring: %s", rvalue);
709 path_kill_slashes(n);
710 r = strv_extend(sv, n);
718 int config_parse_mode(const char *unit,
719 const char *filename,
738 l = strtol(rvalue, &x, 8);
739 if (!x || x == rvalue || *x || errno) {
740 log_syntax(unit, LOG_ERR, filename, line, errno,
741 "Failed to parse mode value, ignoring: %s", rvalue);
745 if (l < 0000 || l > 07777) {
746 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
747 "Mode value out of range, ignoring: %s", rvalue);
755 int config_parse_facility(const char *unit,
756 const char *filename,
773 x = log_facility_unshifted_from_string(rvalue);
775 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
776 "Failed to parse log facility, ignoring: %s", rvalue);
780 *o = (x << 3) | LOG_PRI(*o);
785 int config_parse_level(const char *unit,
786 const char *filename,
803 x = log_level_from_string(rvalue);
805 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
806 "Failed to parse log level, ignoring: %s", rvalue);
810 *o = (*o & LOG_FACMASK) | x;
814 int config_parse_set_status(const char *unit,
815 const char *filename,
828 ExitStatusSet *status_set = data;
835 if (isempty(rvalue)) {
836 /* Empty assignment resets the list */
838 set_free(status_set->signal);
839 set_free(status_set->code);
841 status_set->signal = status_set->code = NULL;
845 FOREACH_WORD(w, l, rvalue, state) {
849 temp = strndup(w, l);
853 r = safe_atoi(temp, &val);
855 val = signal_from_string_try_harder(temp);
859 r = set_ensure_allocated(&status_set->signal, trivial_hash_func, trivial_compare_func);
863 r = set_put(status_set->signal, INT_TO_PTR(val));
865 log_syntax(unit, LOG_ERR, filename, line, -r,
866 "Unable to store: %s", w);
870 log_syntax(unit, LOG_ERR, filename, line, -val,
871 "Failed to parse value, ignoring: %s", w);
877 if (val < 0 || val > 255)
878 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
879 "Value %d is outside range 0-255, ignoring", val);
881 r = set_ensure_allocated(&status_set->code, trivial_hash_func, trivial_compare_func);
885 r = set_put(status_set->code, INT_TO_PTR(val));
887 log_syntax(unit, LOG_ERR, filename, line, -r,
888 "Unable to store: %s", w);