1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
11 #include "alloc-util.h"
15 #include "time-util.h"
17 /* An abstract parser for simple, line based, shallow configuration files consisting of variable assignments only. */
19 typedef enum ConfigParseFlags
{
20 CONFIG_PARSE_RELAXED
= 1 << 0, /* Do not warn about unknown non-extension fields */
21 CONFIG_PARSE_WARN
= 1 << 1, /* Emit non-debug messages */
24 /* Argument list for parsers of specific configuration settings. */
25 #define CONFIG_PARSER_ARGUMENTS \
27 const char *filename, \
29 const char *section, \
30 unsigned section_line, \
37 /* Prototype for a parser for a specific configuration setting */
38 typedef int (*ConfigParserCallback
)(CONFIG_PARSER_ARGUMENTS
);
40 /* A macro declaring a function prototype, following the typedef above, simply because it's so cumbersomely long
41 * otherwise. (And current emacs gets irritatingly slow when editing files that contain lots of very long function
42 * prototypes on the same screen…) */
43 #define CONFIG_PARSER_PROTOTYPE(name) int name(CONFIG_PARSER_ARGUMENTS)
45 /* Wraps information for parsing a specific configuration variable, to
46 * be stored in a simple array */
47 typedef struct ConfigTableItem
{
48 const char *section
; /* Section */
49 const char *lvalue
; /* Name of the variable */
50 ConfigParserCallback parse
; /* Function that is called to parse the variable's value */
51 int ltype
; /* Distinguish different variables passed to the same callback */
52 void *data
; /* Where to store the variable's data */
55 /* Wraps information for parsing a specific configuration variable, to
56 * be stored in a gperf perfect hashtable */
57 typedef struct ConfigPerfItem
{
58 const char *section_and_lvalue
; /* Section + "." + name of the variable */
59 ConfigParserCallback parse
; /* Function that is called to parse the variable's value */
60 int ltype
; /* Distinguish different variables passed to the same callback */
61 size_t offset
; /* Offset where to store data, from the beginning of userdata */
64 /* Prototype for a low-level gperf lookup function */
65 typedef const ConfigPerfItem
* (*ConfigPerfItemLookup
)(const char *section_and_lvalue
, unsigned length
);
67 /* Prototype for a generic high-level lookup function */
68 typedef int (*ConfigItemLookup
)(
72 ConfigParserCallback
*ret_func
,
77 /* Linear table search implementation of ConfigItemLookup, based on
78 * ConfigTableItem arrays */
79 int config_item_table_lookup(const void *table
, const char *section
, const char *lvalue
, ConfigParserCallback
*ret_func
, int *ret_ltype
, void **ret_data
, void *userdata
);
81 /* gperf implementation of ConfigItemLookup, based on gperf
82 * ConfigPerfItem tables */
83 int config_item_perf_lookup(const void *table
, const char *section
, const char *lvalue
, ConfigParserCallback
*ret_func
, int *ret_ltype
, void **ret_data
, void *userdata
);
89 const char *sections
, /* nulstr */
90 ConfigItemLookup lookup
,
92 ConfigParseFlags flags
,
94 struct stat
*ret_stat
); /* possibly NULL */
96 int config_parse_many_nulstr(
97 const char *conf_file
, /* possibly NULL */
98 const char *conf_file_dirs
, /* nulstr */
99 const char *sections
, /* nulstr */
100 ConfigItemLookup lookup
,
102 ConfigParseFlags flags
,
104 Hashmap
**ret_stats_by_path
); /* possibly NULL */
106 int config_parse_many(
107 const char* const* conf_files
, /* possibly empty */
108 const char* const* conf_file_dirs
,
109 const char *dropin_dirname
,
110 const char *sections
, /* nulstr */
111 ConfigItemLookup lookup
,
113 ConfigParseFlags flags
,
115 Hashmap
**ret_stats_by_path
, /* possibly NULL */
116 char ***ret_drop_in_files
); /* possibly NULL */
118 int config_get_stats_by_path(
122 const char* const* dirs
,
126 int hashmap_put_stats_by_path(Hashmap
**stats_by_path
, const char *path
, const struct stat
*st
);
127 bool stats_by_path_equal(Hashmap
*a
, Hashmap
*b
);
129 typedef struct ConfigSection
{
135 static inline ConfigSection
* config_section_free(ConfigSection
*cs
) {
138 DEFINE_TRIVIAL_CLEANUP_FUNC(ConfigSection
*, config_section_free
);
140 int config_section_new(const char *filename
, unsigned line
, ConfigSection
**s
);
141 extern const struct hash_ops config_section_hash_ops
;
142 unsigned hashmap_find_free_section_line(Hashmap
*hashmap
);
144 static inline bool section_is_invalid(ConfigSection
*section
) {
145 /* If this returns false, then it does _not_ mean the section is valid. */
150 return section
->invalid
;
153 #define DEFINE_SECTION_CLEANUP_FUNCTIONS(type, free_func) \
154 static inline type* free_func##_or_set_invalid(type *p) { \
158 p->section->invalid = true; \
163 DEFINE_TRIVIAL_CLEANUP_FUNC(type*, free_func); \
164 DEFINE_TRIVIAL_CLEANUP_FUNC(type*, free_func##_or_set_invalid);
166 CONFIG_PARSER_PROTOTYPE(config_parse_int
);
167 CONFIG_PARSER_PROTOTYPE(config_parse_unsigned
);
168 CONFIG_PARSER_PROTOTYPE(config_parse_long
);
169 CONFIG_PARSER_PROTOTYPE(config_parse_uint8
);
170 CONFIG_PARSER_PROTOTYPE(config_parse_uint16
);
171 CONFIG_PARSER_PROTOTYPE(config_parse_uint32
);
172 CONFIG_PARSER_PROTOTYPE(config_parse_int32
);
173 CONFIG_PARSER_PROTOTYPE(config_parse_uint64
);
174 CONFIG_PARSER_PROTOTYPE(config_parse_double
);
175 CONFIG_PARSER_PROTOTYPE(config_parse_iec_size
);
176 CONFIG_PARSER_PROTOTYPE(config_parse_si_uint64
);
177 CONFIG_PARSER_PROTOTYPE(config_parse_iec_uint64
);
178 CONFIG_PARSER_PROTOTYPE(config_parse_iec_uint64_infinity
);
179 CONFIG_PARSER_PROTOTYPE(config_parse_bool
);
180 CONFIG_PARSER_PROTOTYPE(config_parse_id128
);
181 CONFIG_PARSER_PROTOTYPE(config_parse_tristate
);
182 CONFIG_PARSER_PROTOTYPE(config_parse_string
);
183 CONFIG_PARSER_PROTOTYPE(config_parse_dns_name
);
184 CONFIG_PARSER_PROTOTYPE(config_parse_hostname
);
185 CONFIG_PARSER_PROTOTYPE(config_parse_path
);
186 CONFIG_PARSER_PROTOTYPE(config_parse_strv
);
187 CONFIG_PARSER_PROTOTYPE(config_parse_sec
);
188 CONFIG_PARSER_PROTOTYPE(config_parse_sec_def_infinity
);
189 CONFIG_PARSER_PROTOTYPE(config_parse_sec_def_unset
);
190 CONFIG_PARSER_PROTOTYPE(config_parse_nsec
);
191 CONFIG_PARSER_PROTOTYPE(config_parse_mode
);
192 CONFIG_PARSER_PROTOTYPE(config_parse_warn_compat
);
193 CONFIG_PARSER_PROTOTYPE(config_parse_log_facility
);
194 CONFIG_PARSER_PROTOTYPE(config_parse_log_level
);
195 CONFIG_PARSER_PROTOTYPE(config_parse_signal
);
196 CONFIG_PARSER_PROTOTYPE(config_parse_personality
);
197 CONFIG_PARSER_PROTOTYPE(config_parse_permille
);
198 CONFIG_PARSER_PROTOTYPE(config_parse_ifname
);
199 CONFIG_PARSER_PROTOTYPE(config_parse_ifnames
);
200 CONFIG_PARSER_PROTOTYPE(config_parse_ip_port
);
201 CONFIG_PARSER_PROTOTYPE(config_parse_mtu
);
202 CONFIG_PARSER_PROTOTYPE(config_parse_rlimit
);
203 CONFIG_PARSER_PROTOTYPE(config_parse_vlanprotocol
);
204 CONFIG_PARSER_PROTOTYPE(config_parse_hw_addr
);
205 CONFIG_PARSER_PROTOTYPE(config_parse_hw_addrs
);
206 CONFIG_PARSER_PROTOTYPE(config_parse_ether_addr
);
207 CONFIG_PARSER_PROTOTYPE(config_parse_ether_addrs
);
208 CONFIG_PARSER_PROTOTYPE(config_parse_in_addr_non_null
);
209 CONFIG_PARSER_PROTOTYPE(config_parse_percent
);
210 CONFIG_PARSER_PROTOTYPE(config_parse_permyriad
);
211 CONFIG_PARSER_PROTOTYPE(config_parse_pid
);
212 CONFIG_PARSER_PROTOTYPE(config_parse_sec_fix_0
);
214 typedef enum Disabled
{
215 DISABLED_CONFIGURATION
,
217 DISABLED_EXPERIMENTAL
,
220 typedef enum ConfigParseStringFlags
{
221 CONFIG_PARSE_STRING_SAFE
= 1 << 0,
222 CONFIG_PARSE_STRING_ASCII
= 1 << 1,
224 CONFIG_PARSE_STRING_SAFE_AND_ASCII
= CONFIG_PARSE_STRING_SAFE
| CONFIG_PARSE_STRING_ASCII
,
225 } ConfigParseStringFlags
;
227 #define DEFINE_CONFIG_PARSE(function, parser, msg) \
228 CONFIG_PARSER_PROTOTYPE(function) { \
236 r = parser(rvalue); \
238 log_syntax(unit, LOG_WARNING, filename, line, r, \
239 msg ", ignoring: %s", rvalue); \
247 #define DEFINE_CONFIG_PARSE_PTR(function, parser, type, msg) \
248 CONFIG_PARSER_PROTOTYPE(function) { \
257 r = parser(rvalue, i); \
259 log_syntax(unit, LOG_WARNING, filename, line, r, \
260 msg ", ignoring: %s", rvalue); \
265 #define DEFINE_CONFIG_PARSE_ENUM_FULL(function, from_string, type, msg) \
266 CONFIG_PARSER_PROTOTYPE(function) { \
274 x = from_string(rvalue); \
276 log_syntax(unit, LOG_WARNING, filename, line, x, \
277 msg ", ignoring: %s", rvalue); \
285 #define DEFINE_CONFIG_PARSE_ENUM(function, name, type, msg) \
286 DEFINE_CONFIG_PARSE_ENUM_FULL(function, name##_from_string, type, msg)
288 #define DEFINE_CONFIG_PARSE_ENUM_WITH_DEFAULT(function, name, type, default_value, msg) \
289 CONFIG_PARSER_PROTOTYPE(function) { \
297 if (isempty(rvalue)) { \
298 *i = default_value; \
302 x = name##_from_string(rvalue); \
304 log_syntax(unit, LOG_WARNING, filename, line, x, \
305 msg ", ignoring: %s", rvalue); \
313 #define DEFINE_CONFIG_PARSE_ENUMV(function, name, type, invalid, msg) \
314 CONFIG_PARSER_PROTOTYPE(function) { \
315 type **enums = data; \
316 _cleanup_free_ type *xs = NULL; \
325 xs = new0(type, 1); \
331 for (const char *p = rvalue;;) { \
332 _cleanup_free_ char *en = NULL; \
335 r = extract_first_word(&p, &en, NULL, 0); \
339 log_syntax(unit, LOG_WARNING, filename, line, r, \
340 msg ", ignoring: %s", en); \
346 x = name##_from_string(en); \
348 log_syntax(unit, LOG_WARNING, filename, line, x, \
349 msg ", ignoring: %s", en); \
353 for (type *ys = xs; x != invalid && *ys != invalid; ys++) \
355 log_syntax(unit, LOG_NOTICE, filename, line, 0, \
356 "Duplicate entry, ignoring: %s", \
365 new_xs = realloc(xs, (++i + 1) * sizeof(type)); \
371 *(xs + i) = invalid; \
374 return free_and_replace(*enums, xs); \