]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/conf-parser.h
time-util: Introduce parse_sec_def_infinity
[thirdparty/systemd.git] / src / shared / conf-parser.h
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
c2f1db8f 2#pragma once
ed5bcfbe 3
a8fbdf54 4#include <errno.h>
10e87ee7 5#include <stdbool.h>
a8fbdf54 6#include <stddef.h>
71d35b6b 7#include <stdio.h>
a8fbdf54 8#include <syslog.h>
ed5bcfbe 9
a8fbdf54
TA
10#include "alloc-util.h"
11#include "log.h"
e8e581bf
ZJS
12#include "macro.h"
13
bcde742e
LP
14/* An abstract parser for simple, line based, shallow configuration files consisting of variable assignments only. */
15
16typedef enum ConfigParseFlags {
ef31828d
LP
17 CONFIG_PARSE_RELAXED = 1 << 0,
18 CONFIG_PARSE_ALLOW_INCLUDE = 1 << 1,
19 CONFIG_PARSE_WARN = 1 << 2,
20 CONFIG_PARSE_REFUSE_BOM = 1 << 3,
bcde742e 21} ConfigParseFlags;
ed5bcfbe 22
1f12b48a
LP
23/* Argument list for parsers of specific configuration settings. */
24#define CONFIG_PARSER_ARGUMENTS \
25 const char *unit, \
26 const char *filename, \
27 unsigned line, \
28 const char *section, \
29 unsigned section_line, \
30 const char *lvalue, \
31 int ltype, \
32 const char *rvalue, \
33 void *data, \
34 void *userdata
35
f975e971 36/* Prototype for a parser for a specific configuration setting */
1f12b48a
LP
37typedef int (*ConfigParserCallback)(CONFIG_PARSER_ARGUMENTS);
38
39/* A macro declaring the a function prototype, following the typedef above, simply because it's so cumbersomely long
40 * otherwise. (And current emacs gets irritatingly slow when editing files that contain lots of very long function
41 * prototypes on the same screen…) */
42#define CONFIG_PARSER_PROTOTYPE(name) int name(CONFIG_PARSER_ARGUMENTS)
f975e971
LP
43
44/* Wraps information for parsing a specific configuration variable, to
45 * be stored in a simple array */
46typedef struct ConfigTableItem {
47 const char *section; /* Section */
48 const char *lvalue; /* Name of the variable */
49 ConfigParserCallback parse; /* Function that is called to parse the variable's value */
50 int ltype; /* Distinguish different variables passed to the same callback */
51 void *data; /* Where to store the variable's data */
52} ConfigTableItem;
53
54/* Wraps information for parsing a specific configuration variable, to
e5a7f173 55 * be stored in a gperf perfect hashtable */
f975e971
LP
56typedef struct ConfigPerfItem {
57 const char *section_and_lvalue; /* Section + "." + name of the variable */
58 ConfigParserCallback parse; /* Function that is called to parse the variable's value */
59 int ltype; /* Distinguish different variables passed to the same callback */
60 size_t offset; /* Offset where to store data, from the beginning of userdata */
61} ConfigPerfItem;
62
63/* Prototype for a low-level gperf lookup function */
64typedef const ConfigPerfItem* (*ConfigPerfItemLookup)(const char *section_and_lvalue, unsigned length);
65
66/* Prototype for a generic high-level lookup function */
67typedef int (*ConfigItemLookup)(
e9f3d2d5 68 const void *table,
f975e971
LP
69 const char *section,
70 const char *lvalue,
71 ConfigParserCallback *func,
72 int *ltype,
73 void **data,
74 void *userdata);
75
76/* Linear table search implementation of ConfigItemLookup, based on
77 * ConfigTableItem arrays */
e9f3d2d5 78int config_item_table_lookup(const void *table, const char *section, const char *lvalue, ConfigParserCallback *func, int *ltype, void **data, void *userdata);
f975e971
LP
79
80/* gperf implementation of ConfigItemLookup, based on gperf
81 * ConfigPerfItem tables */
e9f3d2d5 82int config_item_perf_lookup(const void *table, const char *section, const char *lvalue, ConfigParserCallback *func, int *ltype, void **data, void *userdata);
f975e971 83
43688c49
ZJS
84int config_parse(
85 const char *unit,
86 const char *filename,
87 FILE *f,
88 const char *sections, /* nulstr */
89 ConfigItemLookup lookup,
90 const void *table,
bcde742e 91 ConfigParseFlags flags,
43688c49
ZJS
92 void *userdata);
93
94int config_parse_many_nulstr(
95 const char *conf_file, /* possibly NULL */
96 const char *conf_file_dirs, /* nulstr */
97 const char *sections, /* nulstr */
98 ConfigItemLookup lookup,
99 const void *table,
bcde742e 100 ConfigParseFlags flags,
43688c49 101 void *userdata);
e8461023 102
23bb31aa
ZJS
103int config_parse_many(
104 const char *conf_file, /* possibly NULL */
105 const char* const* conf_file_dirs,
106 const char *dropin_dirname,
107 const char *sections, /* nulstr */
108 ConfigItemLookup lookup,
109 const void *table,
bcde742e 110 ConfigParseFlags flags,
23bb31aa
ZJS
111 void *userdata);
112
1f12b48a
LP
113CONFIG_PARSER_PROTOTYPE(config_parse_int);
114CONFIG_PARSER_PROTOTYPE(config_parse_unsigned);
115CONFIG_PARSER_PROTOTYPE(config_parse_long);
116CONFIG_PARSER_PROTOTYPE(config_parse_uint8);
117CONFIG_PARSER_PROTOTYPE(config_parse_uint16);
118CONFIG_PARSER_PROTOTYPE(config_parse_uint32);
119CONFIG_PARSER_PROTOTYPE(config_parse_uint64);
120CONFIG_PARSER_PROTOTYPE(config_parse_double);
121CONFIG_PARSER_PROTOTYPE(config_parse_iec_size);
122CONFIG_PARSER_PROTOTYPE(config_parse_si_size);
123CONFIG_PARSER_PROTOTYPE(config_parse_iec_uint64);
124CONFIG_PARSER_PROTOTYPE(config_parse_bool);
125CONFIG_PARSER_PROTOTYPE(config_parse_tristate);
126CONFIG_PARSER_PROTOTYPE(config_parse_string);
127CONFIG_PARSER_PROTOTYPE(config_parse_path);
128CONFIG_PARSER_PROTOTYPE(config_parse_strv);
129CONFIG_PARSER_PROTOTYPE(config_parse_sec);
7b61ce3c 130CONFIG_PARSER_PROTOTYPE(config_parse_sec_def_infinity);
1f12b48a
LP
131CONFIG_PARSER_PROTOTYPE(config_parse_nsec);
132CONFIG_PARSER_PROTOTYPE(config_parse_mode);
133CONFIG_PARSER_PROTOTYPE(config_parse_warn_compat);
134CONFIG_PARSER_PROTOTYPE(config_parse_log_facility);
135CONFIG_PARSER_PROTOTYPE(config_parse_log_level);
136CONFIG_PARSER_PROTOTYPE(config_parse_signal);
137CONFIG_PARSER_PROTOTYPE(config_parse_personality);
c07b23ca 138CONFIG_PARSER_PROTOTYPE(config_parse_permille);
1f12b48a
LP
139CONFIG_PARSER_PROTOTYPE(config_parse_ifname);
140CONFIG_PARSER_PROTOTYPE(config_parse_ip_port);
1f12b48a
LP
141CONFIG_PARSER_PROTOTYPE(config_parse_mtu);
142CONFIG_PARSER_PROTOTYPE(config_parse_rlimit);
e8e581bf 143
1e35c5ab
RP
144typedef enum Disabled {
145 DISABLED_CONFIGURATION,
146 DISABLED_LEGACY,
147 DISABLED_EXPERIMENTAL,
148} Disabled;
149
2d1729ca
YW
150#define DEFINE_CONFIG_PARSE(function, parser, msg) \
151 CONFIG_PARSER_PROTOTYPE(function) { \
152 int *i = data, r; \
153 \
154 assert(filename); \
155 assert(lvalue); \
156 assert(rvalue); \
157 assert(data); \
158 \
159 r = parser(rvalue); \
160 if (r < 0) { \
161 log_syntax(unit, LOG_ERR, filename, line, r, \
162 msg ", ignoring: %s", rvalue); \
163 return 0; \
164 } \
165 \
166 *i = r; \
167 return 0; \
168 }
169
170#define DEFINE_CONFIG_PARSE_PTR(function, parser, type, msg) \
171 CONFIG_PARSER_PROTOTYPE(function) { \
172 type *i = data; \
173 int r; \
174 \
175 assert(filename); \
176 assert(lvalue); \
177 assert(rvalue); \
178 assert(data); \
179 \
180 r = parser(rvalue, i); \
181 if (r < 0) \
182 log_syntax(unit, LOG_ERR, filename, line, r, \
183 msg ", ignoring: %s", rvalue); \
184 \
185 return 0; \
186 }
187
188#define DEFINE_CONFIG_PARSE_ENUM(function, name, type, msg) \
189 CONFIG_PARSER_PROTOTYPE(function) { \
190 type *i = data, x; \
191 \
192 assert(filename); \
193 assert(lvalue); \
194 assert(rvalue); \
195 assert(data); \
196 \
197 x = name##_from_string(rvalue); \
198 if (x < 0) { \
199 log_syntax(unit, LOG_ERR, filename, line, 0, \
200 msg ", ignoring: %s", rvalue); \
201 return 0; \
202 } \
203 \
204 *i = x; \
205 return 0; \
206 }
207
208#define DEFINE_CONFIG_PARSE_ENUM_WITH_DEFAULT(function, name, type, default_value, msg) \
1f12b48a 209 CONFIG_PARSER_PROTOTYPE(function) { \
487393e9
LP
210 type *i = data, x; \
211 \
212 assert(filename); \
213 assert(lvalue); \
214 assert(rvalue); \
215 assert(data); \
216 \
2d1729ca
YW
217 if (isempty(rvalue)) { \
218 *i = default_value; \
219 return 0; \
220 } \
221 \
222 x = name##_from_string(rvalue); \
223 if (x < 0) { \
224 log_syntax(unit, LOG_ERR, filename, line, 0, \
e8e581bf 225 msg ", ignoring: %s", rvalue); \
c0b34696 226 return 0; \
487393e9
LP
227 } \
228 \
229 *i = x; \
487393e9
LP
230 return 0; \
231 }
916484f5 232
2d1729ca 233#define DEFINE_CONFIG_PARSE_ENUMV(function, name, type, invalid, msg) \
1f12b48a 234 CONFIG_PARSER_PROTOTYPE(function) { \
77c10205
TG
235 type **enums = data, x, *ys; \
236 _cleanup_free_ type *xs = NULL; \
a2a5291b 237 const char *word, *state; \
916484f5
TG
238 size_t l, i = 0; \
239 \
240 assert(filename); \
241 assert(lvalue); \
242 assert(rvalue); \
243 assert(data); \
244 \
245 xs = new0(type, 1); \
9ed794a3 246 if (!xs) \
83e341a6
TG
247 return -ENOMEM; \
248 \
916484f5
TG
249 *xs = invalid; \
250 \
a2a5291b 251 FOREACH_WORD(word, l, rvalue, state) { \
916484f5 252 _cleanup_free_ char *en = NULL; \
77c10205 253 type *new_xs; \
916484f5 254 \
a2a5291b 255 en = strndup(word, l); \
916484f5
TG
256 if (!en) \
257 return -ENOMEM; \
258 \
259 if ((x = name##_from_string(en)) < 0) { \
2d1729ca
YW
260 log_syntax(unit, LOG_ERR, filename, line, 0, \
261 msg ", ignoring: %s", en); \
916484f5
TG
262 continue; \
263 } \
264 \
265 for (ys = xs; x != invalid && *ys != invalid; ys++) { \
266 if (*ys == x) { \
2d1729ca
YW
267 log_syntax(unit, LOG_NOTICE, filename, \
268 line, 0, \
269 "Duplicate entry, ignoring: %s", \
270 en); \
916484f5
TG
271 x = invalid; \
272 } \
273 } \
274 \
275 if (x == invalid) \
276 continue; \
277 \
278 *(xs + i) = x; \
77c10205
TG
279 new_xs = realloc(xs, (++i + 1) * sizeof(type)); \
280 if (new_xs) \
281 xs = new_xs; \
282 else \
916484f5 283 return -ENOMEM; \
83e341a6 284 \
916484f5
TG
285 *(xs + i) = invalid; \
286 } \
287 \
5f92e517 288 free_and_replace(*enums, xs); \
916484f5
TG
289 return 0; \
290 }