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"
38 int config_item_table_lookup(
42 ConfigParserCallback
*func
,
55 for (t
= table
; t
->lvalue
; t
++) {
57 if (!streq(lvalue
, t
->lvalue
))
60 if (!streq_ptr(section
, t
->section
))
72 int config_item_perf_lookup(
76 ConfigParserCallback
*func
,
81 ConfigPerfItemLookup lookup
= (ConfigPerfItemLookup
) table
;
82 const ConfigPerfItem
*p
;
91 p
= lookup(lvalue
, strlen(lvalue
));
95 key
= strjoin(section
, ".", lvalue
, NULL
);
99 p
= lookup(key
, strlen(key
));
108 *data
= (uint8_t*) userdata
+ p
->offset
;
112 /* Run the user supplied parser for an assignment */
113 static int next_assignment(
114 const char *filename
,
116 ConfigItemLookup lookup
,
124 ConfigParserCallback func
= NULL
;
135 r
= lookup(table
, section
, lvalue
, &func
, <ype
, &data
, userdata
);
141 return func(filename
, line
, section
, lvalue
, ltype
, rvalue
, data
, userdata
);
146 /* Warn about unknown non-extension fields. */
147 if (!relaxed
&& !startswith(lvalue
, "X-"))
148 log_info("[%s:%u] Unknown lvalue '%s' in section '%s'. Ignoring.", filename
, line
, lvalue
, section
);
153 /* Parse a variable assignment line */
154 static int parse_line(
155 const char *filename
,
157 const char *sections
,
158 ConfigItemLookup lookup
,
177 if (strchr(COMMENTS
, *l
))
180 if (startswith(l
, ".include ")) {
184 fn
= file_in_same_dir(filename
, strstrip(l
+9));
188 r
= config_parse(fn
, NULL
, sections
, lookup
, table
, relaxed
, userdata
);
202 log_error("[%s:%u] Invalid section header.", filename
, line
);
206 n
= strndup(l
+1, k
-2);
210 if (sections
&& !nulstr_contains(sections
, n
)) {
213 log_info("[%s:%u] Unknown section '%s'. Ignoring.", filename
, line
, n
);
225 if (sections
&& !*section
) {
228 log_info("[%s:%u] Assignment outside of section. Ignoring.", filename
, line
);
235 log_error("[%s:%u] Missing '='.", filename
, line
);
242 return next_assignment(
254 /* Go through the file and parse each line */
256 const char *filename
,
258 const char *sections
,
259 ConfigItemLookup lookup
,
265 char *section
= NULL
;
268 char *continuation
= NULL
;
274 f
= fopen(filename
, "re");
277 log_error("Failed to open configuration file '%s': %s", filename
, strerror(-r
));
285 char l
[LINE_MAX
], *p
, *c
= NULL
, *e
;
286 bool escaped
= false;
288 if (!fgets(l
, sizeof(l
), f
)) {
293 log_error("Failed to read configuration file '%s': %s", filename
, strerror(-r
));
300 c
= strappend(continuation
, l
);
312 for (e
= p
; *e
; e
++) {
325 continuation
= strdup(l
);
335 r
= parse_line(filename
,
362 int config_parse_int(
363 const char *filename
,
380 r
= safe_atoi(rvalue
, i
);
382 log_error("[%s:%u] Failed to parse numeric value, ingoring: %s", filename
, line
, rvalue
);
389 int config_parse_long(
390 const char *filename
,
407 r
= safe_atoli(rvalue
, i
);
409 log_error("[%s:%u] Failed to parse numeric value, ignoring: %s", filename
, line
, rvalue
);
416 int config_parse_uint64(
417 const char *filename
,
434 r
= safe_atou64(rvalue
, u
);
436 log_error("[%s:%u] Failed to parse numeric value, ignoring: %s", filename
, line
, rvalue
);
443 int config_parse_unsigned(
444 const char *filename
,
461 r
= safe_atou(rvalue
, u
);
463 log_error("[%s:%u] Failed to parse numeric value: %s", filename
, line
, rvalue
);
470 int config_parse_double(
471 const char *filename
,
488 r
= safe_atod(rvalue
, d
);
490 log_error("[%s:%u] Failed to parse numeric value: %s", filename
, line
, rvalue
);
497 int config_parse_bytes_size(
498 const char *filename
,
515 if (parse_bytes(rvalue
, &o
) < 0 || (off_t
) (size_t) o
!= o
) {
516 log_error("[%s:%u] Failed to parse byte value, ignoring: %s", filename
, line
, rvalue
);
525 int config_parse_bytes_off(
526 const char *filename
,
542 assert_cc(sizeof(off_t
) == sizeof(uint64_t));
544 if (parse_bytes(rvalue
, bytes
) < 0) {
545 log_error("[%s:%u] Failed to parse bytes value, ignoring: %s", filename
, line
, rvalue
);
552 int config_parse_bool(
553 const char *filename
,
570 if ((k
= parse_boolean(rvalue
)) < 0) {
571 log_error("[%s:%u] Failed to parse boolean value, ignoring: %s", filename
, line
, rvalue
);
579 int config_parse_tristate(
580 const char *filename
,
597 /* Tristates are like booleans, but can also take the 'default' value, i.e. "-1" */
599 k
= parse_boolean(rvalue
);
601 log_error("[%s:%u] Failed to parse boolean value, ignoring: %s", filename
, line
, rvalue
);
609 int config_parse_string(
610 const char *filename
,
631 if (!utf8_is_valid(n
)) {
632 log_error("[%s:%u] String is not UTF-8 clean, ignoring assignment: %s", filename
, line
, rvalue
);
648 int config_parse_path(
649 const char *filename
,
666 if (!utf8_is_valid(rvalue
)) {
667 log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename
, line
, rvalue
);
671 if (!path_is_absolute(rvalue
)) {
672 log_error("[%s:%u] Not an absolute path, ignoring: %s", filename
, line
, rvalue
);
680 path_kill_slashes(n
);
688 int config_parse_strv(
689 const char *filename
,
698 char *** sv
= data
, *w
, *state
;
707 if (isempty(rvalue
)) {
710 /* Empty assignment resets the list. As a special rule
711 * we actually fill in a real empty array here rather
712 * than NULL, since some code wants to know if
713 * something was set at all... */
714 empty
= strv_new(NULL
, NULL
);
723 FOREACH_WORD_QUOTED(w
, l
, rvalue
, state
) {
724 _cleanup_free_
char *n
;
726 n
= cunescape_length(w
, l
);
730 if (!utf8_is_valid(n
)) {
731 log_error("[%s:%u] String is not UTF-8 clean, ignoring: %s", filename
, line
, rvalue
);
735 r
= strv_extend(sv
, n
);
743 int config_parse_path_strv(
744 const char *filename
,
753 char*** sv
= data
, *w
, *state
;
762 if (isempty(rvalue
)) {
763 /* Empty assignment resets the list */
769 FOREACH_WORD_QUOTED(w
, l
, rvalue
, state
) {
770 _cleanup_free_
char *n
;
776 if (!utf8_is_valid(n
)) {
777 log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename
, line
, rvalue
);
781 if (!path_is_absolute(n
)) {
782 log_error("[%s:%u] Not an absolute path, ignoring: %s", filename
, line
, rvalue
);
786 path_kill_slashes(n
);
787 r
= strv_extend(sv
, n
);
795 int config_parse_sec(
796 const char *filename
,
812 if (parse_sec(rvalue
, usec
) < 0) {
813 log_error("[%s:%u] Failed to parse time value, ignoring: %s", filename
, line
, rvalue
);
820 int config_parse_nsec(
821 const char *filename
,
837 if (parse_nsec(rvalue
, nsec
) < 0) {
838 log_error("[%s:%u] Failed to parse time value, ignoring: %s", filename
, line
, rvalue
);
845 int config_parse_mode(
846 const char *filename
,
865 l
= strtol(rvalue
, &x
, 8);
866 if (!x
|| x
== rvalue
|| *x
|| errno
) {
867 log_error("[%s:%u] Failed to parse mode value, ignoring: %s", filename
, line
, rvalue
);
871 if (l
< 0000 || l
> 07777) {
872 log_error("[%s:%u] mode value out of range, ignoring: %s", filename
, line
, rvalue
);
880 int config_parse_facility(
881 const char *filename
,
898 x
= log_facility_unshifted_from_string(rvalue
);
900 log_error("[%s:%u] Failed to parse log facility, ignoring: %s", filename
, line
, rvalue
);
904 *o
= (x
<< 3) | LOG_PRI(*o
);
909 int config_parse_level(
910 const char *filename
,
927 x
= log_level_from_string(rvalue
);
929 log_error("[%s:%u] Failed to parse log level, ignoring: %s", filename
, line
, rvalue
);
933 *o
= (*o
& LOG_FACMASK
) | x
;
937 int config_parse_set_status(
938 const char *filename
,
951 ExitStatusSet
*status_set
= data
;
958 if (isempty(rvalue
)) {
959 /* Empty assignment resets the list */
961 set_free(status_set
->signal
);
962 set_free(status_set
->code
);
964 status_set
->signal
= status_set
->code
= NULL
;
968 FOREACH_WORD(w
, l
, rvalue
, state
) {
972 temp
= strndup(w
, l
);
976 r
= safe_atoi(temp
, &val
);
978 val
= signal_from_string_try_harder(temp
);
982 r
= set_ensure_allocated(&status_set
->signal
, trivial_hash_func
, trivial_compare_func
);
986 r
= set_put(status_set
->signal
, INT_TO_PTR(val
));
988 log_error("[%s:%u] Unable to store: %s", filename
, line
, w
);
992 log_error("[%s:%u] Failed to parse value, ignoring: %s", filename
, line
, w
);
998 if (val
< 0 || val
> 255)
999 log_warning("[%s:%u] Value %d is outside range 0-255, ignoring", filename
, line
, val
);
1001 r
= set_ensure_allocated(&status_set
->code
, trivial_hash_func
, trivial_compare_func
);
1005 r
= set_put(status_set
->code
, INT_TO_PTR(val
));
1007 log_error("[%s:%u] Unable to store: %s", filename
, line
, w
);