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/>.
30 #include "install-printf.h"
31 #include "specifier.h"
35 #include "load-fragment.h"
38 #include "test-helper.h"
40 static int test_unit_file_get_set(void) {
46 h = hashmap_new(&string_hash_ops);
49 r = unit_file_get_list(UNIT_FILE_SYSTEM, NULL, h);
51 if (r == -EPERM || r == -EACCES) {
52 printf("Skipping test: unit_file_get_list: %s", strerror(-r));
53 return EXIT_TEST_SKIP;
56 log_full(r == 0 ? LOG_INFO : LOG_ERR,
57 "unit_file_get_list: %s", strerror(-r));
61 HASHMAP_FOREACH(p, h, i)
62 printf("%s = %s\n", p->path, unit_file_state_to_string(p->state));
64 unit_file_list_free(h);
69 static void check_execcommand(ExecCommand *c,
78 log_info("expect: \"%s\" [\"%s\" \"%s\" \"%s\"]",
79 path, argv0 ?: path, argv1, argv2);
80 n = strv_length(c->argv);
81 log_info("actual: \"%s\" [\"%s\" \"%s\" \"%s\"]",
82 c->path, c->argv[0], n > 0 ? c->argv[1] : NULL, n > 1 ? c->argv[2] : NULL);
83 assert_se(streq(c->path, path));
84 assert_se(streq(c->argv[0], argv0 ?: path));
86 assert_se(streq_ptr(c->argv[1], argv1));
88 assert_se(streq_ptr(c->argv[2], argv2));
89 assert_se(c->ignore == ignore);
92 static void test_config_parse_exec(void) {
93 /* int config_parse_exec(
97 unsigned section_line,
105 ExecCommand *c = NULL, *c1;
108 log_info("/* basic test */");
109 r = config_parse_exec(NULL, "fake", 1, "section", 1,
110 "LValue", 0, "/RValue r1",
113 check_execcommand(c, "/RValue", "/RValue", "r1", NULL, false);
115 r = config_parse_exec(NULL, "fake", 2, "section", 1,
116 "LValue", 0, "/RValue///slashes r1///",
119 log_info("/* test slashes */");
121 c1 = c->command_next;
122 check_execcommand(c1, "/RValue/slashes", "/RValue///slashes", "r1///", NULL, false);
124 log_info("/* trailing slash */");
125 r = config_parse_exec(NULL, "fake", 4, "section", 1,
126 "LValue", 0, "/RValue/ argv0 r1",
129 assert_se(c1->command_next == NULL);
131 log_info("/* honour_argv0 */");
132 r = config_parse_exec(NULL, "fake", 3, "section", 1,
133 "LValue", 0, "@/RValue///slashes2 ///argv0 r1",
136 c1 = c1->command_next;
137 check_execcommand(c1, "/RValue/slashes2", "///argv0", "r1", NULL, false);
139 log_info("/* honour_argv0, no args */");
140 r = config_parse_exec(NULL, "fake", 3, "section", 1,
141 "LValue", 0, "@/RValue",
144 assert_se(c1->command_next == NULL);
146 log_info("/* no command, check for bad memory access */");
147 r = config_parse_exec(NULL, "fake", 3, "section", 1,
151 assert_se(c1->command_next == NULL);
153 log_info("/* ignore && honour_argv0 */");
154 r = config_parse_exec(NULL, "fake", 4, "section", 1,
155 "LValue", 0, "-@/RValue///slashes3 argv0a r1",
158 c1 = c1->command_next;
159 check_execcommand(c1, "/RValue/slashes3", "argv0a", "r1", NULL, true);
161 log_info("/* ignore && honour_argv0 */");
162 r = config_parse_exec(NULL, "fake", 4, "section", 1,
163 "LValue", 0, "@-/RValue///slashes4 argv0b r1",
166 c1 = c1->command_next;
167 check_execcommand(c1, "/RValue/slashes4", "argv0b", "r1", NULL, true);
169 log_info("/* ignore && ignore */");
170 r = config_parse_exec(NULL, "fake", 4, "section", 1,
171 "LValue", 0, "--/RValue argv0 r1",
174 assert_se(c1->command_next == NULL);
176 log_info("/* ignore && ignore (2) */");
177 r = config_parse_exec(NULL, "fake", 4, "section", 1,
178 "LValue", 0, "-@-/RValue argv0 r1",
181 assert_se(c1->command_next == NULL);
183 log_info("/* semicolon */");
184 r = config_parse_exec(NULL, "fake", 5, "section", 1,
186 "-@/RValue argv0 r1 ; "
190 c1 = c1->command_next;
191 check_execcommand(c1, "/RValue", "argv0", "r1", NULL, true);
193 c1 = c1->command_next;
194 check_execcommand(c1, "/goo/goo", NULL, "boo", NULL, false);
196 log_info("/* trailing semicolon */");
197 r = config_parse_exec(NULL, "fake", 5, "section", 1,
199 "-@/RValue argv0 r1 ; ",
202 c1 = c1->command_next;
203 check_execcommand(c1, "/RValue", "argv0", "r1", NULL, true);
205 assert_se(c1->command_next == NULL);
207 log_info("/* escaped semicolon */");
208 r = config_parse_exec(NULL, "fake", 5, "section", 1,
213 c1 = c1->command_next;
214 check_execcommand(c1, "/bin/find", NULL, ";", NULL, false);
216 log_info("/* escaped semicolon with following arg */");
217 r = config_parse_exec(NULL, "fake", 5, "section", 1,
222 c1 = c1->command_next;
223 check_execcommand(c1,
224 "/sbin/find", NULL, ";", "x", false);
226 log_info("/* spaces in the filename */");
227 r = config_parse_exec(NULL, "fake", 5, "section", 1,
229 "\"/PATH WITH SPACES/daemon\" -1 -2",
232 c1 = c1->command_next;
233 check_execcommand(c1,
234 "/PATH WITH SPACES/daemon", NULL, "-1", "-2", false);
236 log_info("/* spaces in the filename, no args */");
237 r = config_parse_exec(NULL, "fake", 5, "section", 1,
239 "\"/PATH WITH SPACES/daemon -1 -2\"",
242 c1 = c1->command_next;
243 check_execcommand(c1,
244 "/PATH WITH SPACES/daemon -1 -2", NULL, NULL, NULL, false);
246 log_info("/* spaces in the filename, everything quoted */");
247 r = config_parse_exec(NULL, "fake", 5, "section", 1,
249 "\"/PATH WITH SPACES/daemon\" \"-1\" '-2'",
252 c1 = c1->command_next;
253 check_execcommand(c1,
254 "/PATH WITH SPACES/daemon", NULL, "-1", "-2", false);
256 log_info("/* escaped spaces in the filename */");
257 r = config_parse_exec(NULL, "fake", 5, "section", 1,
259 "\"/PATH\\sWITH\\sSPACES/daemon\" '-1 -2'",
262 c1 = c1->command_next;
263 check_execcommand(c1,
264 "/PATH WITH SPACES/daemon", NULL, "-1 -2", NULL, false);
266 log_info("/* escaped spaces in the filename (2) */");
267 r = config_parse_exec(NULL, "fake", 5, "section", 1,
269 "\"/PATH\\x20WITH\\x20SPACES/daemon\" \"-1 -2\"",
272 c1 = c1->command_next;
273 check_execcommand(c1,
274 "/PATH WITH SPACES/daemon", NULL, "-1 -2", NULL, false);
276 for (ccc = "abfnrtv\\\'\"x"; *ccc; ccc++) {
277 /* \\x is an incomplete hexadecimal sequence, invalid because of the slash */
278 char path[] = "/path\\X";
279 path[sizeof(path) - 2] = *ccc;
281 log_info("/* invalid character: \\%c */", *ccc);
282 r = config_parse_exec(NULL, "fake", 4, "section", 1,
286 assert_se(c1->command_next == NULL);
289 log_info("/* valid character: \\s */");
290 r = config_parse_exec(NULL, "fake", 4, "section", 1,
291 "LValue", 0, "/path\\s",
294 c1 = c1->command_next;
295 check_execcommand(c1, "/path ", NULL, NULL, NULL, false);
297 log_info("/* trailing backslash: \\ */");
298 /* backslash is invalid */
299 r = config_parse_exec(NULL, "fake", 4, "section", 1,
300 "LValue", 0, "/path\\",
303 assert_se(c1->command_next == NULL);
305 exec_command_free_list(c);
323 "#SPAMD_ARGS=\"-d --socketpath=/var/lib/bulwark/spamd \\\n" \
324 "#--nouser-config \\\n" \
330 "HWMON_MODULES=\"coretemp f71882fg\"\n" \
332 "# For compatibility reasons\n" \
334 "MODULE_0=coretemp\n" \
341 static void test_load_env_file_1(void) {
342 _cleanup_strv_free_ char **data = NULL;
345 char name[] = "/tmp/test-load-env-file.XXXXXX";
346 _cleanup_close_ int fd;
348 fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC);
350 assert_se(write(fd, env_file_1, sizeof(env_file_1)) == sizeof(env_file_1));
352 r = load_env_file(NULL, name, NULL, &data);
354 assert_se(streq(data[0], "a=a"));
355 assert_se(streq(data[1], "b=bc"));
356 assert_se(streq(data[2], "d=def"));
357 assert_se(streq(data[3], "g=g "));
358 assert_se(streq(data[4], "h=h"));
359 assert_se(streq(data[5], "i=i"));
360 assert_se(data[6] == NULL);
364 static void test_load_env_file_2(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_2, sizeof(env_file_2)) == sizeof(env_file_2));
375 r = load_env_file(NULL, name, NULL, &data);
377 assert_se(streq(data[0], "a=a"));
378 assert_se(data[1] == NULL);
382 static void test_load_env_file_3(void) {
383 _cleanup_strv_free_ char **data = NULL;
386 char name[] = "/tmp/test-load-env-file.XXXXXX";
387 _cleanup_close_ int fd;
389 fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC);
391 assert_se(write(fd, env_file_3, sizeof(env_file_3)) == sizeof(env_file_3));
393 r = load_env_file(NULL, name, NULL, &data);
395 assert_se(data == NULL);
399 static void test_load_env_file_4(void) {
400 _cleanup_strv_free_ char **data = NULL;
401 char name[] = "/tmp/test-load-env-file.XXXXXX";
402 _cleanup_close_ int fd;
405 fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC);
407 assert_se(write(fd, env_file_4, sizeof(env_file_4)) == sizeof(env_file_4));
409 r = load_env_file(NULL, name, NULL, &data);
411 assert_se(streq(data[0], "HWMON_MODULES=coretemp f71882fg"));
412 assert_se(streq(data[1], "MODULE_0=coretemp"));
413 assert_se(streq(data[2], "MODULE_1=f71882fg"));
414 assert_se(data[3] == NULL);
418 static void test_load_env_file_5(void) {
419 _cleanup_strv_free_ char **data = NULL;
422 char name[] = "/tmp/test-load-env-file.XXXXXX";
423 _cleanup_close_ int fd;
425 fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC);
427 assert_se(write(fd, env_file_5, sizeof(env_file_5)) == sizeof(env_file_5));
429 r = load_env_file(NULL, name, NULL, &data);
431 assert_se(streq(data[0], "a="));
432 assert_se(streq(data[1], "b="));
433 assert_se(data[2] == NULL);
437 static void test_install_printf(void) {
438 char name[] = "name.service",
439 path[] = "/run/systemd/system/name.service",
440 user[] = "xxxx-no-such-user";
441 InstallInfo i = {name, path, user};
442 InstallInfo i2 = {name, path, NULL};
443 char name3[] = "name@inst.service",
444 path3[] = "/run/systemd/system/name.service";
445 InstallInfo i3 = {name3, path3, user};
446 InstallInfo i4 = {name3, path3, NULL};
448 _cleanup_free_ char *mid, *bid, *host;
450 assert_se(specifier_machine_id('m', NULL, NULL, &mid) >= 0 && mid);
451 assert_se(specifier_boot_id('b', NULL, NULL, &bid) >= 0 && bid);
452 assert_se((host = gethostname_malloc()));
454 #define expect(src, pattern, result) \
456 _cleanup_free_ char *t = NULL; \
457 _cleanup_free_ char \
458 *d1 = strdup(i.name), \
459 *d2 = strdup(i.path), \
460 *d3 = strdup(i.user); \
461 assert_se(install_full_printf(&src, pattern, &t) >= 0 || !result); \
462 memzero(i.name, strlen(i.name)); \
463 memzero(i.path, strlen(i.path)); \
464 memzero(i.user, strlen(i.user)); \
465 assert_se(d1 && d2 && d3); \
468 assert_se(streq(t, result)); \
469 } else assert_se(t == NULL); \
470 strcpy(i.name, d1); \
471 strcpy(i.path, d2); \
472 strcpy(i.user, d3); \
475 assert_se(setenv("USER", "root", 1) == 0);
477 expect(i, "%n", "name.service");
478 expect(i, "%N", "name");
479 expect(i, "%p", "name");
481 expect(i, "%u", "xxxx-no-such-user");
483 DISABLE_WARNING_NONNULL;
484 expect(i, "%U", NULL);
487 expect(i, "%m", mid);
488 expect(i, "%b", bid);
489 expect(i, "%H", host);
491 expect(i2, "%u", "root");
492 expect(i2, "%U", "0");
494 expect(i3, "%n", "name@inst.service");
495 expect(i3, "%N", "name@inst");
496 expect(i3, "%p", "name");
497 expect(i3, "%u", "xxxx-no-such-user");
499 DISABLE_WARNING_NONNULL;
500 expect(i3, "%U", NULL);
503 expect(i3, "%m", mid);
504 expect(i3, "%b", bid);
505 expect(i3, "%H", host);
507 expect(i4, "%u", "root");
508 expect(i4, "%U", "0");
511 int main(int argc, char *argv[]) {
514 log_parse_environment();
517 r = test_unit_file_get_set();
518 test_config_parse_exec();
519 test_load_env_file_1();
520 test_load_env_file_2();
521 test_load_env_file_3();
522 test_load_env_file_4();
523 test_load_env_file_5();
524 TEST_REQ_RUNNING_SYSTEMD(test_install_printf());