]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/test/test-conf-parser.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / test / test-conf-parser.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
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"
22 #include "fd-util.h"
23 #include "fileio.h"
24 #include "log.h"
25 #include "macro.h"
26 #include "string-util.h"
27 #include "strv.h"
28 #include "util.h"
29
30 static void test_config_parse_path_one(const char *rvalue, const char *expected) {
31 _cleanup_free_ char *path = NULL;
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));
35 }
36
37 static 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
44 static 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
51 static 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
58 static 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
65 static 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
72 static 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
79 static void test_config_parse_strv_one(const char *rvalue, char **expected) {
80 _cleanup_strv_free_ char **strv = NULL;
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));
84 }
85
86 static 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
93 static 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
100 static 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
107 static 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");
111 test_config_parse_path_one("/path/\xc3\x80", "/path/\xc3\x80");
112
113 test_config_parse_path_one("not_absolute/path", NULL);
114 test_config_parse_path_one("/path/\xc3\x7f", NULL);
115 }
116
117 static 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
124 static 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
131 static 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
144 static 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
157 static 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
168 static 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
179 static 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"));
184 test_config_parse_strv_one("\xc3\x80", STRV_MAKE("\xc3\x80"));
185 test_config_parse_strv_one("\xc3\x7f", STRV_MAKE_EMPTY);
186 }
187
188 static 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
199 static 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
210 static 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
221 static 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
229 #define x10(x) x x x x x x x x x x
230 #define x100(x) x10(x10(x))
231 #define x1000(x) x10(x100(x))
232
233 static const char* const config_file[] = {
234 "[Section]\n"
235 "setting1=1\n",
236
237 "[Section]\n"
238 "setting1=1", /* no terminating newline */
239
240 "\n\n\n\n[Section]\n\n\n"
241 "setting1=1", /* some whitespace, no terminating newline */
242
243 "[Section]\n"
244 "[Section]\n"
245 "setting1=1\n"
246 "setting1=2\n"
247 "setting1=1\n", /* repeated settings */
248
249 "[Section]\n"
250 "setting1=1\\\n" /* normal continuation */
251 "2\\\n"
252 "3\n",
253
254 "[Section]\n"
255 "setting1=1\\\\\\\n" /* continuation with trailing escape symbols */
256 "\\\\2\n", /* note that C requires one level of escaping, so the
257 * parser gets "…1 BS BS BS NL BS BS 2 NL", which
258 * it translates into "…1 BS BS SP BS BS 2" */
259
260 "\n[Section]\n\n"
261 "setting1=" /* a line above LINE_MAX length */
262 x1000("ABCD")
263 "\n",
264
265 "[Section]\n"
266 "setting1=" /* a line above LINE_MAX length, with continuation */
267 x1000("ABCD") "\\\n"
268 "foobar",
269
270 "[Section]\n"
271 "setting1=" /* a line above the allowed limit: 9 + 1050000 + 1 */
272 x1000(x1000("x") x10("abcde")) "\n",
273
274 "[Section]\n"
275 "setting1=" /* many continuation lines, together above the limit */
276 x1000(x1000("x") x10("abcde") "\\\n") "xxx",
277 };
278
279 static void test_config_parse(unsigned i, const char *s) {
280 char name[] = "/tmp/test-conf-parser.XXXXXX";
281 int fd, r;
282 _cleanup_fclose_ FILE *f = NULL;
283 _cleanup_free_ char *setting1 = NULL;
284
285 const ConfigTableItem items[] = {
286 { "Section", "setting1", config_parse_string, 0, &setting1},
287 {}
288 };
289
290 log_info("== %s[%i] ==", __func__, i);
291
292 fd = mkostemp_safe(name);
293 assert_se(fd >= 0);
294 assert_se((size_t) write(fd, s, strlen(s)) == strlen(s));
295
296 assert_se(lseek(fd, 0, SEEK_SET) == 0);
297 assert_se(f = fdopen(fd, "r"));
298
299 /*
300 int config_parse(const char *unit,
301 const char *filename,
302 FILE *f,
303 const char *sections,
304 ConfigItemLookup lookup,
305 const void *table,
306 bool relaxed,
307 bool allow_include,
308 bool warn,
309 void *userdata)
310 */
311
312 r = config_parse(NULL, name, f,
313 "Section\0",
314 config_item_table_lookup, items,
315 CONFIG_PARSE_WARN, NULL);
316
317 switch (i) {
318 case 0 ... 3:
319 assert_se(r == 0);
320 assert_se(streq(setting1, "1"));
321 break;
322
323 case 4:
324 assert_se(r == 0);
325 assert_se(streq(setting1, "1 2 3"));
326 break;
327
328 case 5:
329 assert_se(r == 0);
330 assert_se(streq(setting1, "1\\\\ \\\\2"));
331 break;
332
333 case 6:
334 assert_se(r == 0);
335 assert_se(streq(setting1, x1000("ABCD")));
336 break;
337
338 case 7:
339 assert_se(r == 0);
340 assert_se(streq(setting1, x1000("ABCD") " foobar"));
341 break;
342
343 case 8 ... 9:
344 assert_se(r == -ENOBUFS);
345 assert_se(setting1 == NULL);
346 break;
347 }
348 }
349
350 int main(int argc, char **argv) {
351 unsigned i;
352
353 log_parse_environment();
354 log_open();
355
356 test_config_parse_path();
357 test_config_parse_log_level();
358 test_config_parse_log_facility();
359 test_config_parse_iec_size();
360 test_config_parse_si_size();
361 test_config_parse_int();
362 test_config_parse_unsigned();
363 test_config_parse_strv();
364 test_config_parse_mode();
365 test_config_parse_sec();
366 test_config_parse_nsec();
367 test_config_parse_iec_uint64();
368
369 for (i = 0; i < ELEMENTSOF(config_file); i++)
370 test_config_parse(i, config_file[i]);
371
372 return 0;
373 }