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);
335 fd_warn_permissions(filename, fileno(f));
338 char l[LINE_MAX], *p, *c = NULL, *e;
339 bool escaped = false;
341 if (!fgets(l, sizeof(l), f)) {
345 log_error("Failed to read configuration file '%s': %m", filename);
352 c = strappend(continuation, l);
362 for (e = p; *e; e++) {
375 continuation = strdup(l);
404 #define DEFINE_PARSER(type, vartype, conv_func) \
405 int config_parse_##type(const char *unit, \
406 const char *filename, \
408 const char *section, \
409 unsigned section_line, \
410 const char *lvalue, \
412 const char *rvalue, \
424 r = conv_func(rvalue, i); \
426 log_syntax(unit, LOG_ERR, filename, line, -r, \
427 "Failed to parse %s value, ignoring: %s", \
433 DEFINE_PARSER(int, int, safe_atoi)
434 DEFINE_PARSER(long, long, safe_atoli)
435 DEFINE_PARSER(uint64, uint64_t, safe_atou64)
436 DEFINE_PARSER(unsigned, unsigned, safe_atou)
437 DEFINE_PARSER(double, double, safe_atod)
438 DEFINE_PARSER(nsec, nsec_t, parse_nsec)
439 DEFINE_PARSER(sec, usec_t, parse_sec)
442 int config_parse_bytes_size(const char* unit,
443 const char *filename,
446 unsigned section_line,
462 r = parse_bytes(rvalue, &o);
463 if (r < 0 || (off_t) (size_t) o != o) {
464 log_syntax(unit, LOG_ERR, filename, line, -r,
465 "Failed to parse byte value, ignoring: %s", rvalue);
474 int config_parse_bytes_off(const char* unit,
475 const char *filename,
478 unsigned section_line,
493 assert_cc(sizeof(off_t) == sizeof(uint64_t));
495 r = parse_bytes(rvalue, bytes);
497 log_syntax(unit, LOG_ERR, filename, line, -r,
498 "Failed to parse bytes value, ignoring: %s", rvalue);
503 int config_parse_bool(const char* unit,
504 const char *filename,
507 unsigned section_line,
522 k = parse_boolean(rvalue);
524 log_syntax(unit, LOG_ERR, filename, line, -k,
525 "Failed to parse boolean value, ignoring: %s", rvalue);
533 int config_parse_show_status(const char* unit,
534 const char *filename,
537 unsigned section_line,
545 ShowStatus *b = data;
552 k = parse_show_status(rvalue, b);
554 log_syntax(unit, LOG_ERR, filename, line, -k,
555 "Failed to parse show status setting, ignoring: %s", rvalue);
562 int config_parse_string(const char *unit,
563 const char *filename,
566 unsigned section_line,
585 if (!utf8_is_valid(n)) {
586 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
587 "String is not UTF-8 clean, ignoring assignment: %s", rvalue);
603 int config_parse_path(const char *unit,
604 const char *filename,
607 unsigned section_line,
623 if (!utf8_is_valid(rvalue)) {
624 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
625 "Path is not UTF-8 clean, ignoring assignment: %s", rvalue);
629 offset = rvalue[0] == '-' && (streq(lvalue, "InaccessibleDirectories") ||
630 streq(lvalue, "ReadOnlyDirectories"));
631 if (!path_is_absolute(rvalue + offset)) {
632 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
633 "Not an absolute path, ignoring: %s", rvalue);
641 path_kill_slashes(n);
649 int config_parse_strv(const char *unit,
650 const char *filename,
653 unsigned section_line,
660 char *** sv = data, *w, *state;
669 if (isempty(rvalue)) {
672 /* Empty assignment resets the list. As a special rule
673 * we actually fill in a real empty array here rather
674 * than NULL, since some code wants to know if
675 * something was set at all... */
676 empty = strv_new(NULL, NULL);
685 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
686 _cleanup_free_ char *n;
688 n = cunescape_length(w, l);
692 if (!utf8_is_valid(n)) {
693 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
694 "String is not UTF-8 clean, ignoring: %s", rvalue);
698 r = strv_extend(sv, n);
706 int config_parse_path_strv(const char *unit,
707 const char *filename,
710 unsigned section_line,
717 char*** sv = data, *w, *state;
726 if (isempty(rvalue)) {
727 /* Empty assignment resets the list */
733 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
734 _cleanup_free_ char *n;
741 if (!utf8_is_valid(n)) {
742 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
743 "Path is not UTF-8 clean, ignoring assignment: %s", rvalue);
747 offset = n[0] == '-' && (streq(lvalue, "InaccessibleDirectories") ||
748 streq(lvalue, "ReadOnlyDirectories"));
749 if (!path_is_absolute(n + offset)) {
750 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
751 "Not an absolute path, ignoring: %s", rvalue);
755 path_kill_slashes(n);
756 r = strv_extend(sv, n);
764 int config_parse_mode(const char *unit,
765 const char *filename,
768 unsigned section_line,
785 l = strtol(rvalue, &x, 8);
786 if (!x || x == rvalue || *x || errno) {
787 log_syntax(unit, LOG_ERR, filename, line, errno,
788 "Failed to parse mode value, ignoring: %s", rvalue);
792 if (l < 0000 || l > 07777) {
793 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
794 "Mode value out of range, ignoring: %s", rvalue);
802 int config_parse_facility(const char *unit,
803 const char *filename,
806 unsigned section_line,
821 x = log_facility_unshifted_from_string(rvalue);
823 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
824 "Failed to parse log facility, ignoring: %s", rvalue);
828 *o = (x << 3) | LOG_PRI(*o);
833 int config_parse_level(const char *unit,
834 const char *filename,
837 unsigned section_line,
852 x = log_level_from_string(rvalue);
854 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
855 "Failed to parse log level, ignoring: %s", rvalue);
859 *o = (*o & LOG_FACMASK) | x;
863 int config_parse_set_status(const char *unit,
864 const char *filename,
867 unsigned section_line,
878 ExitStatusSet *status_set = data;
885 if (isempty(rvalue)) {
886 /* Empty assignment resets the list */
888 set_free(status_set->signal);
889 set_free(status_set->code);
891 status_set->signal = status_set->code = NULL;
895 FOREACH_WORD(w, l, rvalue, state) {
899 temp = strndup(w, l);
903 r = safe_atoi(temp, &val);
905 val = signal_from_string_try_harder(temp);
909 r = set_ensure_allocated(&status_set->signal, trivial_hash_func, trivial_compare_func);
913 r = set_put(status_set->signal, INT_TO_PTR(val));
915 log_syntax(unit, LOG_ERR, filename, line, -r,
916 "Unable to store: %s", w);
920 log_syntax(unit, LOG_ERR, filename, line, -val,
921 "Failed to parse value, ignoring: %s", w);
927 if (val < 0 || val > 255)
928 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
929 "Value %d is outside range 0-255, ignoring", val);
931 r = set_ensure_allocated(&status_set->code, trivial_hash_func, trivial_compare_func);
935 r = set_put(status_set->code, INT_TO_PTR(val));
937 log_syntax(unit, LOG_ERR, filename, line, -r,
938 "Unable to store: %s", w);