1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2012 Lennart Poettering
7 Copyright 2013 Zbigniew Jędrzejewski-Szmek
9 systemd is free software; you can redistribute it and/or modify it
10 under the terms of the GNU Lesser General Public License as published by
11 the Free Software Foundation; either version 2.1 of the License, or
12 (at your option) any later version.
14 systemd is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Lesser General Public License for more details.
19 You should have received a copy of the GNU Lesser General Public License
20 along with systemd; If not, see <http://www.gnu.org/licenses/>.
31 #include "install-printf.h"
32 #include "specifier.h"
36 #include "load-fragment.h"
39 #include "test-helper.h"
41 static int test_unit_file_get_set(void) {
47 h = hashmap_new(&string_hash_ops);
50 r = unit_file_get_list(UNIT_FILE_SYSTEM, NULL, h);
52 if (r == -EPERM || r == -EACCES) {
53 printf("Skipping test: unit_file_get_list: %s", strerror(-r));
54 return EXIT_TEST_SKIP;
57 log_full(r == 0 ? LOG_INFO : LOG_ERR,
58 "unit_file_get_list: %s", strerror(-r));
62 HASHMAP_FOREACH(p, h, i)
63 printf("%s = %s\n", p->path, unit_file_state_to_string(p->state));
65 unit_file_list_free(h);
70 static void check_execcommand(ExecCommand *c,
77 log_info("expect: \"%s\" [\"%s\" \"%s\" \"%s\"]",
78 path, argv0 ?: path, argv1, argv2);
79 log_info("actual: \"%s\" [\"%s\" \"%s\" \"%s\"]",
80 c->path, c->argv[0], c->argv[1], c->argv[2]);
81 assert_se(streq(c->path, path));
82 assert_se(streq(c->argv[0], argv0 ?: path));
83 assert_se(streq_ptr(c->argv[1], argv1));
84 assert_se(streq_ptr(c->argv[2], argv2));
85 assert_se(c->ignore == ignore);
88 static void test_config_parse_exec(void) {
89 /* int config_parse_exec(
93 unsigned section_line,
101 ExecCommand *c = NULL, *c1;
104 log_info("/* basic test */");
105 r = config_parse_exec(NULL, "fake", 1, "section", 1,
106 "LValue", 0, "/RValue r1",
109 check_execcommand(c, "/RValue", "/RValue", "r1", NULL, false);
111 r = config_parse_exec(NULL, "fake", 2, "section", 1,
112 "LValue", 0, "/RValue///slashes r1///",
115 log_info("/* test slashes */");
117 c1 = c->command_next;
118 check_execcommand(c1, "/RValue/slashes", "/RValue///slashes", "r1///", NULL, false);
120 log_info("/* trailing slash */");
121 r = config_parse_exec(NULL, "fake", 4, "section", 1,
122 "LValue", 0, "/RValue/ argv0 r1",
125 assert_se(c1->command_next == NULL);
127 log_info("/* honour_argv0 */");
128 r = config_parse_exec(NULL, "fake", 3, "section", 1,
129 "LValue", 0, "@/RValue///slashes2 ///argv0 r1",
132 c1 = c1->command_next;
133 check_execcommand(c1, "/RValue/slashes2", "///argv0", "r1", NULL, false);
135 log_info("/* ignore && honour_argv0 */");
136 r = config_parse_exec(NULL, "fake", 4, "section", 1,
137 "LValue", 0, "-@/RValue///slashes3 argv0a r1",
140 c1 = c1->command_next;
141 check_execcommand(c1, "/RValue/slashes3", "argv0a", "r1", NULL, true);
143 log_info("/* ignore && honour_argv0 */");
144 r = config_parse_exec(NULL, "fake", 4, "section", 1,
145 "LValue", 0, "@-/RValue///slashes4 argv0b r1",
148 c1 = c1->command_next;
149 check_execcommand(c1, "/RValue/slashes4", "argv0b", "r1", NULL, true);
151 log_info("/* ignore && ignore */");
152 r = config_parse_exec(NULL, "fake", 4, "section", 1,
153 "LValue", 0, "--/RValue argv0 r1",
156 assert_se(c1->command_next == NULL);
158 log_info("/* ignore && ignore (2) */");
159 r = config_parse_exec(NULL, "fake", 4, "section", 1,
160 "LValue", 0, "-@-/RValue argv0 r1",
163 assert_se(c1->command_next == NULL);
165 log_info("/* semicolon */");
166 r = config_parse_exec(NULL, "fake", 5, "section", 1,
168 "-@/RValue argv0 r1 ; "
172 c1 = c1->command_next;
173 check_execcommand(c1, "/RValue", "argv0", "r1", NULL, true);
175 c1 = c1->command_next;
176 check_execcommand(c1, "/goo/goo", NULL, "boo", NULL, false);
178 log_info("/* trailing semicolon */");
179 r = config_parse_exec(NULL, "fake", 5, "section", 1,
181 "-@/RValue argv0 r1 ; ",
184 c1 = c1->command_next;
185 check_execcommand(c1, "/RValue", "argv0", "r1", NULL, true);
187 assert_se(c1->command_next == NULL);
189 log_info("/* escaped semicolon */");
190 r = config_parse_exec(NULL, "fake", 5, "section", 1,
195 c1 = c1->command_next;
196 check_execcommand(c1, "/bin/find", NULL, ";", NULL, false);
198 log_info("/* escaped semicolon with following arg */");
199 r = config_parse_exec(NULL, "fake", 5, "section", 1,
204 c1 = c1->command_next;
205 check_execcommand(c1,
206 "/sbin/find", NULL, ";", "x", false);
208 log_info("/* spaces in the filename */");
209 r = config_parse_exec(NULL, "fake", 5, "section", 1,
211 "\"/PATH WITH SPACES/daemon\" -1 -2",
214 c1 = c1->command_next;
215 check_execcommand(c1,
216 "/PATH WITH SPACES/daemon", NULL, "-1", "-2", false);
218 log_info("/* spaces in the filename, no args */");
219 r = config_parse_exec(NULL, "fake", 5, "section", 1,
221 "\"/PATH WITH SPACES/daemon -1 -2\"",
224 c1 = c1->command_next;
225 check_execcommand(c1,
226 "/PATH WITH SPACES/daemon -1 -2", NULL, NULL, NULL, false);
228 log_info("/* spaces in the filename, everything quoted */");
229 r = config_parse_exec(NULL, "fake", 5, "section", 1,
231 "\"/PATH WITH SPACES/daemon\" \"-1\" '-2'",
234 c1 = c1->command_next;
235 check_execcommand(c1,
236 "/PATH WITH SPACES/daemon", NULL, "-1", "-2", false);
238 log_info("/* escaped spaces in the filename */");
239 r = config_parse_exec(NULL, "fake", 5, "section", 1,
241 "\"/PATH\\sWITH\\sSPACES/daemon\" '-1 -2'",
244 c1 = c1->command_next;
245 check_execcommand(c1,
246 "/PATH WITH SPACES/daemon", NULL, "-1 -2", NULL, false);
248 log_info("/* escaped spaces in the filename (2) */");
249 r = config_parse_exec(NULL, "fake", 5, "section", 1,
251 "\"/PATH\\x20WITH\\x20SPACES/daemon\" \"-1 -2\"",
254 c1 = c1->command_next;
255 check_execcommand(c1,
256 "/PATH WITH SPACES/daemon", NULL, "-1 -2", NULL, false);
258 for (ccc = "abfnrtv\\\'\"x"; *ccc; ccc++) {
259 /* \\x is an incomplete hexadecimal sequence, invalid because of the slash */
260 char path[] = "/path\\X";
261 path[sizeof(path) - 2] = *ccc;
263 log_info("/* invalid character: \\%c */", *ccc);
264 r = config_parse_exec(NULL, "fake", 4, "section", 1,
268 assert_se(c1->command_next == NULL);
271 log_info("/* valid character: \\s */");
272 r = config_parse_exec(NULL, "fake", 4, "section", 1,
273 "LValue", 0, "/path\\s",
276 c1 = c1->command_next;
277 check_execcommand(c1, "/path ", NULL, NULL, NULL, false);
279 log_info("/* trailing backslash: \\ */");
280 /* backslash is invalid */
281 r = config_parse_exec(NULL, "fake", 4, "section", 1,
282 "LValue", 0, "/path\\",
285 assert_se(c1->command_next == NULL);
287 exec_command_free_list(c);
305 "#SPAMD_ARGS=\"-d --socketpath=/var/lib/bulwark/spamd \\\n" \
306 "#--nouser-config \\\n" \
312 "HWMON_MODULES=\"coretemp f71882fg\"\n" \
314 "# For compatibility reasons\n" \
316 "MODULE_0=coretemp\n" \
323 static void test_load_env_file_1(void) {
324 _cleanup_strv_free_ char **data = NULL;
327 char name[] = "/tmp/test-load-env-file.XXXXXX";
328 _cleanup_close_ int fd;
330 fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC);
332 assert_se(write(fd, env_file_1, sizeof(env_file_1)) == sizeof(env_file_1));
334 r = load_env_file(NULL, name, NULL, &data);
336 assert_se(streq(data[0], "a=a"));
337 assert_se(streq(data[1], "b=bc"));
338 assert_se(streq(data[2], "d=def"));
339 assert_se(streq(data[3], "g=g "));
340 assert_se(streq(data[4], "h=h"));
341 assert_se(streq(data[5], "i=i"));
342 assert_se(data[6] == NULL);
346 static void test_load_env_file_2(void) {
347 _cleanup_strv_free_ char **data = NULL;
350 char name[] = "/tmp/test-load-env-file.XXXXXX";
351 _cleanup_close_ int fd;
353 fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC);
355 assert_se(write(fd, env_file_2, sizeof(env_file_2)) == sizeof(env_file_2));
357 r = load_env_file(NULL, name, NULL, &data);
359 assert_se(streq(data[0], "a=a"));
360 assert_se(data[1] == NULL);
364 static void test_load_env_file_3(void) {
365 _cleanup_strv_free_ char **data = NULL;
368 char name[] = "/tmp/test-load-env-file.XXXXXX";
369 _cleanup_close_ int fd;
371 fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC);
373 assert_se(write(fd, env_file_3, sizeof(env_file_3)) == sizeof(env_file_3));
375 r = load_env_file(NULL, name, NULL, &data);
377 assert_se(data == NULL);
381 static void test_load_env_file_4(void) {
382 _cleanup_strv_free_ char **data = NULL;
383 char name[] = "/tmp/test-load-env-file.XXXXXX";
384 _cleanup_close_ int fd;
387 fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC);
389 assert_se(write(fd, env_file_4, sizeof(env_file_4)) == sizeof(env_file_4));
391 r = load_env_file(NULL, name, NULL, &data);
393 assert_se(streq(data[0], "HWMON_MODULES=coretemp f71882fg"));
394 assert_se(streq(data[1], "MODULE_0=coretemp"));
395 assert_se(streq(data[2], "MODULE_1=f71882fg"));
396 assert_se(data[3] == NULL);
400 static void test_load_env_file_5(void) {
401 _cleanup_strv_free_ char **data = NULL;
404 char name[] = "/tmp/test-load-env-file.XXXXXX";
405 _cleanup_close_ int fd;
407 fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC);
409 assert_se(write(fd, env_file_5, sizeof(env_file_5)) == sizeof(env_file_5));
411 r = load_env_file(NULL, name, NULL, &data);
413 assert_se(streq(data[0], "a="));
414 assert_se(streq(data[1], "b="));
415 assert_se(data[2] == NULL);
419 static void test_install_printf(void) {
420 char name[] = "name.service",
421 path[] = "/run/systemd/system/name.service",
422 user[] = "xxxx-no-such-user";
423 InstallInfo i = {name, path, user};
424 InstallInfo i2 = {name, path, NULL};
425 char name3[] = "name@inst.service",
426 path3[] = "/run/systemd/system/name.service";
427 InstallInfo i3 = {name3, path3, user};
428 InstallInfo i4 = {name3, path3, NULL};
430 _cleanup_free_ char *mid, *bid, *host;
432 assert_se(specifier_machine_id('m', NULL, NULL, &mid) >= 0 && mid);
433 assert_se(specifier_boot_id('b', NULL, NULL, &bid) >= 0 && bid);
434 assert_se((host = gethostname_malloc()));
436 #define expect(src, pattern, result) \
438 _cleanup_free_ char *t = NULL; \
439 _cleanup_free_ char \
440 *d1 = strdup(i.name), \
441 *d2 = strdup(i.path), \
442 *d3 = strdup(i.user); \
443 assert_se(install_full_printf(&src, pattern, &t) >= 0 || !result); \
444 memzero(i.name, strlen(i.name)); \
445 memzero(i.path, strlen(i.path)); \
446 memzero(i.user, strlen(i.user)); \
447 assert_se(d1 && d2 && d3); \
450 assert_se(streq(t, result)); \
451 } else assert_se(t == NULL); \
452 strcpy(i.name, d1); \
453 strcpy(i.path, d2); \
454 strcpy(i.user, d3); \
457 assert_se(setenv("USER", "root", 1) == 0);
459 expect(i, "%n", "name.service");
460 expect(i, "%N", "name");
461 expect(i, "%p", "name");
463 expect(i, "%u", "xxxx-no-such-user");
465 DISABLE_WARNING_NONNULL;
466 expect(i, "%U", NULL);
469 expect(i, "%m", mid);
470 expect(i, "%b", bid);
471 expect(i, "%H", host);
473 expect(i2, "%u", "root");
474 expect(i2, "%U", "0");
476 expect(i3, "%n", "name@inst.service");
477 expect(i3, "%N", "name@inst");
478 expect(i3, "%p", "name");
479 expect(i3, "%u", "xxxx-no-such-user");
481 DISABLE_WARNING_NONNULL;
482 expect(i3, "%U", NULL);
485 expect(i3, "%m", mid);
486 expect(i3, "%b", bid);
487 expect(i3, "%H", host);
489 expect(i4, "%u", "root");
490 expect(i4, "%U", "0");
493 int main(int argc, char *argv[]) {
496 log_parse_environment();
499 r = test_unit_file_get_set();
500 test_config_parse_exec();
501 test_load_env_file_1();
502 test_load_env_file_2();
503 test_load_env_file_3();
504 test_load_env_file_4();
505 test_load_env_file_5();
506 TEST_REQ_RUNNING_SYSTEMD(test_install_printf());