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"
41 int config_item_table_lookup(
45 ConfigParserCallback
*func
,
50 const ConfigTableItem
*t
;
58 for (t
= table
; t
->lvalue
; t
++) {
60 if (!streq(lvalue
, t
->lvalue
))
63 if (!streq_ptr(section
, t
->section
))
75 int config_item_perf_lookup(
79 ConfigParserCallback
*func
,
84 ConfigPerfItemLookup lookup
= (ConfigPerfItemLookup
) table
;
85 const ConfigPerfItem
*p
;
94 p
= lookup(lvalue
, strlen(lvalue
));
98 key
= strjoin(section
, ".", lvalue
, NULL
);
102 p
= lookup(key
, strlen(key
));
111 *data
= (uint8_t*) userdata
+ p
->offset
;
115 /* Run the user supplied parser for an assignment */
116 static int next_assignment(const char *unit
,
117 const char *filename
,
119 ConfigItemLookup lookup
,
122 unsigned section_line
,
128 ConfigParserCallback func
= NULL
;
139 r
= lookup(table
, section
, lvalue
, &func
, <ype
, &data
, userdata
);
145 return func(unit
, filename
, line
, section
, section_line
,
146 lvalue
, ltype
, rvalue
, data
, userdata
);
151 /* Warn about unknown non-extension fields. */
152 if (!relaxed
&& !startswith(lvalue
, "X-"))
153 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Unknown lvalue '%s' in section '%s'", lvalue
, section
);
158 /* Parse a variable assignment line */
159 static int parse_line(const char* unit
,
160 const char *filename
,
162 const char *sections
,
163 ConfigItemLookup lookup
,
168 unsigned *section_line
,
169 bool *section_ignored
,
185 if (strchr(COMMENTS
"\n", *l
))
188 if (startswith(l
, ".include ")) {
189 _cleanup_free_
char *fn
= NULL
;
191 /* .includes are a bad idea, we only support them here
192 * for historical reasons. They create cyclic include
193 * problems and make it difficult to detect
194 * configuration file changes with an easy
195 * stat(). Better approaches, such as .d/ drop-in
198 * Support for them should be eventually removed. */
200 if (!allow_include
) {
201 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, ".include not allowed here. Ignoring.");
205 fn
= file_in_same_dir(filename
, strstrip(l
+9));
209 return config_parse(unit
, fn
, NULL
, sections
, lookup
, table
, relaxed
, false, false, userdata
);
220 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid section header '%s'", l
);
224 n
= strndup(l
+1, k
-2);
228 if (sections
&& !nulstr_contains(sections
, n
)) {
230 if (!relaxed
&& !startswith(n
, "X-"))
231 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Unknown section '%s'. Ignoring.", n
);
234 *section
= mfree(*section
);
236 *section_ignored
= true;
240 *section_line
= line
;
241 *section_ignored
= false;
247 if (sections
&& !*section
) {
249 if (!relaxed
&& !*section_ignored
)
250 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Assignment outside of section. Ignoring.");
257 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Missing '='.");
264 return next_assignment(unit
,
277 /* Go through the file and parse each line */
278 int config_parse(const char *unit
,
279 const char *filename
,
281 const char *sections
,
282 ConfigItemLookup lookup
,
289 _cleanup_free_
char *section
= NULL
, *continuation
= NULL
;
290 _cleanup_fclose_
FILE *ours
= NULL
;
291 unsigned line
= 0, section_line
= 0;
292 bool section_ignored
= false;
299 f
= ours
= fopen(filename
, "re");
301 /* Only log on request, except for ENOENT,
302 * since we return 0 to the caller. */
303 if (warn
|| errno
== ENOENT
)
304 log_full(errno
== ENOENT
? LOG_DEBUG
: LOG_ERR
,
305 "Failed to open configuration file '%s': %m", filename
);
306 return errno
== ENOENT
? 0 : -errno
;
310 fd_warn_permissions(filename
, fileno(f
));
313 char l
[LINE_MAX
], *p
, *c
= NULL
, *e
;
314 bool escaped
= false;
316 if (!fgets(l
, sizeof(l
), f
)) {
320 log_error_errno(errno
, "Failed to read configuration file '%s': %m", filename
);
327 c
= strappend(continuation
, l
);
334 continuation
= mfree(continuation
);
339 for (e
= p
; *e
; e
++) {
352 continuation
= strdup(l
);
380 log_warning_errno(r
, "Failed to parse file '%s': %m",
389 /* Parse each config file in the specified directories. */
390 int config_parse_many(const char *conf_file
,
391 const char *conf_file_dirs
,
392 const char *sections
,
393 ConfigItemLookup lookup
,
397 _cleanup_strv_free_
char **files
= NULL
;
401 r
= conf_files_list_nulstr(&files
, ".conf", NULL
, conf_file_dirs
);
406 r
= config_parse(NULL
, conf_file
, NULL
, sections
, lookup
, table
, relaxed
, false, true, userdata
);
411 STRV_FOREACH(fn
, files
) {
412 r
= config_parse(NULL
, *fn
, NULL
, sections
, lookup
, table
, relaxed
, false, true, userdata
);
420 #define DEFINE_PARSER(type, vartype, conv_func) \
421 int config_parse_##type( \
423 const char *filename, \
425 const char *section, \
426 unsigned section_line, \
427 const char *lvalue, \
429 const char *rvalue, \
441 r = conv_func(rvalue, i); \
443 log_syntax(unit, LOG_ERR, filename, line, r, \
444 "Failed to parse %s value, ignoring: %s", \
449 struct __useless_struct_to_allow_trailing_semicolon__
451 DEFINE_PARSER(int, int, safe_atoi
);
452 DEFINE_PARSER(long, long, safe_atoli
);
453 DEFINE_PARSER(uint32
, uint32_t, safe_atou32
);
454 DEFINE_PARSER(uint64
, uint64_t, safe_atou64
);
455 DEFINE_PARSER(unsigned, unsigned, safe_atou
);
456 DEFINE_PARSER(double, double, safe_atod
);
457 DEFINE_PARSER(nsec
, nsec_t
, parse_nsec
);
458 DEFINE_PARSER(sec
, usec_t
, parse_sec
);
459 DEFINE_PARSER(mode
, mode_t
, parse_mode
);
461 int config_parse_iec_size(const char* unit
,
462 const char *filename
,
465 unsigned section_line
,
481 r
= parse_size(rvalue
, 1024, &v
);
482 if (r
< 0 || (uint64_t) (size_t) v
!= v
) {
483 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse size value, ignoring: %s", rvalue
);
491 int config_parse_si_size(const char* unit
,
492 const char *filename
,
495 unsigned section_line
,
511 r
= parse_size(rvalue
, 1000, &v
);
512 if (r
< 0 || (uint64_t) (size_t) v
!= v
) {
513 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse size value, ignoring: %s", rvalue
);
521 int config_parse_iec_uint64(const char* unit
,
522 const char *filename
,
525 unsigned section_line
,
532 uint64_t *bytes
= data
;
540 r
= parse_size(rvalue
, 1024, bytes
);
542 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse size value, ignoring: %s", rvalue
);
547 int config_parse_bool(const char* unit
,
548 const char *filename
,
551 unsigned section_line
,
566 k
= parse_boolean(rvalue
);
568 log_syntax(unit
, LOG_ERR
, filename
, line
, k
, "Failed to parse boolean value, ignoring: %s", rvalue
);
576 int config_parse_tristate(
578 const char *filename
,
581 unsigned section_line
,
595 /* A tristate is pretty much a boolean, except that it can
596 * also take the special value -1, indicating "uninitialized",
597 * much like NULL is for a pointer type. */
599 k
= parse_boolean(rvalue
);
601 log_syntax(unit
, LOG_ERR
, filename
, line
, k
, "Failed to parse boolean value, ignoring: %s", rvalue
);
609 int config_parse_string(
611 const char *filename
,
614 unsigned section_line
,
628 if (!utf8_is_valid(rvalue
)) {
629 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
647 int config_parse_path(
649 const char *filename
,
652 unsigned section_line
,
666 if (!utf8_is_valid(rvalue
)) {
667 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
671 if (!path_is_absolute(rvalue
)) {
672 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Not an absolute path, ignoring: %s", rvalue
);
680 path_kill_slashes(n
);
688 int config_parse_strv(const char *unit
,
689 const char *filename
,
692 unsigned section_line
,
700 const char *word
, *state
;
709 if (isempty(rvalue
)) {
712 /* Empty assignment resets the list. As a special rule
713 * we actually fill in a real empty array here rather
714 * than NULL, since some code wants to know if
715 * something was set at all... */
716 empty
= strv_new(NULL
, NULL
);
725 FOREACH_WORD_QUOTED(word
, l
, rvalue
, state
) {
728 n
= strndup(word
, l
);
732 if (!utf8_is_valid(n
)) {
733 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
738 r
= strv_consume(sv
, n
);
743 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
748 int config_parse_log_facility(
750 const char *filename
,
753 unsigned section_line
,
768 x
= log_facility_unshifted_from_string(rvalue
);
770 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse log facility, ignoring: %s", rvalue
);
774 *o
= (x
<< 3) | LOG_PRI(*o
);
779 int config_parse_log_level(
781 const char *filename
,
784 unsigned section_line
,
799 x
= log_level_from_string(rvalue
);
801 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse log level, ignoring: %s", rvalue
);
805 *o
= (*o
& LOG_FACMASK
) | x
;
809 int config_parse_signal(
811 const char *filename
,
814 unsigned section_line
,
828 r
= signal_from_string_try_harder(rvalue
);
830 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse signal name, ignoring: %s", rvalue
);
838 int config_parse_personality(
840 const char *filename
,
843 unsigned section_line
,
850 unsigned long *personality
= data
, p
;
857 p
= personality_from_string(rvalue
);
858 if (p
== PERSONALITY_INVALID
) {
859 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse personality, ignoring: %s", rvalue
);