2 This file is part of systemd.
4 Copyright 2010 Lennart Poettering
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
26 #include <sys/types.h>
28 #include "alloc-util.h"
29 #include "conf-files.h"
30 #include "conf-parser.h"
31 #include "extract-word.h"
36 #include "parse-util.h"
37 #include "path-util.h"
38 #include "process-util.h"
39 #include "signal-util.h"
40 #include "socket-util.h"
41 #include "string-util.h"
43 #include "syslog-util.h"
44 #include "time-util.h"
47 int config_item_table_lookup(
51 ConfigParserCallback
*func
,
56 const ConfigTableItem
*t
;
64 for (t
= table
; t
->lvalue
; t
++) {
66 if (!streq(lvalue
, t
->lvalue
))
69 if (!streq_ptr(section
, t
->section
))
81 int config_item_perf_lookup(
85 ConfigParserCallback
*func
,
90 ConfigPerfItemLookup lookup
= (ConfigPerfItemLookup
) table
;
91 const ConfigPerfItem
*p
;
100 p
= lookup(lvalue
, strlen(lvalue
));
104 key
= strjoin(section
, ".", lvalue
, NULL
);
108 p
= lookup(key
, strlen(key
));
117 *data
= (uint8_t*) userdata
+ p
->offset
;
121 /* Run the user supplied parser for an assignment */
122 static int next_assignment(const char *unit
,
123 const char *filename
,
125 ConfigItemLookup lookup
,
128 unsigned section_line
,
134 ConfigParserCallback func
= NULL
;
145 r
= lookup(table
, section
, lvalue
, &func
, <ype
, &data
, userdata
);
151 return func(unit
, filename
, line
, section
, section_line
,
152 lvalue
, ltype
, rvalue
, data
, userdata
);
157 /* Warn about unknown non-extension fields. */
158 if (!relaxed
&& !startswith(lvalue
, "X-"))
159 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Unknown lvalue '%s' in section '%s'", lvalue
, section
);
164 /* Parse a variable assignment line */
165 static int parse_line(const char* unit
,
166 const char *filename
,
168 const char *sections
,
169 ConfigItemLookup lookup
,
174 unsigned *section_line
,
175 bool *section_ignored
,
191 if (strchr(COMMENTS
"\n", *l
))
194 if (startswith(l
, ".include ")) {
195 _cleanup_free_
char *fn
= NULL
;
197 /* .includes are a bad idea, we only support them here
198 * for historical reasons. They create cyclic include
199 * problems and make it difficult to detect
200 * configuration file changes with an easy
201 * stat(). Better approaches, such as .d/ drop-in
204 * Support for them should be eventually removed. */
206 if (!allow_include
) {
207 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, ".include not allowed here. Ignoring.");
211 fn
= file_in_same_dir(filename
, strstrip(l
+9));
215 return config_parse(unit
, fn
, NULL
, sections
, lookup
, table
, relaxed
, false, false, userdata
);
226 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid section header '%s'", l
);
230 n
= strndup(l
+1, k
-2);
234 if (sections
&& !nulstr_contains(sections
, n
)) {
236 if (!relaxed
&& !startswith(n
, "X-"))
237 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Unknown section '%s'. Ignoring.", n
);
240 *section
= mfree(*section
);
242 *section_ignored
= true;
246 *section_line
= line
;
247 *section_ignored
= false;
253 if (sections
&& !*section
) {
255 if (!relaxed
&& !*section_ignored
)
256 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Assignment outside of section. Ignoring.");
263 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Missing '='.");
270 return next_assignment(unit
,
283 /* Go through the file and parse each line */
284 int config_parse(const char *unit
,
285 const char *filename
,
287 const char *sections
,
288 ConfigItemLookup lookup
,
295 _cleanup_free_
char *section
= NULL
, *continuation
= NULL
;
296 _cleanup_fclose_
FILE *ours
= NULL
;
297 unsigned line
= 0, section_line
= 0;
298 bool section_ignored
= false, allow_bom
= true;
305 f
= ours
= fopen(filename
, "re");
307 /* Only log on request, except for ENOENT,
308 * since we return 0 to the caller. */
309 if (warn
|| errno
== ENOENT
)
310 log_full(errno
== ENOENT
? LOG_DEBUG
: LOG_ERR
,
311 "Failed to open configuration file '%s': %m", filename
);
312 return errno
== ENOENT
? 0 : -errno
;
316 fd_warn_permissions(filename
, fileno(f
));
319 char buf
[LINE_MAX
], *l
, *p
, *c
= NULL
, *e
;
320 bool escaped
= false;
322 if (!fgets(buf
, sizeof buf
, f
)) {
326 return log_error_errno(errno
, "Failed to read configuration file '%s': %m", filename
);
330 if (allow_bom
&& startswith(l
, UTF8_BYTE_ORDER_MARK
))
331 l
+= strlen(UTF8_BYTE_ORDER_MARK
);
337 c
= strappend(continuation
, l
);
344 continuation
= mfree(continuation
);
349 for (e
= p
; *e
; e
++) {
362 continuation
= strdup(l
);
390 log_warning_errno(r
, "Failed to parse file '%s': %m",
399 static int config_parse_many_files(
400 const char *conf_file
,
402 const char *sections
,
403 ConfigItemLookup lookup
,
412 r
= config_parse(NULL
, conf_file
, NULL
, sections
, lookup
, table
, relaxed
, false, true, userdata
);
417 STRV_FOREACH(fn
, files
) {
418 r
= config_parse(NULL
, *fn
, NULL
, sections
, lookup
, table
, relaxed
, false, true, userdata
);
426 /* Parse each config file in the directories specified as nulstr. */
427 int config_parse_many_nulstr(
428 const char *conf_file
,
429 const char *conf_file_dirs
,
430 const char *sections
,
431 ConfigItemLookup lookup
,
436 _cleanup_strv_free_
char **files
= NULL
;
439 r
= conf_files_list_nulstr(&files
, ".conf", NULL
, conf_file_dirs
);
443 return config_parse_many_files(conf_file
, files
,
444 sections
, lookup
, table
, relaxed
, userdata
);
447 /* Parse each config file in the directories specified as strv. */
448 int config_parse_many(
449 const char *conf_file
,
450 const char* const* conf_file_dirs
,
451 const char *dropin_dirname
,
452 const char *sections
,
453 ConfigItemLookup lookup
,
458 _cleanup_strv_free_
char **dropin_dirs
= NULL
;
459 _cleanup_strv_free_
char **files
= NULL
;
463 suffix
= strjoina("/", dropin_dirname
);
464 r
= strv_extend_strv_concat(&dropin_dirs
, (char**) conf_file_dirs
, suffix
);
468 r
= conf_files_list_strv(&files
, ".conf", NULL
, (const char* const*) dropin_dirs
);
472 return config_parse_many_files(conf_file
, files
,
473 sections
, lookup
, table
, relaxed
, userdata
);
476 #define DEFINE_PARSER(type, vartype, conv_func) \
477 int config_parse_##type( \
479 const char *filename, \
481 const char *section, \
482 unsigned section_line, \
483 const char *lvalue, \
485 const char *rvalue, \
497 r = conv_func(rvalue, i); \
499 log_syntax(unit, LOG_ERR, filename, line, r, \
500 "Failed to parse %s value, ignoring: %s", \
505 struct __useless_struct_to_allow_trailing_semicolon__
507 DEFINE_PARSER(int, int, safe_atoi
);
508 DEFINE_PARSER(long, long, safe_atoli
);
509 DEFINE_PARSER(uint16
, uint16_t, safe_atou16
);
510 DEFINE_PARSER(uint32
, uint32_t, safe_atou32
);
511 DEFINE_PARSER(uint64
, uint64_t, safe_atou64
);
512 DEFINE_PARSER(unsigned, unsigned, safe_atou
);
513 DEFINE_PARSER(double, double, safe_atod
);
514 DEFINE_PARSER(nsec
, nsec_t
, parse_nsec
);
515 DEFINE_PARSER(sec
, usec_t
, parse_sec
);
516 DEFINE_PARSER(mode
, mode_t
, parse_mode
);
518 int config_parse_iec_size(const char* unit
,
519 const char *filename
,
522 unsigned section_line
,
538 r
= parse_size(rvalue
, 1024, &v
);
539 if (r
< 0 || (uint64_t) (size_t) v
!= v
) {
540 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse size value, ignoring: %s", rvalue
);
548 int config_parse_si_size(const char* unit
,
549 const char *filename
,
552 unsigned section_line
,
568 r
= parse_size(rvalue
, 1000, &v
);
569 if (r
< 0 || (uint64_t) (size_t) v
!= v
) {
570 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse size value, ignoring: %s", rvalue
);
578 int config_parse_iec_uint64(const char* unit
,
579 const char *filename
,
582 unsigned section_line
,
589 uint64_t *bytes
= data
;
597 r
= parse_size(rvalue
, 1024, bytes
);
599 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse size value, ignoring: %s", rvalue
);
604 int config_parse_bool(const char* unit
,
605 const char *filename
,
608 unsigned section_line
,
623 k
= parse_boolean(rvalue
);
625 log_syntax(unit
, LOG_ERR
, filename
, line
, k
, "Failed to parse boolean value, ignoring: %s", rvalue
);
633 int config_parse_tristate(
635 const char *filename
,
638 unsigned section_line
,
652 /* A tristate is pretty much a boolean, except that it can
653 * also take the special value -1, indicating "uninitialized",
654 * much like NULL is for a pointer type. */
656 k
= parse_boolean(rvalue
);
658 log_syntax(unit
, LOG_ERR
, filename
, line
, k
, "Failed to parse boolean value, ignoring: %s", rvalue
);
666 int config_parse_string(
668 const char *filename
,
671 unsigned section_line
,
685 if (!utf8_is_valid(rvalue
)) {
686 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
704 int config_parse_path(
706 const char *filename
,
709 unsigned section_line
,
723 if (!utf8_is_valid(rvalue
)) {
724 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
728 if (!path_is_absolute(rvalue
)) {
729 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Not an absolute path, ignoring: %s", rvalue
);
737 path_kill_slashes(n
);
745 int config_parse_strv(const char *unit
,
746 const char *filename
,
749 unsigned section_line
,
764 if (isempty(rvalue
)) {
767 /* Empty assignment resets the list. As a special rule
768 * we actually fill in a real empty array here rather
769 * than NULL, since some code wants to know if
770 * something was set at all... */
771 empty
= new0(char*, 1);
784 r
= extract_first_word(&rvalue
, &word
, WHITESPACE
, EXTRACT_QUOTES
|EXTRACT_RETAIN_ESCAPE
);
790 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid syntax, ignoring: %s", rvalue
);
794 if (!utf8_is_valid(word
)) {
795 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
799 r
= strv_consume(sv
, word
);
807 int config_parse_log_facility(
809 const char *filename
,
812 unsigned section_line
,
827 x
= log_facility_unshifted_from_string(rvalue
);
829 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse log facility, ignoring: %s", rvalue
);
833 *o
= (x
<< 3) | LOG_PRI(*o
);
838 int config_parse_log_level(
840 const char *filename
,
843 unsigned section_line
,
858 x
= log_level_from_string(rvalue
);
860 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse log level, ignoring: %s", rvalue
);
864 *o
= (*o
& LOG_FACMASK
) | x
;
868 int config_parse_signal(
870 const char *filename
,
873 unsigned section_line
,
887 r
= signal_from_string_try_harder(rvalue
);
889 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse signal name, ignoring: %s", rvalue
);
897 int config_parse_personality(
899 const char *filename
,
902 unsigned section_line
,
909 unsigned long *personality
= data
, p
;
916 p
= personality_from_string(rvalue
);
917 if (p
== PERSONALITY_INVALID
) {
918 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse personality, ignoring: %s", rvalue
);
926 int config_parse_ifname(
928 const char *filename
,
931 unsigned section_line
,
946 if (isempty(rvalue
)) {
951 if (!ifname_valid(rvalue
)) {
952 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Interface name is not valid or too long, ignoring assignment: %s", rvalue
);
956 r
= free_and_strdup(s
, rvalue
);