]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/conf-parser.h
Merge pull request #10777 from poettering/seccomp-filter-others
[thirdparty/systemd.git] / src / shared / conf-parser.h
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 #pragma once
3
4 #include <errno.h>
5 #include <stdbool.h>
6 #include <stddef.h>
7 #include <stdio.h>
8 #include <syslog.h>
9
10 #include "alloc-util.h"
11 #include "log.h"
12 #include "macro.h"
13
14 /* An abstract parser for simple, line based, shallow configuration files consisting of variable assignments only. */
15
16 typedef enum ConfigParseFlags {
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,
21 } ConfigParseFlags;
22
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
36 /* Prototype for a parser for a specific configuration setting */
37 typedef 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)
43
44 /* Wraps information for parsing a specific configuration variable, to
45 * be stored in a simple array */
46 typedef 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
55 * be stored in a gperf perfect hashtable */
56 typedef 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 */
64 typedef const ConfigPerfItem* (*ConfigPerfItemLookup)(const char *section_and_lvalue, unsigned length);
65
66 /* Prototype for a generic high-level lookup function */
67 typedef int (*ConfigItemLookup)(
68 const void *table,
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 */
78 int config_item_table_lookup(const void *table, const char *section, const char *lvalue, ConfigParserCallback *func, int *ltype, void **data, void *userdata);
79
80 /* gperf implementation of ConfigItemLookup, based on gperf
81 * ConfigPerfItem tables */
82 int config_item_perf_lookup(const void *table, const char *section, const char *lvalue, ConfigParserCallback *func, int *ltype, void **data, void *userdata);
83
84 int 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,
91 ConfigParseFlags flags,
92 void *userdata);
93
94 int 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,
100 ConfigParseFlags flags,
101 void *userdata);
102
103 int 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,
110 ConfigParseFlags flags,
111 void *userdata);
112
113 CONFIG_PARSER_PROTOTYPE(config_parse_int);
114 CONFIG_PARSER_PROTOTYPE(config_parse_unsigned);
115 CONFIG_PARSER_PROTOTYPE(config_parse_long);
116 CONFIG_PARSER_PROTOTYPE(config_parse_uint8);
117 CONFIG_PARSER_PROTOTYPE(config_parse_uint16);
118 CONFIG_PARSER_PROTOTYPE(config_parse_uint32);
119 CONFIG_PARSER_PROTOTYPE(config_parse_uint64);
120 CONFIG_PARSER_PROTOTYPE(config_parse_double);
121 CONFIG_PARSER_PROTOTYPE(config_parse_iec_size);
122 CONFIG_PARSER_PROTOTYPE(config_parse_si_size);
123 CONFIG_PARSER_PROTOTYPE(config_parse_iec_uint64);
124 CONFIG_PARSER_PROTOTYPE(config_parse_bool);
125 CONFIG_PARSER_PROTOTYPE(config_parse_tristate);
126 CONFIG_PARSER_PROTOTYPE(config_parse_string);
127 CONFIG_PARSER_PROTOTYPE(config_parse_path);
128 CONFIG_PARSER_PROTOTYPE(config_parse_strv);
129 CONFIG_PARSER_PROTOTYPE(config_parse_sec);
130 CONFIG_PARSER_PROTOTYPE(config_parse_nsec);
131 CONFIG_PARSER_PROTOTYPE(config_parse_mode);
132 CONFIG_PARSER_PROTOTYPE(config_parse_warn_compat);
133 CONFIG_PARSER_PROTOTYPE(config_parse_log_facility);
134 CONFIG_PARSER_PROTOTYPE(config_parse_log_level);
135 CONFIG_PARSER_PROTOTYPE(config_parse_signal);
136 CONFIG_PARSER_PROTOTYPE(config_parse_personality);
137 CONFIG_PARSER_PROTOTYPE(config_parse_permille);
138 CONFIG_PARSER_PROTOTYPE(config_parse_ifname);
139 CONFIG_PARSER_PROTOTYPE(config_parse_ip_port);
140 CONFIG_PARSER_PROTOTYPE(config_parse_mtu);
141 CONFIG_PARSER_PROTOTYPE(config_parse_rlimit);
142
143 typedef enum Disabled {
144 DISABLED_CONFIGURATION,
145 DISABLED_LEGACY,
146 DISABLED_EXPERIMENTAL,
147 } Disabled;
148
149 #define DEFINE_CONFIG_PARSE(function, parser, msg) \
150 CONFIG_PARSER_PROTOTYPE(function) { \
151 int *i = data, r; \
152 \
153 assert(filename); \
154 assert(lvalue); \
155 assert(rvalue); \
156 assert(data); \
157 \
158 r = parser(rvalue); \
159 if (r < 0) { \
160 log_syntax(unit, LOG_ERR, filename, line, r, \
161 msg ", ignoring: %s", rvalue); \
162 return 0; \
163 } \
164 \
165 *i = r; \
166 return 0; \
167 }
168
169 #define DEFINE_CONFIG_PARSE_PTR(function, parser, type, msg) \
170 CONFIG_PARSER_PROTOTYPE(function) { \
171 type *i = data; \
172 int r; \
173 \
174 assert(filename); \
175 assert(lvalue); \
176 assert(rvalue); \
177 assert(data); \
178 \
179 r = parser(rvalue, i); \
180 if (r < 0) \
181 log_syntax(unit, LOG_ERR, filename, line, r, \
182 msg ", ignoring: %s", rvalue); \
183 \
184 return 0; \
185 }
186
187 #define DEFINE_CONFIG_PARSE_ENUM(function, name, type, msg) \
188 CONFIG_PARSER_PROTOTYPE(function) { \
189 type *i = data, x; \
190 \
191 assert(filename); \
192 assert(lvalue); \
193 assert(rvalue); \
194 assert(data); \
195 \
196 x = name##_from_string(rvalue); \
197 if (x < 0) { \
198 log_syntax(unit, LOG_ERR, filename, line, 0, \
199 msg ", ignoring: %s", rvalue); \
200 return 0; \
201 } \
202 \
203 *i = x; \
204 return 0; \
205 }
206
207 #define DEFINE_CONFIG_PARSE_ENUM_WITH_DEFAULT(function, name, type, default_value, msg) \
208 CONFIG_PARSER_PROTOTYPE(function) { \
209 type *i = data, x; \
210 \
211 assert(filename); \
212 assert(lvalue); \
213 assert(rvalue); \
214 assert(data); \
215 \
216 if (isempty(rvalue)) { \
217 *i = default_value; \
218 return 0; \
219 } \
220 \
221 x = name##_from_string(rvalue); \
222 if (x < 0) { \
223 log_syntax(unit, LOG_ERR, filename, line, 0, \
224 msg ", ignoring: %s", rvalue); \
225 return 0; \
226 } \
227 \
228 *i = x; \
229 return 0; \
230 }
231
232 #define DEFINE_CONFIG_PARSE_ENUMV(function, name, type, invalid, msg) \
233 CONFIG_PARSER_PROTOTYPE(function) { \
234 type **enums = data, x, *ys; \
235 _cleanup_free_ type *xs = NULL; \
236 const char *word, *state; \
237 size_t l, i = 0; \
238 \
239 assert(filename); \
240 assert(lvalue); \
241 assert(rvalue); \
242 assert(data); \
243 \
244 xs = new0(type, 1); \
245 if (!xs) \
246 return -ENOMEM; \
247 \
248 *xs = invalid; \
249 \
250 FOREACH_WORD(word, l, rvalue, state) { \
251 _cleanup_free_ char *en = NULL; \
252 type *new_xs; \
253 \
254 en = strndup(word, l); \
255 if (!en) \
256 return -ENOMEM; \
257 \
258 if ((x = name##_from_string(en)) < 0) { \
259 log_syntax(unit, LOG_ERR, filename, line, 0, \
260 msg ", ignoring: %s", en); \
261 continue; \
262 } \
263 \
264 for (ys = xs; x != invalid && *ys != invalid; ys++) { \
265 if (*ys == x) { \
266 log_syntax(unit, LOG_NOTICE, filename, \
267 line, 0, \
268 "Duplicate entry, ignoring: %s", \
269 en); \
270 x = invalid; \
271 } \
272 } \
273 \
274 if (x == invalid) \
275 continue; \
276 \
277 *(xs + i) = x; \
278 new_xs = realloc(xs, (++i + 1) * sizeof(type)); \
279 if (new_xs) \
280 xs = new_xs; \
281 else \
282 return -ENOMEM; \
283 \
284 *(xs + i) = invalid; \
285 } \
286 \
287 free_and_replace(*enums, xs); \
288 return 0; \
289 }