]>
Commit | Line | Data |
---|---|---|
db9ecf05 | 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
0763adbe RC |
2 | |
3 | #include "conf-parser.h" | |
e3f46367 | 4 | #include "fd-util.h" |
627d2bac | 5 | #include "fs-util.h" |
07630cea | 6 | #include "log.h" |
0763adbe | 7 | #include "macro.h" |
07630cea | 8 | #include "string-util.h" |
0763adbe | 9 | #include "strv.h" |
4f7452a8 | 10 | #include "tests.h" |
e4de7287 | 11 | #include "tmpfile-util.h" |
07630cea | 12 | #include "util.h" |
0763adbe RC |
13 | |
14 | static void test_config_parse_path_one(const char *rvalue, const char *expected) { | |
a12807aa | 15 | _cleanup_free_ char *path = NULL; |
0763adbe RC |
16 | |
17 | assert_se(config_parse_path("unit", "filename", 1, "section", 1, "lvalue", 0, rvalue, &path, NULL) >= 0); | |
18 | assert_se(streq_ptr(expected, path)); | |
0763adbe RC |
19 | } |
20 | ||
21 | static void test_config_parse_log_level_one(const char *rvalue, int expected) { | |
22 | int log_level = 0; | |
23 | ||
24 | assert_se(config_parse_log_level("unit", "filename", 1, "section", 1, "lvalue", 0, rvalue, &log_level, NULL) >= 0); | |
25 | assert_se(expected == log_level); | |
26 | } | |
27 | ||
28 | static void test_config_parse_log_facility_one(const char *rvalue, int expected) { | |
29 | int log_facility = 0; | |
30 | ||
31 | assert_se(config_parse_log_facility("unit", "filename", 1, "section", 1, "lvalue", 0, rvalue, &log_facility, NULL) >= 0); | |
32 | assert_se(expected == log_facility); | |
33 | } | |
34 | ||
35 | static void test_config_parse_iec_size_one(const char *rvalue, size_t expected) { | |
36 | size_t iec_size = 0; | |
37 | ||
38 | assert_se(config_parse_iec_size("unit", "filename", 1, "section", 1, "lvalue", 0, rvalue, &iec_size, NULL) >= 0); | |
39 | assert_se(expected == iec_size); | |
40 | } | |
41 | ||
50299121 YW |
42 | static void test_config_parse_si_uint64_one(const char *rvalue, uint64_t expected) { |
43 | uint64_t si_uint64 = 0; | |
0763adbe | 44 | |
50299121 YW |
45 | assert_se(config_parse_si_uint64("unit", "filename", 1, "section", 1, "lvalue", 0, rvalue, &si_uint64, NULL) >= 0); |
46 | assert_se(expected == si_uint64); | |
0763adbe RC |
47 | } |
48 | ||
49 | static void test_config_parse_int_one(const char *rvalue, int expected) { | |
50 | int v = -1; | |
51 | ||
52 | assert_se(config_parse_int("unit", "filename", 1, "section", 1, "lvalue", 0, rvalue, &v, NULL) >= 0); | |
53 | assert_se(expected == v); | |
54 | } | |
55 | ||
56 | static void test_config_parse_unsigned_one(const char *rvalue, unsigned expected) { | |
57 | unsigned v = 0; | |
58 | ||
59 | assert_se(config_parse_unsigned("unit", "filename", 1, "section", 1, "lvalue", 0, rvalue, &v, NULL) >= 0); | |
60 | assert_se(expected == v); | |
61 | } | |
62 | ||
63 | static void test_config_parse_strv_one(const char *rvalue, char **expected) { | |
a12807aa | 64 | _cleanup_strv_free_ char **strv = NULL; |
0763adbe RC |
65 | |
66 | assert_se(config_parse_strv("unit", "filename", 1, "section", 1, "lvalue", 0, rvalue, &strv, NULL) >= 0); | |
67 | assert_se(strv_equal(expected, strv)); | |
0763adbe RC |
68 | } |
69 | ||
70 | static void test_config_parse_mode_one(const char *rvalue, mode_t expected) { | |
71 | mode_t v = 0; | |
72 | ||
73 | assert_se(config_parse_mode("unit", "filename", 1, "section", 1, "lvalue", 0, rvalue, &v, NULL) >= 0); | |
74 | assert_se(expected == v); | |
75 | } | |
76 | ||
77 | static void test_config_parse_sec_one(const char *rvalue, usec_t expected) { | |
78 | usec_t v = 0; | |
79 | ||
80 | assert_se(config_parse_sec("unit", "filename", 1, "section", 1, "lvalue", 0, rvalue, &v, NULL) >= 0); | |
81 | assert_se(expected == v); | |
82 | } | |
83 | ||
84 | static void test_config_parse_nsec_one(const char *rvalue, nsec_t expected) { | |
85 | nsec_t v = 0; | |
86 | ||
87 | assert_se(config_parse_nsec("unit", "filename", 1, "nsection", 1, "lvalue", 0, rvalue, &v, NULL) >= 0); | |
88 | assert_se(expected == v); | |
89 | } | |
90 | ||
4f7452a8 | 91 | TEST(config_parse_path) { |
0763adbe RC |
92 | test_config_parse_path_one("/path", "/path"); |
93 | test_config_parse_path_one("/path//////////", "/path"); | |
94 | test_config_parse_path_one("///path/foo///bar////bar//", "/path/foo/bar/bar"); | |
cd4f53c5 | 95 | test_config_parse_path_one("/path//./////hogehoge///.", "/path/hogehoge"); |
d5ade2d6 | 96 | test_config_parse_path_one("/path/\xc3\x80", "/path/\xc3\x80"); |
0763adbe RC |
97 | |
98 | test_config_parse_path_one("not_absolute/path", NULL); | |
d5ade2d6 | 99 | test_config_parse_path_one("/path/\xc3\x7f", NULL); |
0763adbe RC |
100 | } |
101 | ||
4f7452a8 | 102 | TEST(config_parse_log_level) { |
0763adbe RC |
103 | test_config_parse_log_level_one("debug", LOG_DEBUG); |
104 | test_config_parse_log_level_one("info", LOG_INFO); | |
105 | ||
106 | test_config_parse_log_level_one("garbage", 0); | |
107 | } | |
108 | ||
4f7452a8 | 109 | TEST(config_parse_log_facility) { |
0763adbe RC |
110 | test_config_parse_log_facility_one("mail", LOG_MAIL); |
111 | test_config_parse_log_facility_one("user", LOG_USER); | |
112 | ||
113 | test_config_parse_log_facility_one("garbage", 0); | |
114 | } | |
115 | ||
4f7452a8 | 116 | TEST(config_parse_iec_size) { |
0763adbe RC |
117 | test_config_parse_iec_size_one("1024", 1024); |
118 | test_config_parse_iec_size_one("2K", 2048); | |
119 | test_config_parse_iec_size_one("10M", 10 * 1024 * 1024); | |
120 | test_config_parse_iec_size_one("1G", 1 * 1024 * 1024 * 1024); | |
121 | test_config_parse_iec_size_one("0G", 0); | |
122 | test_config_parse_iec_size_one("0", 0); | |
123 | ||
124 | test_config_parse_iec_size_one("-982", 0); | |
125 | test_config_parse_iec_size_one("49874444198739873000000G", 0); | |
126 | test_config_parse_iec_size_one("garbage", 0); | |
127 | } | |
128 | ||
4f7452a8 | 129 | TEST(config_parse_si_uint64) { |
50299121 YW |
130 | test_config_parse_si_uint64_one("1024", 1024); |
131 | test_config_parse_si_uint64_one("2K", 2000); | |
132 | test_config_parse_si_uint64_one("10M", 10 * 1000 * 1000); | |
133 | test_config_parse_si_uint64_one("1G", 1 * 1000 * 1000 * 1000); | |
134 | test_config_parse_si_uint64_one("0G", 0); | |
135 | test_config_parse_si_uint64_one("0", 0); | |
136 | ||
137 | test_config_parse_si_uint64_one("-982", 0); | |
138 | test_config_parse_si_uint64_one("49874444198739873000000G", 0); | |
139 | test_config_parse_si_uint64_one("garbage", 0); | |
0763adbe RC |
140 | } |
141 | ||
4f7452a8 | 142 | TEST(config_parse_int) { |
0763adbe RC |
143 | test_config_parse_int_one("1024", 1024); |
144 | test_config_parse_int_one("-1024", -1024); | |
145 | test_config_parse_int_one("0", 0); | |
146 | ||
147 | test_config_parse_int_one("99999999999999999999999999999999999999999999999999999999", -1); | |
148 | test_config_parse_int_one("-99999999999999999999999999999999999999999999999999999999", -1); | |
149 | test_config_parse_int_one("1G", -1); | |
150 | test_config_parse_int_one("garbage", -1); | |
151 | } | |
152 | ||
4f7452a8 | 153 | TEST(config_parse_unsigned) { |
0763adbe RC |
154 | test_config_parse_unsigned_one("10241024", 10241024); |
155 | test_config_parse_unsigned_one("1024", 1024); | |
156 | test_config_parse_unsigned_one("0", 0); | |
157 | ||
158 | test_config_parse_unsigned_one("99999999999999999999999999999999999999999999999999999999", 0); | |
159 | test_config_parse_unsigned_one("1G", 0); | |
160 | test_config_parse_unsigned_one("garbage", 0); | |
161 | test_config_parse_unsigned_one("1000garbage", 0); | |
162 | } | |
163 | ||
4f7452a8 | 164 | TEST(config_parse_strv) { |
0763adbe RC |
165 | test_config_parse_strv_one("", STRV_MAKE_EMPTY); |
166 | test_config_parse_strv_one("foo", STRV_MAKE("foo")); | |
167 | test_config_parse_strv_one("foo bar foo", STRV_MAKE("foo", "bar", "foo")); | |
168 | test_config_parse_strv_one("\"foo bar\" foo", STRV_MAKE("foo bar", "foo")); | |
b4958f42 | 169 | test_config_parse_strv_one("\xc3\x80", STRV_MAKE("\xc3\x80")); |
f106314c | 170 | test_config_parse_strv_one("\xc3\x7f", STRV_MAKE("\xc3\x7f")); |
0763adbe RC |
171 | } |
172 | ||
4f7452a8 | 173 | TEST(config_parse_mode) { |
0763adbe RC |
174 | test_config_parse_mode_one("777", 0777); |
175 | test_config_parse_mode_one("644", 0644); | |
176 | ||
177 | test_config_parse_mode_one("-777", 0); | |
178 | test_config_parse_mode_one("999", 0); | |
179 | test_config_parse_mode_one("garbage", 0); | |
180 | test_config_parse_mode_one("777garbage", 0); | |
181 | test_config_parse_mode_one("777 garbage", 0); | |
182 | } | |
183 | ||
4f7452a8 | 184 | TEST(config_parse_sec) { |
0763adbe RC |
185 | test_config_parse_sec_one("1", 1 * USEC_PER_SEC); |
186 | test_config_parse_sec_one("1s", 1 * USEC_PER_SEC); | |
187 | test_config_parse_sec_one("100ms", 100 * USEC_PER_MSEC); | |
188 | test_config_parse_sec_one("5min 20s", 5 * 60 * USEC_PER_SEC + 20 * USEC_PER_SEC); | |
189 | ||
190 | test_config_parse_sec_one("-1", 0); | |
191 | test_config_parse_sec_one("10foo", 0); | |
192 | test_config_parse_sec_one("garbage", 0); | |
193 | } | |
194 | ||
4f7452a8 | 195 | TEST(config_parse_nsec) { |
0763adbe RC |
196 | test_config_parse_nsec_one("1", 1); |
197 | test_config_parse_nsec_one("1s", 1 * NSEC_PER_SEC); | |
198 | test_config_parse_nsec_one("100ms", 100 * NSEC_PER_MSEC); | |
199 | test_config_parse_nsec_one("5min 20s", 5 * 60 * NSEC_PER_SEC + 20 * NSEC_PER_SEC); | |
200 | ||
201 | test_config_parse_nsec_one("-1", 0); | |
202 | test_config_parse_nsec_one("10foo", 0); | |
203 | test_config_parse_nsec_one("garbage", 0); | |
204 | } | |
205 | ||
4f7452a8 | 206 | TEST(config_parse_iec_uint64) { |
f55211db RC |
207 | uint64_t offset = 0; |
208 | assert_se(config_parse_iec_uint64(NULL, "/this/file", 11, "Section", 22, "Size", 0, "4M", &offset, NULL) == 0); | |
209 | assert_se(offset == 4 * 1024 * 1024); | |
210 | ||
211 | assert_se(config_parse_iec_uint64(NULL, "/this/file", 11, "Section", 22, "Size", 0, "4.5M", &offset, NULL) == 0); | |
212 | } | |
213 | ||
8f313f4f ZJS |
214 | #define x10(x) x x x x x x x x x x |
215 | #define x100(x) x10(x10(x)) | |
216 | #define x1000(x) x10(x100(x)) | |
217 | ||
e3f46367 ZJS |
218 | static const char* const config_file[] = { |
219 | "[Section]\n" | |
220 | "setting1=1\n", | |
221 | ||
222 | "[Section]\n" | |
223 | "setting1=1", /* no terminating newline */ | |
224 | ||
225 | "\n\n\n\n[Section]\n\n\n" | |
226 | "setting1=1", /* some whitespace, no terminating newline */ | |
227 | ||
228 | "[Section]\n" | |
229 | "[Section]\n" | |
230 | "setting1=1\n" | |
b9d9fbe4 ZJS |
231 | "setting1= 2 \t\n" |
232 | "setting1= 1\n", /* repeated settings */ | |
e3f46367 | 233 | |
3d5d346a YW |
234 | "[Section]\n" |
235 | "[Section]\n" | |
236 | "setting1=1\n" | |
237 | "setting1=2\\\n" | |
238 | " \n" /* empty line breaks continuation */ | |
239 | "setting1=1\n", /* repeated settings */ | |
240 | ||
e3f46367 ZJS |
241 | "[Section]\n" |
242 | "setting1=1\\\n" /* normal continuation */ | |
243 | "2\\\n" | |
244 | "3\n", | |
245 | ||
9adbfeb3 YW |
246 | "[Section]\n" |
247 | "#hogehoge\\\n" /* continuation is ignored in comment */ | |
248 | "setting1=1\\\n" /* normal continuation */ | |
249 | "2\\\n" | |
250 | "3\n", | |
251 | ||
252 | "[Section]\n" | |
253 | "setting1=1\\\n" /* normal continuation */ | |
254 | "#hogehoge\\\n" /* commented out line in continuation is ignored */ | |
255 | "2\\\n" | |
256 | "3\n", | |
257 | ||
ff650ffe YW |
258 | "[Section]\n" |
259 | " #hogehoge\\\n" /* whitespaces before comments */ | |
260 | " setting1=1\\\n" /* whitespaces before key */ | |
261 | "2\\\n" | |
262 | "3\n", | |
263 | ||
264 | "[Section]\n" | |
265 | " setting1=1\\\n" /* whitespaces before key */ | |
266 | " #hogehoge\\\n" /* commented out line prefixed with whitespaces in continuation */ | |
267 | "2\\\n" | |
268 | "3\n", | |
269 | ||
4f29e0db FB |
270 | "[Section]\n" |
271 | "setting1=1\\\n" /* continuation with extra trailing backslash at the end */ | |
272 | "2\\\n" | |
273 | "3\\\n", | |
274 | ||
e3f46367 ZJS |
275 | "[Section]\n" |
276 | "setting1=1\\\\\\\n" /* continuation with trailing escape symbols */ | |
277 | "\\\\2\n", /* note that C requires one level of escaping, so the | |
278 | * parser gets "…1 BS BS BS NL BS BS 2 NL", which | |
279 | * it translates into "…1 BS BS SP BS BS 2" */ | |
8f313f4f ZJS |
280 | |
281 | "\n[Section]\n\n" | |
282 | "setting1=" /* a line above LINE_MAX length */ | |
283 | x1000("ABCD") | |
284 | "\n", | |
285 | ||
286 | "[Section]\n" | |
287 | "setting1=" /* a line above LINE_MAX length, with continuation */ | |
288 | x1000("ABCD") "\\\n" | |
289 | "foobar", | |
290 | ||
4f29e0db FB |
291 | "[Section]\n" |
292 | "setting1=" /* a line above LINE_MAX length, with continuation */ | |
293 | x1000("ABCD") "\\\n" /* and an extra trailing backslash */ | |
294 | "foobar\\\n", | |
295 | ||
8f313f4f ZJS |
296 | "[Section]\n" |
297 | "setting1=" /* a line above the allowed limit: 9 + 1050000 + 1 */ | |
298 | x1000(x1000("x") x10("abcde")) "\n", | |
299 | ||
300 | "[Section]\n" | |
301 | "setting1=" /* many continuation lines, together above the limit */ | |
302 | x1000(x1000("x") x10("abcde") "\\\n") "xxx", | |
ddeb3f5d ZJS |
303 | |
304 | "[Section]\n" | |
305 | "setting1=2\n" | |
306 | "[NoWarnSection]\n" | |
307 | "setting1=3\n" | |
308 | "[WarnSection]\n" | |
309 | "setting1=3\n" | |
310 | "[X-Section]\n" | |
311 | "setting1=3\n", | |
e3f46367 ZJS |
312 | }; |
313 | ||
4f7452a8 | 314 | static void test_config_parse_one(unsigned i, const char *s) { |
627d2bac | 315 | _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-conf-parser.XXXXXX"; |
e3f46367 ZJS |
316 | _cleanup_fclose_ FILE *f = NULL; |
317 | _cleanup_free_ char *setting1 = NULL; | |
d8351049 | 318 | int r; |
e3f46367 ZJS |
319 | |
320 | const ConfigTableItem items[] = { | |
321 | { "Section", "setting1", config_parse_string, 0, &setting1}, | |
322 | {} | |
323 | }; | |
324 | ||
325 | log_info("== %s[%i] ==", __func__, i); | |
326 | ||
d8351049 ZJS |
327 | assert_se(fmkostemp_safe(name, "r+", &f) == 0); |
328 | assert_se(fwrite(s, strlen(s), 1, f) == 1); | |
329 | rewind(f); | |
e3f46367 ZJS |
330 | |
331 | /* | |
332 | int config_parse(const char *unit, | |
333 | const char *filename, | |
334 | FILE *f, | |
335 | const char *sections, | |
336 | ConfigItemLookup lookup, | |
337 | const void *table, | |
ddeb3f5d | 338 | ConfigParseFlags flags, |
4f9ff96a | 339 | void *userdata, |
3dea4701 | 340 | struct stat *ret_stat); |
e3f46367 ZJS |
341 | */ |
342 | ||
343 | r = config_parse(NULL, name, f, | |
4f9ff96a LP |
344 | "Section\0" |
345 | "-NoWarnSection\0", | |
e3f46367 | 346 | config_item_table_lookup, items, |
4f9ff96a LP |
347 | CONFIG_PARSE_WARN, |
348 | NULL, | |
349 | NULL); | |
e3f46367 ZJS |
350 | |
351 | switch (i) { | |
3d5d346a | 352 | case 0 ... 4: |
8b8024f1 | 353 | assert_se(r == 1); |
e3f46367 ZJS |
354 | assert_se(streq(setting1, "1")); |
355 | break; | |
356 | ||
3d5d346a | 357 | case 5 ... 10: |
8b8024f1 | 358 | assert_se(r == 1); |
e3f46367 ZJS |
359 | assert_se(streq(setting1, "1 2 3")); |
360 | break; | |
361 | ||
3d5d346a | 362 | case 11: |
8b8024f1 | 363 | assert_se(r == 1); |
e3f46367 ZJS |
364 | assert_se(streq(setting1, "1\\\\ \\\\2")); |
365 | break; | |
8f313f4f | 366 | |
3d5d346a | 367 | case 12: |
8b8024f1 | 368 | assert_se(r == 1); |
8f313f4f ZJS |
369 | assert_se(streq(setting1, x1000("ABCD"))); |
370 | break; | |
371 | ||
3d5d346a | 372 | case 13 ... 14: |
8b8024f1 | 373 | assert_se(r == 1); |
8f313f4f ZJS |
374 | assert_se(streq(setting1, x1000("ABCD") " foobar")); |
375 | break; | |
376 | ||
3d5d346a | 377 | case 15 ... 16: |
8f313f4f ZJS |
378 | assert_se(r == -ENOBUFS); |
379 | assert_se(setting1 == NULL); | |
380 | break; | |
ddeb3f5d ZJS |
381 | |
382 | case 17: | |
8b8024f1 | 383 | assert_se(r == 1); |
ddeb3f5d ZJS |
384 | assert_se(streq(setting1, "2")); |
385 | break; | |
e3f46367 ZJS |
386 | } |
387 | } | |
388 | ||
4f7452a8 JJ |
389 | TEST(config_parse) { |
390 | for (unsigned i = 0; i < ELEMENTSOF(config_file); i++) | |
391 | test_config_parse_one(i, config_file[i]); | |
0763adbe | 392 | } |
4f7452a8 JJ |
393 | |
394 | DEFINE_TEST_MAIN(LOG_INFO); |