]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/test/test-conf-parser.c
tools/hwdb-update: allow downloads to fail
[thirdparty/systemd.git] / src / test / test-conf-parser.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
0763adbe
RC
2/***
3 This file is part of systemd.
4
5 Copyright 2015 Ronny Chevalier
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19***/
20
21#include "conf-parser.h"
e3f46367
ZJS
22#include "fd-util.h"
23#include "fileio.h"
07630cea 24#include "log.h"
0763adbe 25#include "macro.h"
07630cea 26#include "string-util.h"
0763adbe 27#include "strv.h"
07630cea 28#include "util.h"
0763adbe
RC
29
30static void test_config_parse_path_one(const char *rvalue, const char *expected) {
a12807aa 31 _cleanup_free_ char *path = NULL;
0763adbe
RC
32
33 assert_se(config_parse_path("unit", "filename", 1, "section", 1, "lvalue", 0, rvalue, &path, NULL) >= 0);
34 assert_se(streq_ptr(expected, path));
0763adbe
RC
35}
36
37static void test_config_parse_log_level_one(const char *rvalue, int expected) {
38 int log_level = 0;
39
40 assert_se(config_parse_log_level("unit", "filename", 1, "section", 1, "lvalue", 0, rvalue, &log_level, NULL) >= 0);
41 assert_se(expected == log_level);
42}
43
44static void test_config_parse_log_facility_one(const char *rvalue, int expected) {
45 int log_facility = 0;
46
47 assert_se(config_parse_log_facility("unit", "filename", 1, "section", 1, "lvalue", 0, rvalue, &log_facility, NULL) >= 0);
48 assert_se(expected == log_facility);
49}
50
51static void test_config_parse_iec_size_one(const char *rvalue, size_t expected) {
52 size_t iec_size = 0;
53
54 assert_se(config_parse_iec_size("unit", "filename", 1, "section", 1, "lvalue", 0, rvalue, &iec_size, NULL) >= 0);
55 assert_se(expected == iec_size);
56}
57
58static void test_config_parse_si_size_one(const char *rvalue, size_t expected) {
59 size_t si_size = 0;
60
61 assert_se(config_parse_si_size("unit", "filename", 1, "section", 1, "lvalue", 0, rvalue, &si_size, NULL) >= 0);
62 assert_se(expected == si_size);
63}
64
65static void test_config_parse_int_one(const char *rvalue, int expected) {
66 int v = -1;
67
68 assert_se(config_parse_int("unit", "filename", 1, "section", 1, "lvalue", 0, rvalue, &v, NULL) >= 0);
69 assert_se(expected == v);
70}
71
72static void test_config_parse_unsigned_one(const char *rvalue, unsigned expected) {
73 unsigned v = 0;
74
75 assert_se(config_parse_unsigned("unit", "filename", 1, "section", 1, "lvalue", 0, rvalue, &v, NULL) >= 0);
76 assert_se(expected == v);
77}
78
79static void test_config_parse_strv_one(const char *rvalue, char **expected) {
a12807aa 80 _cleanup_strv_free_ char **strv = NULL;
0763adbe
RC
81
82 assert_se(config_parse_strv("unit", "filename", 1, "section", 1, "lvalue", 0, rvalue, &strv, NULL) >= 0);
83 assert_se(strv_equal(expected, strv));
0763adbe
RC
84}
85
86static void test_config_parse_mode_one(const char *rvalue, mode_t expected) {
87 mode_t v = 0;
88
89 assert_se(config_parse_mode("unit", "filename", 1, "section", 1, "lvalue", 0, rvalue, &v, NULL) >= 0);
90 assert_se(expected == v);
91}
92
93static void test_config_parse_sec_one(const char *rvalue, usec_t expected) {
94 usec_t v = 0;
95
96 assert_se(config_parse_sec("unit", "filename", 1, "section", 1, "lvalue", 0, rvalue, &v, NULL) >= 0);
97 assert_se(expected == v);
98}
99
100static void test_config_parse_nsec_one(const char *rvalue, nsec_t expected) {
101 nsec_t v = 0;
102
103 assert_se(config_parse_nsec("unit", "filename", 1, "nsection", 1, "lvalue", 0, rvalue, &v, NULL) >= 0);
104 assert_se(expected == v);
105}
106
107static void test_config_parse_path(void) {
108 test_config_parse_path_one("/path", "/path");
109 test_config_parse_path_one("/path//////////", "/path");
110 test_config_parse_path_one("///path/foo///bar////bar//", "/path/foo/bar/bar");
d5ade2d6 111 test_config_parse_path_one("/path/\xc3\x80", "/path/\xc3\x80");
0763adbe
RC
112
113 test_config_parse_path_one("not_absolute/path", NULL);
d5ade2d6 114 test_config_parse_path_one("/path/\xc3\x7f", NULL);
0763adbe
RC
115}
116
117static void test_config_parse_log_level(void) {
118 test_config_parse_log_level_one("debug", LOG_DEBUG);
119 test_config_parse_log_level_one("info", LOG_INFO);
120
121 test_config_parse_log_level_one("garbage", 0);
122}
123
124static void test_config_parse_log_facility(void) {
125 test_config_parse_log_facility_one("mail", LOG_MAIL);
126 test_config_parse_log_facility_one("user", LOG_USER);
127
128 test_config_parse_log_facility_one("garbage", 0);
129}
130
131static void test_config_parse_iec_size(void) {
132 test_config_parse_iec_size_one("1024", 1024);
133 test_config_parse_iec_size_one("2K", 2048);
134 test_config_parse_iec_size_one("10M", 10 * 1024 * 1024);
135 test_config_parse_iec_size_one("1G", 1 * 1024 * 1024 * 1024);
136 test_config_parse_iec_size_one("0G", 0);
137 test_config_parse_iec_size_one("0", 0);
138
139 test_config_parse_iec_size_one("-982", 0);
140 test_config_parse_iec_size_one("49874444198739873000000G", 0);
141 test_config_parse_iec_size_one("garbage", 0);
142}
143
144static void test_config_parse_si_size(void) {
145 test_config_parse_si_size_one("1024", 1024);
146 test_config_parse_si_size_one("2K", 2000);
147 test_config_parse_si_size_one("10M", 10 * 1000 * 1000);
148 test_config_parse_si_size_one("1G", 1 * 1000 * 1000 * 1000);
149 test_config_parse_si_size_one("0G", 0);
150 test_config_parse_si_size_one("0", 0);
151
152 test_config_parse_si_size_one("-982", 0);
153 test_config_parse_si_size_one("49874444198739873000000G", 0);
154 test_config_parse_si_size_one("garbage", 0);
155}
156
157static void test_config_parse_int(void) {
158 test_config_parse_int_one("1024", 1024);
159 test_config_parse_int_one("-1024", -1024);
160 test_config_parse_int_one("0", 0);
161
162 test_config_parse_int_one("99999999999999999999999999999999999999999999999999999999", -1);
163 test_config_parse_int_one("-99999999999999999999999999999999999999999999999999999999", -1);
164 test_config_parse_int_one("1G", -1);
165 test_config_parse_int_one("garbage", -1);
166}
167
168static void test_config_parse_unsigned(void) {
169 test_config_parse_unsigned_one("10241024", 10241024);
170 test_config_parse_unsigned_one("1024", 1024);
171 test_config_parse_unsigned_one("0", 0);
172
173 test_config_parse_unsigned_one("99999999999999999999999999999999999999999999999999999999", 0);
174 test_config_parse_unsigned_one("1G", 0);
175 test_config_parse_unsigned_one("garbage", 0);
176 test_config_parse_unsigned_one("1000garbage", 0);
177}
178
179static void test_config_parse_strv(void) {
180 test_config_parse_strv_one("", STRV_MAKE_EMPTY);
181 test_config_parse_strv_one("foo", STRV_MAKE("foo"));
182 test_config_parse_strv_one("foo bar foo", STRV_MAKE("foo", "bar", "foo"));
183 test_config_parse_strv_one("\"foo bar\" foo", STRV_MAKE("foo bar", "foo"));
b4958f42
RC
184 test_config_parse_strv_one("\xc3\x80", STRV_MAKE("\xc3\x80"));
185 test_config_parse_strv_one("\xc3\x7f", STRV_MAKE_EMPTY);
0763adbe
RC
186}
187
188static void test_config_parse_mode(void) {
189 test_config_parse_mode_one("777", 0777);
190 test_config_parse_mode_one("644", 0644);
191
192 test_config_parse_mode_one("-777", 0);
193 test_config_parse_mode_one("999", 0);
194 test_config_parse_mode_one("garbage", 0);
195 test_config_parse_mode_one("777garbage", 0);
196 test_config_parse_mode_one("777 garbage", 0);
197}
198
199static void test_config_parse_sec(void) {
200 test_config_parse_sec_one("1", 1 * USEC_PER_SEC);
201 test_config_parse_sec_one("1s", 1 * USEC_PER_SEC);
202 test_config_parse_sec_one("100ms", 100 * USEC_PER_MSEC);
203 test_config_parse_sec_one("5min 20s", 5 * 60 * USEC_PER_SEC + 20 * USEC_PER_SEC);
204
205 test_config_parse_sec_one("-1", 0);
206 test_config_parse_sec_one("10foo", 0);
207 test_config_parse_sec_one("garbage", 0);
208}
209
210static void test_config_parse_nsec(void) {
211 test_config_parse_nsec_one("1", 1);
212 test_config_parse_nsec_one("1s", 1 * NSEC_PER_SEC);
213 test_config_parse_nsec_one("100ms", 100 * NSEC_PER_MSEC);
214 test_config_parse_nsec_one("5min 20s", 5 * 60 * NSEC_PER_SEC + 20 * NSEC_PER_SEC);
215
216 test_config_parse_nsec_one("-1", 0);
217 test_config_parse_nsec_one("10foo", 0);
218 test_config_parse_nsec_one("garbage", 0);
219}
220
f55211db
RC
221static void test_config_parse_iec_uint64(void) {
222 uint64_t offset = 0;
223 assert_se(config_parse_iec_uint64(NULL, "/this/file", 11, "Section", 22, "Size", 0, "4M", &offset, NULL) == 0);
224 assert_se(offset == 4 * 1024 * 1024);
225
226 assert_se(config_parse_iec_uint64(NULL, "/this/file", 11, "Section", 22, "Size", 0, "4.5M", &offset, NULL) == 0);
227}
228
9ecdba8c
ZJS
229static void test_config_parse_join_controllers(void) {
230 int r;
231 _cleanup_(strv_free_freep) char ***c = NULL;
232 char ***c2;
233
234 /* Test normal operation */
235 r = config_parse_join_controllers(NULL, "example.conf", 11, "Section", 10, "JoinControllers", 0, "cpu,cpuacct net_cls,netprio", &c, NULL);
236 assert_se(r == 0);
237 assert_se(c);
238 assert_se(strv_length(c[0]) == 2);
239 assert_se(strv_equal(c[0], STRV_MAKE("cpu", "cpuacct")));
240 assert_se(strv_length(c[1]) == 2);
241 assert_se(strv_equal(c[1], STRV_MAKE("net_cls", "netprio")));
242 assert_se(c[2] == NULL);
243
244 /* Test special case of no mounted controllers */
245 r = config_parse_join_controllers(NULL, "example.conf", 12, "Section", 10, "JoinControllers", 0, "", &c, NULL);
246 assert_se(r == 0);
56c8d744
ZJS
247 assert_se(c);
248 assert_se(strv_equal(c[0], STRV_MAKE_EMPTY));
249 assert_se(c[1] == NULL);
9ecdba8c
ZJS
250
251 /* Test merging of overlapping lists */
252 r = config_parse_join_controllers(NULL, "example.conf", 13, "Section", 10, "JoinControllers", 0, "a,b b,c", &c, NULL);
253 assert_se(r == 0);
254 assert_se(c);
255 assert_se(strv_length(c[0]) == 3);
256 assert_se(strv_contains(c[0], "a"));
257 assert_se(strv_contains(c[0], "b"));
258 assert_se(strv_contains(c[0], "c"));
259 assert_se(c[1] == NULL);
260
261 /* Test ignoring of bad lines */
262 c2 = c;
263 r = config_parse_join_controllers(NULL, "example.conf", 14, "Section", 10, "JoinControllers", 0, "a,\"b ", &c, NULL);
264 assert_se(r < 0);
265 assert_se(c == c2);
266}
267
8f313f4f
ZJS
268#define x10(x) x x x x x x x x x x
269#define x100(x) x10(x10(x))
270#define x1000(x) x10(x100(x))
271
e3f46367
ZJS
272static const char* const config_file[] = {
273 "[Section]\n"
274 "setting1=1\n",
275
276 "[Section]\n"
277 "setting1=1", /* no terminating newline */
278
279 "\n\n\n\n[Section]\n\n\n"
280 "setting1=1", /* some whitespace, no terminating newline */
281
282 "[Section]\n"
283 "[Section]\n"
284 "setting1=1\n"
285 "setting1=2\n"
286 "setting1=1\n", /* repeated settings */
287
288 "[Section]\n"
289 "setting1=1\\\n" /* normal continuation */
290 "2\\\n"
291 "3\n",
292
293 "[Section]\n"
294 "setting1=1\\\\\\\n" /* continuation with trailing escape symbols */
295 "\\\\2\n", /* note that C requires one level of escaping, so the
296 * parser gets "…1 BS BS BS NL BS BS 2 NL", which
297 * it translates into "…1 BS BS SP BS BS 2" */
8f313f4f
ZJS
298
299 "\n[Section]\n\n"
300 "setting1=" /* a line above LINE_MAX length */
301 x1000("ABCD")
302 "\n",
303
304 "[Section]\n"
305 "setting1=" /* a line above LINE_MAX length, with continuation */
306 x1000("ABCD") "\\\n"
307 "foobar",
308
309 "[Section]\n"
310 "setting1=" /* a line above the allowed limit: 9 + 1050000 + 1 */
311 x1000(x1000("x") x10("abcde")) "\n",
312
313 "[Section]\n"
314 "setting1=" /* many continuation lines, together above the limit */
315 x1000(x1000("x") x10("abcde") "\\\n") "xxx",
e3f46367
ZJS
316};
317
318static void test_config_parse(unsigned i, const char *s) {
319 char name[] = "/tmp/test-conf-parser.XXXXXX";
320 int fd, r;
321 _cleanup_fclose_ FILE *f = NULL;
322 _cleanup_free_ char *setting1 = NULL;
323
324 const ConfigTableItem items[] = {
325 { "Section", "setting1", config_parse_string, 0, &setting1},
326 {}
327 };
328
329 log_info("== %s[%i] ==", __func__, i);
330
331 fd = mkostemp_safe(name);
332 assert_se(fd >= 0);
333 assert_se((size_t) write(fd, s, strlen(s)) == strlen(s));
334
335 assert_se(lseek(fd, 0, SEEK_SET) == 0);
336 assert_se(f = fdopen(fd, "r"));
337
338 /*
339 int config_parse(const char *unit,
340 const char *filename,
341 FILE *f,
342 const char *sections,
343 ConfigItemLookup lookup,
344 const void *table,
345 bool relaxed,
346 bool allow_include,
347 bool warn,
348 void *userdata)
349 */
350
351 r = config_parse(NULL, name, f,
352 "Section\0",
353 config_item_table_lookup, items,
bcde742e 354 CONFIG_PARSE_WARN, NULL);
e3f46367
ZJS
355
356 switch (i) {
357 case 0 ... 3:
8f313f4f 358 assert_se(r == 0);
e3f46367
ZJS
359 assert_se(streq(setting1, "1"));
360 break;
361
362 case 4:
8f313f4f 363 assert_se(r == 0);
e3f46367
ZJS
364 assert_se(streq(setting1, "1 2 3"));
365 break;
366
367 case 5:
8f313f4f 368 assert_se(r == 0);
e3f46367
ZJS
369 assert_se(streq(setting1, "1\\\\ \\\\2"));
370 break;
8f313f4f
ZJS
371
372 case 6:
373 assert_se(r == 0);
374 assert_se(streq(setting1, x1000("ABCD")));
375 break;
376
377 case 7:
378 assert_se(r == 0);
379 assert_se(streq(setting1, x1000("ABCD") " foobar"));
380 break;
381
382 case 8 ... 9:
383 assert_se(r == -ENOBUFS);
384 assert_se(setting1 == NULL);
385 break;
e3f46367
ZJS
386 }
387}
388
0763adbe 389int main(int argc, char **argv) {
e3f46367
ZJS
390 unsigned i;
391
0763adbe
RC
392 log_parse_environment();
393 log_open();
394
395 test_config_parse_path();
396 test_config_parse_log_level();
397 test_config_parse_log_facility();
398 test_config_parse_iec_size();
399 test_config_parse_si_size();
400 test_config_parse_int();
401 test_config_parse_unsigned();
402 test_config_parse_strv();
403 test_config_parse_mode();
404 test_config_parse_sec();
405 test_config_parse_nsec();
f55211db 406 test_config_parse_iec_uint64();
9ecdba8c 407 test_config_parse_join_controllers();
0763adbe 408
e3f46367
ZJS
409 for (i = 0; i < ELEMENTSOF(config_file); i++)
410 test_config_parse(i, config_file[i]);
411
0763adbe
RC
412 return 0;
413}