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"
29 #include "conf-files.h"
32 #include "path-util.h"
33 #include "signal-util.h"
34 #include "string-util.h"
38 #include "conf-parser.h"
40 int config_item_table_lookup(
44 ConfigParserCallback
*func
,
49 const ConfigTableItem
*t
;
57 for (t
= table
; t
->lvalue
; t
++) {
59 if (!streq(lvalue
, t
->lvalue
))
62 if (!streq_ptr(section
, t
->section
))
74 int config_item_perf_lookup(
78 ConfigParserCallback
*func
,
83 ConfigPerfItemLookup lookup
= (ConfigPerfItemLookup
) table
;
84 const ConfigPerfItem
*p
;
93 p
= lookup(lvalue
, strlen(lvalue
));
97 key
= strjoin(section
, ".", lvalue
, NULL
);
101 p
= lookup(key
, strlen(key
));
110 *data
= (uint8_t*) userdata
+ p
->offset
;
114 /* Run the user supplied parser for an assignment */
115 static int next_assignment(const char *unit
,
116 const char *filename
,
118 ConfigItemLookup lookup
,
121 unsigned section_line
,
127 ConfigParserCallback func
= NULL
;
138 r
= lookup(table
, section
, lvalue
, &func
, <ype
, &data
, userdata
);
144 return func(unit
, filename
, line
, section
, section_line
,
145 lvalue
, ltype
, rvalue
, data
, userdata
);
150 /* Warn about unknown non-extension fields. */
151 if (!relaxed
&& !startswith(lvalue
, "X-"))
152 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Unknown lvalue '%s' in section '%s'", lvalue
, section
);
157 /* Parse a variable assignment line */
158 static int parse_line(const char* unit
,
159 const char *filename
,
161 const char *sections
,
162 ConfigItemLookup lookup
,
167 unsigned *section_line
,
168 bool *section_ignored
,
184 if (strchr(COMMENTS
"\n", *l
))
187 if (startswith(l
, ".include ")) {
188 _cleanup_free_
char *fn
= NULL
;
190 /* .includes are a bad idea, we only support them here
191 * for historical reasons. They create cyclic include
192 * problems and make it difficult to detect
193 * configuration file changes with an easy
194 * stat(). Better approaches, such as .d/ drop-in
197 * Support for them should be eventually removed. */
199 if (!allow_include
) {
200 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, ".include not allowed here. Ignoring.");
204 fn
= file_in_same_dir(filename
, strstrip(l
+9));
208 return config_parse(unit
, fn
, NULL
, sections
, lookup
, table
, relaxed
, false, false, userdata
);
219 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid section header '%s'", l
);
223 n
= strndup(l
+1, k
-2);
227 if (sections
&& !nulstr_contains(sections
, n
)) {
229 if (!relaxed
&& !startswith(n
, "X-"))
230 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Unknown section '%s'. Ignoring.", n
);
233 *section
= mfree(*section
);
235 *section_ignored
= true;
239 *section_line
= line
;
240 *section_ignored
= false;
246 if (sections
&& !*section
) {
248 if (!relaxed
&& !*section_ignored
)
249 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Assignment outside of section. Ignoring.");
256 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Missing '='.");
263 return next_assignment(unit
,
276 /* Go through the file and parse each line */
277 int config_parse(const char *unit
,
278 const char *filename
,
280 const char *sections
,
281 ConfigItemLookup lookup
,
288 _cleanup_free_
char *section
= NULL
, *continuation
= NULL
;
289 _cleanup_fclose_
FILE *ours
= NULL
;
290 unsigned line
= 0, section_line
= 0;
291 bool section_ignored
= false;
298 f
= ours
= fopen(filename
, "re");
300 /* Only log on request, except for ENOENT,
301 * since we return 0 to the caller. */
302 if (warn
|| errno
== ENOENT
)
303 log_full(errno
== ENOENT
? LOG_DEBUG
: LOG_ERR
,
304 "Failed to open configuration file '%s': %m", filename
);
305 return errno
== ENOENT
? 0 : -errno
;
309 fd_warn_permissions(filename
, fileno(f
));
312 char l
[LINE_MAX
], *p
, *c
= NULL
, *e
;
313 bool escaped
= false;
315 if (!fgets(l
, sizeof(l
), f
)) {
319 log_error_errno(errno
, "Failed to read configuration file '%s': %m", filename
);
326 c
= strappend(continuation
, l
);
333 continuation
= mfree(continuation
);
338 for (e
= p
; *e
; e
++) {
351 continuation
= strdup(l
);
379 log_warning_errno(r
, "Failed to parse file '%s': %m",
388 /* Parse each config file in the specified directories. */
389 int config_parse_many(const char *conf_file
,
390 const char *conf_file_dirs
,
391 const char *sections
,
392 ConfigItemLookup lookup
,
396 _cleanup_strv_free_
char **files
= NULL
;
400 r
= conf_files_list_nulstr(&files
, ".conf", NULL
, conf_file_dirs
);
405 r
= config_parse(NULL
, conf_file
, NULL
, sections
, lookup
, table
, relaxed
, false, true, userdata
);
410 STRV_FOREACH(fn
, files
) {
411 r
= config_parse(NULL
, *fn
, NULL
, sections
, lookup
, table
, relaxed
, false, true, userdata
);
419 #define DEFINE_PARSER(type, vartype, conv_func) \
420 int config_parse_##type( \
422 const char *filename, \
424 const char *section, \
425 unsigned section_line, \
426 const char *lvalue, \
428 const char *rvalue, \
440 r = conv_func(rvalue, i); \
442 log_syntax(unit, LOG_ERR, filename, line, r, \
443 "Failed to parse %s value, ignoring: %s", \
448 struct __useless_struct_to_allow_trailing_semicolon__
450 DEFINE_PARSER(int, int, safe_atoi
);
451 DEFINE_PARSER(long, long, safe_atoli
);
452 DEFINE_PARSER(uint32
, uint32_t, safe_atou32
);
453 DEFINE_PARSER(uint64
, uint64_t, safe_atou64
);
454 DEFINE_PARSER(unsigned, unsigned, safe_atou
);
455 DEFINE_PARSER(double, double, safe_atod
);
456 DEFINE_PARSER(nsec
, nsec_t
, parse_nsec
);
457 DEFINE_PARSER(sec
, usec_t
, parse_sec
);
458 DEFINE_PARSER(mode
, mode_t
, parse_mode
);
460 int config_parse_iec_size(const char* unit
,
461 const char *filename
,
464 unsigned section_line
,
480 r
= parse_size(rvalue
, 1024, &v
);
481 if (r
< 0 || (uint64_t) (size_t) v
!= v
) {
482 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse size value, ignoring: %s", rvalue
);
490 int config_parse_si_size(const char* unit
,
491 const char *filename
,
494 unsigned section_line
,
510 r
= parse_size(rvalue
, 1000, &v
);
511 if (r
< 0 || (uint64_t) (size_t) v
!= v
) {
512 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse size value, ignoring: %s", rvalue
);
520 int config_parse_iec_uint64(const char* unit
,
521 const char *filename
,
524 unsigned section_line
,
531 uint64_t *bytes
= data
;
539 r
= parse_size(rvalue
, 1024, bytes
);
541 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse size value, ignoring: %s", rvalue
);
546 int config_parse_bool(const char* unit
,
547 const char *filename
,
550 unsigned section_line
,
565 k
= parse_boolean(rvalue
);
567 log_syntax(unit
, LOG_ERR
, filename
, line
, k
, "Failed to parse boolean value, ignoring: %s", rvalue
);
575 int config_parse_tristate(
577 const char *filename
,
580 unsigned section_line
,
594 /* A tristate is pretty much a boolean, except that it can
595 * also take the special value -1, indicating "uninitialized",
596 * much like NULL is for a pointer type. */
598 k
= parse_boolean(rvalue
);
600 log_syntax(unit
, LOG_ERR
, filename
, line
, k
, "Failed to parse boolean value, ignoring: %s", rvalue
);
608 int config_parse_string(
610 const char *filename
,
613 unsigned section_line
,
627 if (!utf8_is_valid(rvalue
)) {
628 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
646 int config_parse_path(
648 const char *filename
,
651 unsigned section_line
,
665 if (!utf8_is_valid(rvalue
)) {
666 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
670 if (!path_is_absolute(rvalue
)) {
671 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Not an absolute path, ignoring: %s", rvalue
);
679 path_kill_slashes(n
);
687 int config_parse_strv(const char *unit
,
688 const char *filename
,
691 unsigned section_line
,
699 const char *word
, *state
;
708 if (isempty(rvalue
)) {
711 /* Empty assignment resets the list. As a special rule
712 * we actually fill in a real empty array here rather
713 * than NULL, since some code wants to know if
714 * something was set at all... */
715 empty
= strv_new(NULL
, NULL
);
724 FOREACH_WORD_QUOTED(word
, l
, rvalue
, state
) {
727 n
= strndup(word
, l
);
731 if (!utf8_is_valid(n
)) {
732 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
737 r
= strv_consume(sv
, n
);
742 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
747 int config_parse_log_facility(
749 const char *filename
,
752 unsigned section_line
,
767 x
= log_facility_unshifted_from_string(rvalue
);
769 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse log facility, ignoring: %s", rvalue
);
773 *o
= (x
<< 3) | LOG_PRI(*o
);
778 int config_parse_log_level(
780 const char *filename
,
783 unsigned section_line
,
798 x
= log_level_from_string(rvalue
);
800 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse log level, ignoring: %s", rvalue
);
804 *o
= (*o
& LOG_FACMASK
) | x
;
808 int config_parse_signal(
810 const char *filename
,
813 unsigned section_line
,
827 r
= signal_from_string_try_harder(rvalue
);
829 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse signal name, ignoring: %s", rvalue
);
837 int config_parse_personality(
839 const char *filename
,
842 unsigned section_line
,
849 unsigned long *personality
= data
, p
;
856 p
= personality_from_string(rvalue
);
857 if (p
== PERSONALITY_INVALID
) {
858 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse personality, ignoring: %s", rvalue
);