]>
Commit | Line | Data |
---|---|---|
db9ecf05 | 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
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> |
8524db50 | 9 | #include <sys/stat.h> |
ed5bcfbe | 10 | |
a8fbdf54 | 11 | #include "alloc-util.h" |
8524db50 | 12 | #include "hashmap.h" |
a8fbdf54 | 13 | #include "log.h" |
e8e581bf | 14 | #include "macro.h" |
4f9ff96a | 15 | #include "time-util.h" |
e8e581bf | 16 | |
bcde742e LP |
17 | /* An abstract parser for simple, line based, shallow configuration files consisting of variable assignments only. */ |
18 | ||
19 | typedef enum ConfigParseFlags { | |
94a404cb | 20 | CONFIG_PARSE_RELAXED = 1 << 0, /* Do not warn about unknown non-extension fields */ |
7ade8982 | 21 | CONFIG_PARSE_WARN = 1 << 1, /* Emit non-debug messages */ |
bcde742e | 22 | } ConfigParseFlags; |
ed5bcfbe | 23 | |
1f12b48a LP |
24 | /* Argument list for parsers of specific configuration settings. */ |
25 | #define CONFIG_PARSER_ARGUMENTS \ | |
26 | const char *unit, \ | |
27 | const char *filename, \ | |
28 | unsigned line, \ | |
29 | const char *section, \ | |
30 | unsigned section_line, \ | |
31 | const char *lvalue, \ | |
32 | int ltype, \ | |
33 | const char *rvalue, \ | |
34 | void *data, \ | |
35 | void *userdata | |
36 | ||
f975e971 | 37 | /* Prototype for a parser for a specific configuration setting */ |
1f12b48a LP |
38 | typedef int (*ConfigParserCallback)(CONFIG_PARSER_ARGUMENTS); |
39 | ||
d51c4fca | 40 | /* A macro declaring a function prototype, following the typedef above, simply because it's so cumbersomely long |
1f12b48a LP |
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) | |
f975e971 LP |
44 | |
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 */ | |
53 | } ConfigTableItem; | |
54 | ||
55 | /* Wraps information for parsing a specific configuration variable, to | |
e5a7f173 | 56 | * be stored in a gperf perfect hashtable */ |
f975e971 LP |
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 */ | |
62 | } ConfigPerfItem; | |
63 | ||
64 | /* Prototype for a low-level gperf lookup function */ | |
5996cc34 | 65 | typedef const ConfigPerfItem* (*ConfigPerfItemLookup)(const char *section_and_lvalue, GPERF_LEN_TYPE length); |
f975e971 LP |
66 | |
67 | /* Prototype for a generic high-level lookup function */ | |
68 | typedef int (*ConfigItemLookup)( | |
e9f3d2d5 | 69 | const void *table, |
f975e971 LP |
70 | const char *section, |
71 | const char *lvalue, | |
0b954099 LP |
72 | ConfigParserCallback *ret_func, |
73 | int *ret_ltype, | |
74 | void **ret_data, | |
f975e971 LP |
75 | void *userdata); |
76 | ||
77 | /* Linear table search implementation of ConfigItemLookup, based on | |
78 | * ConfigTableItem arrays */ | |
0b954099 | 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); |
f975e971 LP |
80 | |
81 | /* gperf implementation of ConfigItemLookup, based on gperf | |
82 | * ConfigPerfItem tables */ | |
0b954099 | 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); |
f975e971 | 84 | |
43688c49 ZJS |
85 | int config_parse( |
86 | const char *unit, | |
87 | const char *filename, | |
88 | FILE *f, | |
4f9ff96a | 89 | const char *sections, /* nulstr */ |
43688c49 ZJS |
90 | ConfigItemLookup lookup, |
91 | const void *table, | |
bcde742e | 92 | ConfigParseFlags flags, |
4f9ff96a | 93 | void *userdata, |
8524db50 | 94 | struct stat *ret_stat); /* possibly NULL */ |
43688c49 | 95 | |
5656cdfe | 96 | int config_parse_config_file_full( |
07e0ffc8 | 97 | const char *conf_file, |
5656cdfe | 98 | const char *pkgdir, |
43688c49 ZJS |
99 | const char *sections, /* nulstr */ |
100 | ConfigItemLookup lookup, | |
101 | const void *table, | |
bcde742e | 102 | ConfigParseFlags flags, |
07e0ffc8 | 103 | void *userdata); |
e8461023 | 104 | |
5656cdfe DT |
105 | static inline int config_parse_config_file( |
106 | const char *conf_file, | |
107 | const char *sections, /* nulstr */ | |
108 | ConfigItemLookup lookup, | |
109 | const void *table, | |
110 | ConfigParseFlags flags, | |
111 | void *userdata) { | |
112 | return config_parse_config_file_full(conf_file, "systemd", sections, lookup, table, flags, userdata); | |
113 | } | |
114 | ||
23bb31aa | 115 | int config_parse_many( |
8b8024f1 | 116 | const char* const* conf_files, /* possibly empty */ |
23bb31aa ZJS |
117 | const char* const* conf_file_dirs, |
118 | const char *dropin_dirname, | |
947f59ba | 119 | const char *root, |
23bb31aa ZJS |
120 | const char *sections, /* nulstr */ |
121 | ConfigItemLookup lookup, | |
122 | const void *table, | |
bcde742e | 123 | ConfigParseFlags flags, |
9f83091e | 124 | void *userdata, |
ead3a3fc RP |
125 | Hashmap **ret_stats_by_path, /* possibly NULL */ |
126 | char ***ret_drop_in_files); /* possibly NULL */ | |
23bb31aa | 127 | |
bdb2d3c6 YW |
128 | int config_get_stats_by_path( |
129 | const char *suffix, | |
130 | const char *root, | |
131 | unsigned flags, | |
132 | const char* const* dirs, | |
3f4dfd9d | 133 | bool check_dropins, |
bdb2d3c6 YW |
134 | Hashmap **ret); |
135 | ||
acfbd71c | 136 | int hashmap_put_stats_by_path(Hashmap **stats_by_path, const char *path, const struct stat *st); |
bdb2d3c6 YW |
137 | bool stats_by_path_equal(Hashmap *a, Hashmap *b); |
138 | ||
307fe3cd YW |
139 | typedef struct ConfigSection { |
140 | unsigned line; | |
141 | bool invalid; | |
142 | char filename[]; | |
143 | } ConfigSection; | |
144 | ||
145 | static inline ConfigSection* config_section_free(ConfigSection *cs) { | |
146 | return mfree(cs); | |
147 | } | |
148 | DEFINE_TRIVIAL_CLEANUP_FUNC(ConfigSection*, config_section_free); | |
149 | ||
08ca764d | 150 | int config_section_new(const char *filename, unsigned line, ConfigSection **ret); |
b46d1694 YW |
151 | |
152 | void config_section_hash_func(const ConfigSection *c, struct siphash *state); | |
153 | int config_section_compare_func(const ConfigSection *x, const ConfigSection *y); | |
307fe3cd | 154 | extern const struct hash_ops config_section_hash_ops; |
b46d1694 | 155 | |
e63c6e9f YW |
156 | int _hashmap_by_section_find_unused_line( |
157 | HashmapBase *entries_by_section, | |
d9171a23 YW |
158 | const char *filename, |
159 | unsigned *ret); | |
e63c6e9f YW |
160 | static inline int hashmap_by_section_find_unused_line( |
161 | Hashmap *entries_by_section, | |
162 | const char *filename, | |
163 | unsigned *ret) { | |
164 | return _hashmap_by_section_find_unused_line(HASHMAP_BASE(entries_by_section), filename, ret); | |
165 | } | |
166 | static inline int ordered_hashmap_by_section_find_unused_line( | |
167 | OrderedHashmap *entries_by_section, | |
168 | const char *filename, | |
169 | unsigned *ret) { | |
170 | return _hashmap_by_section_find_unused_line(HASHMAP_BASE(entries_by_section), filename, ret); | |
171 | } | |
307fe3cd YW |
172 | |
173 | static inline bool section_is_invalid(ConfigSection *section) { | |
174 | /* If this returns false, then it does _not_ mean the section is valid. */ | |
175 | ||
176 | if (!section) | |
177 | return false; | |
178 | ||
179 | return section->invalid; | |
180 | } | |
181 | ||
182 | #define DEFINE_SECTION_CLEANUP_FUNCTIONS(type, free_func) \ | |
183 | static inline type* free_func##_or_set_invalid(type *p) { \ | |
184 | assert(p); \ | |
185 | \ | |
186 | if (p->section) \ | |
187 | p->section->invalid = true; \ | |
188 | else \ | |
189 | free_func(p); \ | |
190 | return NULL; \ | |
191 | } \ | |
192 | DEFINE_TRIVIAL_CLEANUP_FUNC(type*, free_func); \ | |
193 | DEFINE_TRIVIAL_CLEANUP_FUNC(type*, free_func##_or_set_invalid); | |
194 | ||
1f12b48a LP |
195 | CONFIG_PARSER_PROTOTYPE(config_parse_int); |
196 | CONFIG_PARSER_PROTOTYPE(config_parse_unsigned); | |
197 | CONFIG_PARSER_PROTOTYPE(config_parse_long); | |
198 | CONFIG_PARSER_PROTOTYPE(config_parse_uint8); | |
199 | CONFIG_PARSER_PROTOTYPE(config_parse_uint16); | |
200 | CONFIG_PARSER_PROTOTYPE(config_parse_uint32); | |
b57ebc60 | 201 | CONFIG_PARSER_PROTOTYPE(config_parse_int32); |
1f12b48a LP |
202 | CONFIG_PARSER_PROTOTYPE(config_parse_uint64); |
203 | CONFIG_PARSER_PROTOTYPE(config_parse_double); | |
204 | CONFIG_PARSER_PROTOTYPE(config_parse_iec_size); | |
50299121 | 205 | CONFIG_PARSER_PROTOTYPE(config_parse_si_uint64); |
1f12b48a | 206 | CONFIG_PARSER_PROTOTYPE(config_parse_iec_uint64); |
6e8791a0 | 207 | CONFIG_PARSER_PROTOTYPE(config_parse_iec_uint64_infinity); |
1f12b48a | 208 | CONFIG_PARSER_PROTOTYPE(config_parse_bool); |
12963533 | 209 | CONFIG_PARSER_PROTOTYPE(config_parse_id128); |
1f12b48a LP |
210 | CONFIG_PARSER_PROTOTYPE(config_parse_tristate); |
211 | CONFIG_PARSER_PROTOTYPE(config_parse_string); | |
fa787a13 YW |
212 | CONFIG_PARSER_PROTOTYPE(config_parse_dns_name); |
213 | CONFIG_PARSER_PROTOTYPE(config_parse_hostname); | |
1f12b48a LP |
214 | CONFIG_PARSER_PROTOTYPE(config_parse_path); |
215 | CONFIG_PARSER_PROTOTYPE(config_parse_strv); | |
216 | CONFIG_PARSER_PROTOTYPE(config_parse_sec); | |
7b61ce3c | 217 | CONFIG_PARSER_PROTOTYPE(config_parse_sec_def_infinity); |
dc653bf4 | 218 | CONFIG_PARSER_PROTOTYPE(config_parse_sec_def_unset); |
1f12b48a LP |
219 | CONFIG_PARSER_PROTOTYPE(config_parse_nsec); |
220 | CONFIG_PARSER_PROTOTYPE(config_parse_mode); | |
221 | CONFIG_PARSER_PROTOTYPE(config_parse_warn_compat); | |
222 | CONFIG_PARSER_PROTOTYPE(config_parse_log_facility); | |
223 | CONFIG_PARSER_PROTOTYPE(config_parse_log_level); | |
224 | CONFIG_PARSER_PROTOTYPE(config_parse_signal); | |
225 | CONFIG_PARSER_PROTOTYPE(config_parse_personality); | |
c07b23ca | 226 | CONFIG_PARSER_PROTOTYPE(config_parse_permille); |
1f12b48a | 227 | CONFIG_PARSER_PROTOTYPE(config_parse_ifname); |
a5053a15 | 228 | CONFIG_PARSER_PROTOTYPE(config_parse_ifnames); |
1f12b48a | 229 | CONFIG_PARSER_PROTOTYPE(config_parse_ip_port); |
1f12b48a LP |
230 | CONFIG_PARSER_PROTOTYPE(config_parse_mtu); |
231 | CONFIG_PARSER_PROTOTYPE(config_parse_rlimit); | |
4df4df5b | 232 | CONFIG_PARSER_PROTOTYPE(config_parse_vlanprotocol); |
99628f36 YW |
233 | CONFIG_PARSER_PROTOTYPE(config_parse_hw_addr); |
234 | CONFIG_PARSER_PROTOTYPE(config_parse_hw_addrs); | |
aa4f7653 YW |
235 | CONFIG_PARSER_PROTOTYPE(config_parse_ether_addr); |
236 | CONFIG_PARSER_PROTOTYPE(config_parse_ether_addrs); | |
cf074772 | 237 | CONFIG_PARSER_PROTOTYPE(config_parse_in_addr_non_null); |
9de5e321 | 238 | CONFIG_PARSER_PROTOTYPE(config_parse_percent); |
0a9f9344 | 239 | CONFIG_PARSER_PROTOTYPE(config_parse_permyriad); |
65a0ede2 | 240 | CONFIG_PARSER_PROTOTYPE(config_parse_pid); |
4ee8176f | 241 | CONFIG_PARSER_PROTOTYPE(config_parse_sec_fix_0); |
e8e581bf | 242 | |
1e35c5ab RP |
243 | typedef enum Disabled { |
244 | DISABLED_CONFIGURATION, | |
245 | DISABLED_LEGACY, | |
246 | DISABLED_EXPERIMENTAL, | |
247 | } Disabled; | |
248 | ||
3f87eaa5 YW |
249 | typedef enum ConfigParseStringFlags { |
250 | CONFIG_PARSE_STRING_SAFE = 1 << 0, | |
e289ce7f YW |
251 | CONFIG_PARSE_STRING_ASCII = 1 << 1, |
252 | ||
253 | CONFIG_PARSE_STRING_SAFE_AND_ASCII = CONFIG_PARSE_STRING_SAFE | CONFIG_PARSE_STRING_ASCII, | |
3f87eaa5 YW |
254 | } ConfigParseStringFlags; |
255 | ||
2d1729ca YW |
256 | #define DEFINE_CONFIG_PARSE(function, parser, msg) \ |
257 | CONFIG_PARSER_PROTOTYPE(function) { \ | |
258 | int *i = data, r; \ | |
259 | \ | |
260 | assert(filename); \ | |
261 | assert(lvalue); \ | |
262 | assert(rvalue); \ | |
263 | assert(data); \ | |
264 | \ | |
265 | r = parser(rvalue); \ | |
266 | if (r < 0) { \ | |
d96edb2c | 267 | log_syntax(unit, LOG_WARNING, filename, line, r, \ |
2d1729ca YW |
268 | msg ", ignoring: %s", rvalue); \ |
269 | return 0; \ | |
270 | } \ | |
271 | \ | |
272 | *i = r; \ | |
273 | return 0; \ | |
274 | } | |
275 | ||
276 | #define DEFINE_CONFIG_PARSE_PTR(function, parser, type, msg) \ | |
277 | CONFIG_PARSER_PROTOTYPE(function) { \ | |
99534007 | 278 | type *i = ASSERT_PTR(data); \ |
2d1729ca YW |
279 | int r; \ |
280 | \ | |
281 | assert(filename); \ | |
282 | assert(lvalue); \ | |
283 | assert(rvalue); \ | |
2d1729ca YW |
284 | \ |
285 | r = parser(rvalue, i); \ | |
286 | if (r < 0) \ | |
d96edb2c | 287 | log_syntax(unit, LOG_WARNING, filename, line, r, \ |
2d1729ca YW |
288 | msg ", ignoring: %s", rvalue); \ |
289 | \ | |
290 | return 0; \ | |
291 | } | |
292 | ||
a2b06dbe | 293 | #define DEFINE_CONFIG_PARSE_ENUM_FULL(function, from_string, type, msg) \ |
2d1729ca YW |
294 | CONFIG_PARSER_PROTOTYPE(function) { \ |
295 | type *i = data, x; \ | |
296 | \ | |
297 | assert(filename); \ | |
298 | assert(lvalue); \ | |
299 | assert(rvalue); \ | |
300 | assert(data); \ | |
301 | \ | |
a2b06dbe | 302 | x = from_string(rvalue); \ |
2d1729ca | 303 | if (x < 0) { \ |
0cbb768a | 304 | log_syntax(unit, LOG_WARNING, filename, line, x, \ |
2d1729ca YW |
305 | msg ", ignoring: %s", rvalue); \ |
306 | return 0; \ | |
307 | } \ | |
308 | \ | |
309 | *i = x; \ | |
310 | return 0; \ | |
311 | } | |
312 | ||
a2b06dbe LP |
313 | #define DEFINE_CONFIG_PARSE_ENUM(function, name, type, msg) \ |
314 | DEFINE_CONFIG_PARSE_ENUM_FULL(function, name##_from_string, type, msg) | |
315 | ||
2d1729ca | 316 | #define DEFINE_CONFIG_PARSE_ENUM_WITH_DEFAULT(function, name, type, default_value, msg) \ |
1f12b48a | 317 | CONFIG_PARSER_PROTOTYPE(function) { \ |
487393e9 LP |
318 | type *i = data, x; \ |
319 | \ | |
320 | assert(filename); \ | |
321 | assert(lvalue); \ | |
322 | assert(rvalue); \ | |
323 | assert(data); \ | |
324 | \ | |
2d1729ca YW |
325 | if (isempty(rvalue)) { \ |
326 | *i = default_value; \ | |
327 | return 0; \ | |
328 | } \ | |
329 | \ | |
330 | x = name##_from_string(rvalue); \ | |
331 | if (x < 0) { \ | |
0cbb768a | 332 | log_syntax(unit, LOG_WARNING, filename, line, x, \ |
e8e581bf | 333 | msg ", ignoring: %s", rvalue); \ |
c0b34696 | 334 | return 0; \ |
487393e9 LP |
335 | } \ |
336 | \ | |
337 | *i = x; \ | |
487393e9 LP |
338 | return 0; \ |
339 | } | |
916484f5 | 340 | |
2d1729ca | 341 | #define DEFINE_CONFIG_PARSE_ENUMV(function, name, type, invalid, msg) \ |
1f12b48a | 342 | CONFIG_PARSER_PROTOTYPE(function) { \ |
99534007 | 343 | type **enums = ASSERT_PTR(data); \ |
77c10205 | 344 | _cleanup_free_ type *xs = NULL; \ |
ecaf258e ZJS |
345 | size_t i = 0; \ |
346 | int r; \ | |
916484f5 TG |
347 | \ |
348 | assert(filename); \ | |
349 | assert(lvalue); \ | |
350 | assert(rvalue); \ | |
916484f5 TG |
351 | \ |
352 | xs = new0(type, 1); \ | |
9ed794a3 | 353 | if (!xs) \ |
83e341a6 TG |
354 | return -ENOMEM; \ |
355 | \ | |
916484f5 TG |
356 | *xs = invalid; \ |
357 | \ | |
ecaf258e | 358 | for (const char *p = rvalue;;) { \ |
916484f5 | 359 | _cleanup_free_ char *en = NULL; \ |
ecaf258e | 360 | type x, *new_xs; \ |
916484f5 | 361 | \ |
ecaf258e ZJS |
362 | r = extract_first_word(&p, &en, NULL, 0); \ |
363 | if (r == -ENOMEM) \ | |
d96edb2c | 364 | return log_oom(); \ |
0cbb768a YW |
365 | if (r < 0) { \ |
366 | log_syntax(unit, LOG_WARNING, filename, line, r, \ | |
367 | msg ", ignoring: %s", en); \ | |
368 | return 0; \ | |
369 | } \ | |
ecaf258e ZJS |
370 | if (r == 0) \ |
371 | break; \ | |
916484f5 | 372 | \ |
0cbb768a YW |
373 | x = name##_from_string(en); \ |
374 | if (x < 0) { \ | |
375 | log_syntax(unit, LOG_WARNING, filename, line, x, \ | |
2d1729ca | 376 | msg ", ignoring: %s", en); \ |
916484f5 TG |
377 | continue; \ |
378 | } \ | |
379 | \ | |
ecaf258e ZJS |
380 | for (type *ys = xs; x != invalid && *ys != invalid; ys++) \ |
381 | if (*ys == x) { \ | |
382 | log_syntax(unit, LOG_NOTICE, filename, line, 0, \ | |
383 | "Duplicate entry, ignoring: %s", \ | |
2d1729ca | 384 | en); \ |
916484f5 TG |
385 | x = invalid; \ |
386 | } \ | |
916484f5 TG |
387 | \ |
388 | if (x == invalid) \ | |
389 | continue; \ | |
390 | \ | |
391 | *(xs + i) = x; \ | |
77c10205 TG |
392 | new_xs = realloc(xs, (++i + 1) * sizeof(type)); \ |
393 | if (new_xs) \ | |
394 | xs = new_xs; \ | |
395 | else \ | |
d96edb2c | 396 | return log_oom(); \ |
83e341a6 | 397 | \ |
916484f5 TG |
398 | *(xs + i) = invalid; \ |
399 | } \ | |
400 | \ | |
ecaf258e | 401 | return free_and_replace(*enums, xs); \ |
916484f5 | 402 | } |
851cdffd ZJS |
403 | |
404 | int config_parse_unsigned_bounded( | |
405 | const char *unit, | |
406 | const char *filename, | |
407 | unsigned line, | |
408 | const char *section, | |
409 | unsigned section_line, | |
410 | const char *name, | |
411 | const char *value, | |
412 | unsigned min, | |
413 | unsigned max, | |
414 | bool ignoring, | |
415 | unsigned *ret); | |
416 | ||
417 | static inline int config_parse_uint32_bounded( | |
418 | const char *unit, | |
419 | const char *filename, | |
420 | unsigned line, | |
421 | const char *section, | |
422 | unsigned section_line, | |
423 | const char *name, | |
424 | const char *value, | |
425 | uint32_t min, | |
426 | uint32_t max, | |
427 | bool ignoring, | |
428 | uint32_t *ret) { | |
429 | ||
430 | unsigned t; | |
431 | int r; | |
432 | ||
433 | r = config_parse_unsigned_bounded( | |
434 | unit, filename, line, section, section_line, name, value, | |
435 | min, max, ignoring, | |
436 | &t); | |
437 | if (r <= 0) | |
438 | return r; | |
439 | assert(t <= UINT32_MAX); | |
440 | *ret = t; | |
441 | return 1; | |
442 | } | |
443 | ||
444 | static inline int config_parse_uint16_bounded( | |
445 | const char *unit, | |
446 | const char *filename, | |
447 | unsigned line, | |
448 | const char *section, | |
449 | unsigned section_line, | |
450 | const char *name, | |
451 | const char *value, | |
452 | uint16_t min, | |
453 | uint16_t max, | |
454 | bool ignoring, | |
455 | uint16_t *ret) { | |
456 | ||
457 | unsigned t; | |
458 | int r; | |
459 | ||
460 | r = config_parse_unsigned_bounded( | |
461 | unit, filename, line, section, section_line, name, value, | |
462 | min, max, ignoring, | |
463 | &t); | |
464 | if (r <= 0) | |
465 | return r; | |
466 | assert(t <= UINT16_MAX); | |
467 | *ret = t; | |
468 | return 1; | |
469 | } | |
470 | ||
471 | static inline int config_parse_uint8_bounded( | |
472 | const char *unit, | |
473 | const char *filename, | |
474 | unsigned line, | |
475 | const char *section, | |
476 | unsigned section_line, | |
477 | const char *name, | |
478 | const char *value, | |
479 | uint8_t min, | |
480 | uint8_t max, | |
481 | bool ignoring, | |
482 | uint8_t *ret) { | |
483 | ||
484 | unsigned t; | |
485 | int r; | |
486 | ||
487 | r = config_parse_unsigned_bounded( | |
488 | unit, filename, line, section, section_line, name, value, | |
489 | min, max, ignoring, | |
490 | &t); | |
491 | if (r <= 0) | |
492 | return r; | |
493 | assert(t <= UINT8_MAX); | |
494 | *ret = t; | |
495 | return 1; | |
496 | } |