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 "sd-messages.h"
28 #include "conf-files.h"
34 #include "path-util.h"
35 #include "signal-util.h"
36 #include "conf-parser.h"
38 int config_item_table_lookup(
42 ConfigParserCallback
*func
,
47 const ConfigTableItem
*t
;
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(const char *unit
,
114 const char *filename
,
116 ConfigItemLookup lookup
,
119 unsigned section_line
,
125 ConfigParserCallback func
= NULL
;
136 r
= lookup(table
, section
, lvalue
, &func
, <ype
, &data
, userdata
);
142 return func(unit
, filename
, line
, section
, section_line
,
143 lvalue
, ltype
, rvalue
, data
, userdata
);
148 /* Warn about unknown non-extension fields. */
149 if (!relaxed
&& !startswith(lvalue
, "X-"))
150 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Unknown lvalue '%s' in section '%s'", lvalue
, section
);
155 /* Parse a variable assignment line */
156 static int parse_line(const char* unit
,
157 const char *filename
,
159 const char *sections
,
160 ConfigItemLookup lookup
,
165 unsigned *section_line
,
166 bool *section_ignored
,
182 if (strchr(COMMENTS
"\n", *l
))
185 if (startswith(l
, ".include ")) {
186 _cleanup_free_
char *fn
= NULL
;
188 /* .includes are a bad idea, we only support them here
189 * for historical reasons. They create cyclic include
190 * problems and make it difficult to detect
191 * configuration file changes with an easy
192 * stat(). Better approaches, such as .d/ drop-in
195 * Support for them should be eventually removed. */
197 if (!allow_include
) {
198 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, ".include not allowed here. Ignoring.");
202 fn
= file_in_same_dir(filename
, strstrip(l
+9));
206 return config_parse(unit
, fn
, NULL
, sections
, lookup
, table
, relaxed
, false, false, userdata
);
217 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid section header '%s'", l
);
221 n
= strndup(l
+1, k
-2);
225 if (sections
&& !nulstr_contains(sections
, n
)) {
227 if (!relaxed
&& !startswith(n
, "X-"))
228 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Unknown section '%s'. Ignoring.", n
);
231 *section
= mfree(*section
);
233 *section_ignored
= true;
237 *section_line
= line
;
238 *section_ignored
= false;
244 if (sections
&& !*section
) {
246 if (!relaxed
&& !*section_ignored
)
247 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Assignment outside of section. Ignoring.");
254 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Missing '='.");
261 return next_assignment(unit
,
274 /* Go through the file and parse each line */
275 int config_parse(const char *unit
,
276 const char *filename
,
278 const char *sections
,
279 ConfigItemLookup lookup
,
286 _cleanup_free_
char *section
= NULL
, *continuation
= NULL
;
287 _cleanup_fclose_
FILE *ours
= NULL
;
288 unsigned line
= 0, section_line
= 0;
289 bool section_ignored
= false;
296 f
= ours
= fopen(filename
, "re");
298 /* Only log on request, except for ENOENT,
299 * since we return 0 to the caller. */
300 if (warn
|| errno
== ENOENT
)
301 log_full(errno
== ENOENT
? LOG_DEBUG
: LOG_ERR
,
302 "Failed to open configuration file '%s': %m", filename
);
303 return errno
== ENOENT
? 0 : -errno
;
307 fd_warn_permissions(filename
, fileno(f
));
310 char l
[LINE_MAX
], *p
, *c
= NULL
, *e
;
311 bool escaped
= false;
313 if (!fgets(l
, sizeof(l
), f
)) {
317 log_error_errno(errno
, "Failed to read configuration file '%s': %m", filename
);
324 c
= strappend(continuation
, l
);
331 continuation
= mfree(continuation
);
336 for (e
= p
; *e
; e
++) {
349 continuation
= strdup(l
);
377 log_warning_errno(r
, "Failed to parse file '%s': %m",
386 /* Parse each config file in the specified directories. */
387 int config_parse_many(const char *conf_file
,
388 const char *conf_file_dirs
,
389 const char *sections
,
390 ConfigItemLookup lookup
,
394 _cleanup_strv_free_
char **files
= NULL
;
398 r
= conf_files_list_nulstr(&files
, ".conf", NULL
, conf_file_dirs
);
403 r
= config_parse(NULL
, conf_file
, NULL
, sections
, lookup
, table
, relaxed
, false, true, userdata
);
408 STRV_FOREACH(fn
, files
) {
409 r
= config_parse(NULL
, *fn
, NULL
, sections
, lookup
, table
, relaxed
, false, true, userdata
);
417 #define DEFINE_PARSER(type, vartype, conv_func) \
418 int config_parse_##type( \
420 const char *filename, \
422 const char *section, \
423 unsigned section_line, \
424 const char *lvalue, \
426 const char *rvalue, \
438 r = conv_func(rvalue, i); \
440 log_syntax(unit, LOG_ERR, filename, line, r, \
441 "Failed to parse %s value, ignoring: %s", \
446 struct __useless_struct_to_allow_trailing_semicolon__
448 DEFINE_PARSER(int, int, safe_atoi
);
449 DEFINE_PARSER(long, long, safe_atoli
);
450 DEFINE_PARSER(uint32
, uint32_t, safe_atou32
);
451 DEFINE_PARSER(uint64
, uint64_t, safe_atou64
);
452 DEFINE_PARSER(unsigned, unsigned, safe_atou
);
453 DEFINE_PARSER(double, double, safe_atod
);
454 DEFINE_PARSER(nsec
, nsec_t
, parse_nsec
);
455 DEFINE_PARSER(sec
, usec_t
, parse_sec
);
456 DEFINE_PARSER(mode
, mode_t
, parse_mode
);
458 int config_parse_iec_size(const char* unit
,
459 const char *filename
,
462 unsigned section_line
,
478 r
= parse_size(rvalue
, 1024, &v
);
479 if (r
< 0 || (uint64_t) (size_t) v
!= v
) {
480 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse size value, ignoring: %s", rvalue
);
488 int config_parse_si_size(const char* unit
,
489 const char *filename
,
492 unsigned section_line
,
508 r
= parse_size(rvalue
, 1000, &v
);
509 if (r
< 0 || (uint64_t) (size_t) v
!= v
) {
510 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse size value, ignoring: %s", rvalue
);
518 int config_parse_iec_uint64(const char* unit
,
519 const char *filename
,
522 unsigned section_line
,
529 uint64_t *bytes
= data
;
537 r
= parse_size(rvalue
, 1024, bytes
);
539 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse size value, ignoring: %s", rvalue
);
544 int config_parse_bool(const char* unit
,
545 const char *filename
,
548 unsigned section_line
,
563 k
= parse_boolean(rvalue
);
565 log_syntax(unit
, LOG_ERR
, filename
, line
, k
, "Failed to parse boolean value, ignoring: %s", rvalue
);
573 int config_parse_tristate(
575 const char *filename
,
578 unsigned section_line
,
592 /* A tristate is pretty much a boolean, except that it can
593 * also take the special value -1, indicating "uninitialized",
594 * much like NULL is for a pointer type. */
596 k
= parse_boolean(rvalue
);
598 log_syntax(unit
, LOG_ERR
, filename
, line
, k
, "Failed to parse boolean value, ignoring: %s", rvalue
);
606 int config_parse_string(
608 const char *filename
,
611 unsigned section_line
,
625 if (!utf8_is_valid(rvalue
)) {
626 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
644 int config_parse_path(
646 const char *filename
,
649 unsigned section_line
,
663 if (!utf8_is_valid(rvalue
)) {
664 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
668 if (!path_is_absolute(rvalue
)) {
669 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Not an absolute path, ignoring: %s", rvalue
);
677 path_kill_slashes(n
);
685 int config_parse_strv(const char *unit
,
686 const char *filename
,
689 unsigned section_line
,
697 const char *word
, *state
;
706 if (isempty(rvalue
)) {
709 /* Empty assignment resets the list. As a special rule
710 * we actually fill in a real empty array here rather
711 * than NULL, since some code wants to know if
712 * something was set at all... */
713 empty
= strv_new(NULL
, NULL
);
722 FOREACH_WORD_QUOTED(word
, l
, rvalue
, state
) {
725 n
= strndup(word
, l
);
729 if (!utf8_is_valid(n
)) {
730 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
735 r
= strv_consume(sv
, n
);
740 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
745 int config_parse_log_facility(
747 const char *filename
,
750 unsigned section_line
,
765 x
= log_facility_unshifted_from_string(rvalue
);
767 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse log facility, ignoring: %s", rvalue
);
771 *o
= (x
<< 3) | LOG_PRI(*o
);
776 int config_parse_log_level(
778 const char *filename
,
781 unsigned section_line
,
796 x
= log_level_from_string(rvalue
);
798 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse log level, ignoring: %s", rvalue
);
802 *o
= (*o
& LOG_FACMASK
) | x
;
806 int config_parse_signal(
808 const char *filename
,
811 unsigned section_line
,
825 r
= signal_from_string_try_harder(rvalue
);
827 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse signal name, ignoring: %s", rvalue
);
835 int config_parse_personality(
837 const char *filename
,
840 unsigned section_line
,
847 unsigned long *personality
= data
, p
;
854 p
= personality_from_string(rvalue
);
855 if (p
== PERSONALITY_INVALID
) {
856 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse personality, ignoring: %s", rvalue
);