1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2015 Ronny Chevalier
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.
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.
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/>.
21 #include "conf-parser.h"
26 #include "string-util.h"
30 /// Additional includes needed by elogind
34 static void test_config_parse_path_one(const char *rvalue, const char *expected) {
35 _cleanup_free_ char *path = NULL;
37 assert_se(config_parse_path("unit", "filename", 1, "section", 1, "lvalue", 0, rvalue, &path, NULL) >= 0);
38 assert_se(streq_ptr(expected, path));
41 static void test_config_parse_log_level_one(const char *rvalue, int expected) {
44 assert_se(config_parse_log_level("unit", "filename", 1, "section", 1, "lvalue", 0, rvalue, &log_level, NULL) >= 0);
45 assert_se(expected == log_level);
48 #if 0 /// UNNEEDED by elogind
49 static void test_config_parse_log_facility_one(const char *rvalue, int expected) {
52 assert_se(config_parse_log_facility("unit", "filename", 1, "section", 1, "lvalue", 0, rvalue, &log_facility, NULL) >= 0);
53 assert_se(expected == log_facility);
57 static void test_config_parse_iec_size_one(const char *rvalue, size_t expected) {
60 assert_se(config_parse_iec_size("unit", "filename", 1, "section", 1, "lvalue", 0, rvalue, &iec_size, NULL) >= 0);
61 assert_se(expected == iec_size);
64 #if 0 /// UNNEEDED by elogind
65 static void test_config_parse_si_size_one(const char *rvalue, size_t expected) {
68 assert_se(config_parse_si_size("unit", "filename", 1, "section", 1, "lvalue", 0, rvalue, &si_size, NULL) >= 0);
69 assert_se(expected == si_size);
73 static void test_config_parse_int_one(const char *rvalue, int expected) {
76 assert_se(config_parse_int("unit", "filename", 1, "section", 1, "lvalue", 0, rvalue, &v, NULL) >= 0);
77 assert_se(expected == v);
80 static void test_config_parse_unsigned_one(const char *rvalue, unsigned expected) {
83 assert_se(config_parse_unsigned("unit", "filename", 1, "section", 1, "lvalue", 0, rvalue, &v, NULL) >= 0);
84 assert_se(expected == v);
87 static void test_config_parse_strv_one(const char *rvalue, char **expected) {
88 _cleanup_strv_free_ char **strv = NULL;
90 assert_se(config_parse_strv("unit", "filename", 1, "section", 1, "lvalue", 0, rvalue, &strv, NULL) >= 0);
91 assert_se(strv_equal(expected, strv));
94 static void test_config_parse_mode_one(const char *rvalue, mode_t expected) {
97 assert_se(config_parse_mode("unit", "filename", 1, "section", 1, "lvalue", 0, rvalue, &v, NULL) >= 0);
98 assert_se(expected == v);
101 static void test_config_parse_sec_one(const char *rvalue, usec_t expected) {
104 assert_se(config_parse_sec("unit", "filename", 1, "section", 1, "lvalue", 0, rvalue, &v, NULL) >= 0);
105 assert_se(expected == v);
108 #if 0 /// UNNEEDED by elogind
109 static void test_config_parse_nsec_one(const char *rvalue, nsec_t expected) {
112 assert_se(config_parse_nsec("unit", "filename", 1, "nsection", 1, "lvalue", 0, rvalue, &v, NULL) >= 0);
113 assert_se(expected == v);
117 static void test_config_parse_path(void) {
118 test_config_parse_path_one("/path", "/path");
119 test_config_parse_path_one("/path//////////", "/path");
120 test_config_parse_path_one("///path/foo///bar////bar//", "/path/foo/bar/bar");
121 test_config_parse_path_one("/path/\xc3\x80", "/path/\xc3\x80");
123 test_config_parse_path_one("not_absolute/path", NULL);
124 test_config_parse_path_one("/path/\xc3\x7f", NULL);
127 static void test_config_parse_log_level(void) {
128 test_config_parse_log_level_one("debug", LOG_DEBUG);
129 test_config_parse_log_level_one("info", LOG_INFO);
131 test_config_parse_log_level_one("garbage", 0);
134 #if 0 /// UNNEEDED by elogind
135 static void test_config_parse_log_facility(void) {
136 test_config_parse_log_facility_one("mail", LOG_MAIL);
137 test_config_parse_log_facility_one("user", LOG_USER);
139 test_config_parse_log_facility_one("garbage", 0);
143 static void test_config_parse_iec_size(void) {
144 test_config_parse_iec_size_one("1024", 1024);
145 test_config_parse_iec_size_one("2K", 2048);
146 test_config_parse_iec_size_one("10M", 10 * 1024 * 1024);
147 test_config_parse_iec_size_one("1G", 1 * 1024 * 1024 * 1024);
148 test_config_parse_iec_size_one("0G", 0);
149 test_config_parse_iec_size_one("0", 0);
151 test_config_parse_iec_size_one("-982", 0);
152 test_config_parse_iec_size_one("49874444198739873000000G", 0);
153 test_config_parse_iec_size_one("garbage", 0);
156 #if 0 /// UNNEEDED by elogind
157 static void test_config_parse_si_size(void) {
158 test_config_parse_si_size_one("1024", 1024);
159 test_config_parse_si_size_one("2K", 2000);
160 test_config_parse_si_size_one("10M", 10 * 1000 * 1000);
161 test_config_parse_si_size_one("1G", 1 * 1000 * 1000 * 1000);
162 test_config_parse_si_size_one("0G", 0);
163 test_config_parse_si_size_one("0", 0);
165 test_config_parse_si_size_one("-982", 0);
166 test_config_parse_si_size_one("49874444198739873000000G", 0);
167 test_config_parse_si_size_one("garbage", 0);
171 static void test_config_parse_int(void) {
172 test_config_parse_int_one("1024", 1024);
173 test_config_parse_int_one("-1024", -1024);
174 test_config_parse_int_one("0", 0);
176 test_config_parse_int_one("99999999999999999999999999999999999999999999999999999999", -1);
177 test_config_parse_int_one("-99999999999999999999999999999999999999999999999999999999", -1);
178 test_config_parse_int_one("1G", -1);
179 test_config_parse_int_one("garbage", -1);
182 static void test_config_parse_unsigned(void) {
183 test_config_parse_unsigned_one("10241024", 10241024);
184 test_config_parse_unsigned_one("1024", 1024);
185 test_config_parse_unsigned_one("0", 0);
187 test_config_parse_unsigned_one("99999999999999999999999999999999999999999999999999999999", 0);
188 test_config_parse_unsigned_one("1G", 0);
189 test_config_parse_unsigned_one("garbage", 0);
190 test_config_parse_unsigned_one("1000garbage", 0);
193 static void test_config_parse_strv(void) {
194 test_config_parse_strv_one("", STRV_MAKE_EMPTY);
195 test_config_parse_strv_one("foo", STRV_MAKE("foo"));
196 test_config_parse_strv_one("foo bar foo", STRV_MAKE("foo", "bar", "foo"));
197 test_config_parse_strv_one("\"foo bar\" foo", STRV_MAKE("foo bar", "foo"));
198 test_config_parse_strv_one("\xc3\x80", STRV_MAKE("\xc3\x80"));
199 test_config_parse_strv_one("\xc3\x7f", STRV_MAKE_EMPTY);
202 static void test_config_parse_mode(void) {
203 test_config_parse_mode_one("777", 0777);
204 test_config_parse_mode_one("644", 0644);
206 test_config_parse_mode_one("-777", 0);
207 test_config_parse_mode_one("999", 0);
208 test_config_parse_mode_one("garbage", 0);
209 test_config_parse_mode_one("777garbage", 0);
210 test_config_parse_mode_one("777 garbage", 0);
213 static void test_config_parse_sec(void) {
214 test_config_parse_sec_one("1", 1 * USEC_PER_SEC);
215 test_config_parse_sec_one("1s", 1 * USEC_PER_SEC);
216 test_config_parse_sec_one("100ms", 100 * USEC_PER_MSEC);
217 test_config_parse_sec_one("5min 20s", 5 * 60 * USEC_PER_SEC + 20 * USEC_PER_SEC);
219 test_config_parse_sec_one("-1", 0);
220 test_config_parse_sec_one("10foo", 0);
221 test_config_parse_sec_one("garbage", 0);
224 #if 0 /// UNNEEDED by elogind
225 static void test_config_parse_nsec(void) {
226 test_config_parse_nsec_one("1", 1);
227 test_config_parse_nsec_one("1s", 1 * NSEC_PER_SEC);
228 test_config_parse_nsec_one("100ms", 100 * NSEC_PER_MSEC);
229 test_config_parse_nsec_one("5min 20s", 5 * 60 * NSEC_PER_SEC + 20 * NSEC_PER_SEC);
231 test_config_parse_nsec_one("-1", 0);
232 test_config_parse_nsec_one("10foo", 0);
233 test_config_parse_nsec_one("garbage", 0);
236 static void test_config_parse_iec_uint64(void) {
238 assert_se(config_parse_iec_uint64(NULL, "/this/file", 11, "Section", 22, "Size", 0, "4M", &offset, NULL) == 0);
239 assert_se(offset == 4 * 1024 * 1024);
241 assert_se(config_parse_iec_uint64(NULL, "/this/file", 11, "Section", 22, "Size", 0, "4.5M", &offset, NULL) == 0);
244 static void test_config_parse_join_controllers(void) {
246 _cleanup_(strv_free_freep) char ***c = NULL;
249 /* Test normal operation */
250 r = config_parse_join_controllers(NULL, "example.conf", 11, "Section", 10, "JoinControllers", 0, "cpu,cpuacct net_cls,netprio", &c, NULL);
253 assert_se(strv_length(c[0]) == 2);
254 assert_se(strv_equal(c[0], STRV_MAKE("cpu", "cpuacct")));
255 assert_se(strv_length(c[1]) == 2);
256 assert_se(strv_equal(c[1], STRV_MAKE("net_cls", "netprio")));
257 assert_se(c[2] == NULL);
259 /* Test special case of no mounted controllers */
260 r = config_parse_join_controllers(NULL, "example.conf", 12, "Section", 10, "JoinControllers", 0, "", &c, NULL);
263 assert_se(strv_equal(c[0], STRV_MAKE_EMPTY));
264 assert_se(c[1] == NULL);
266 /* Test merging of overlapping lists */
267 r = config_parse_join_controllers(NULL, "example.conf", 13, "Section", 10, "JoinControllers", 0, "a,b b,c", &c, NULL);
270 assert_se(strv_length(c[0]) == 3);
271 assert_se(strv_contains(c[0], "a"));
272 assert_se(strv_contains(c[0], "b"));
273 assert_se(strv_contains(c[0], "c"));
274 assert_se(c[1] == NULL);
276 /* Test ignoring of bad lines */
278 r = config_parse_join_controllers(NULL, "example.conf", 14, "Section", 10, "JoinControllers", 0, "a,\"b ", &c, NULL);
284 #define x10(x) x x x x x x x x x x
285 #define x100(x) x10(x10(x))
286 #define x1000(x) x10(x100(x))
288 static const char* const config_file[] = {
293 "setting1=1", /* no terminating newline */
295 "\n\n\n\n[Section]\n\n\n"
296 "setting1=1", /* some whitespace, no terminating newline */
302 "setting1=1\n", /* repeated settings */
305 "setting1=1\\\n" /* normal continuation */
310 "setting1=1\\\\\\\n" /* continuation with trailing escape symbols */
311 "\\\\2\n", /* note that C requires one level of escaping, so the
312 * parser gets "…1 BS BS BS NL BS BS 2 NL", which
313 * it translates into "…1 BS BS SP BS BS 2" */
316 "setting1=" /* a line above LINE_MAX length */
321 "setting1=" /* a line above LINE_MAX length, with continuation */
326 "setting1=" /* a line above the allowed limit: 9 + 1050000 + 1 */
327 x1000(x1000("x") x10("abcde")) "\n",
330 "setting1=" /* many continuation lines, together above the limit */
331 x1000(x1000("x") x10("abcde") "\\\n") "xxx",
334 static void test_config_parse(unsigned i, const char *s) {
335 char name[] = "/tmp/test-conf-parser.XXXXXX";
337 _cleanup_fclose_ FILE *f = NULL;
338 _cleanup_free_ char *setting1 = NULL;
340 const ConfigTableItem items[] = {
341 { "Section", "setting1", config_parse_string, 0, &setting1},
345 log_info("== %s[%i] ==", __func__, i);
347 fd = mkostemp_safe(name);
349 assert_se((size_t) write(fd, s, strlen(s)) == strlen(s));
351 assert_se(lseek(fd, 0, SEEK_SET) == 0);
352 assert_se(f = fdopen(fd, "r"));
355 int config_parse(const char *unit,
356 const char *filename,
358 const char *sections,
359 ConfigItemLookup lookup,
367 r = config_parse(NULL, name, f,
369 config_item_table_lookup, items,
370 CONFIG_PARSE_WARN, NULL);
375 assert_se(streq(setting1, "1"));
380 assert_se(streq(setting1, "1 2 3"));
385 assert_se(streq(setting1, "1\\\\ \\\\2"));
390 assert_se(streq(setting1, x1000("ABCD")));
395 assert_se(streq(setting1, x1000("ABCD") " foobar"));
399 assert_se(r == -ENOBUFS);
400 assert_se(setting1 == NULL);
405 int main(int argc, char **argv) {
408 log_parse_environment();
411 test_config_parse_path();
412 test_config_parse_log_level();
413 #if 0 /// UNNEEDED by elogind
414 test_config_parse_log_facility();
416 test_config_parse_iec_size();
417 #if 0 /// UNNEEDED by elogind
418 test_config_parse_si_size();
420 test_config_parse_int();
421 test_config_parse_unsigned();
422 test_config_parse_strv();
423 test_config_parse_mode();
424 test_config_parse_sec();
425 #if 0 /// UNNEEDED by elogind
426 test_config_parse_nsec();
427 test_config_parse_iec_uint64();
428 test_config_parse_join_controllers();
431 for (i = 0; i < ELEMENTSOF(config_file); i++)
432 test_config_parse(i, config_file[i]);