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,
79 log_info("expect: \"%s\" [\"%s\" \"%s\" \"%s\"]",
80 path, argv0 ?: path, argv1, argv2);
81 n = strv_length(c->argv);
82 log_info("actual: \"%s\" [\"%s\" \"%s\" \"%s\"]",
83 c->path, c->argv[0], n > 0 ? c->argv[1] : NULL, n > 1 ? c->argv[2] : NULL);
84 assert_se(streq(c->path, path));
85 assert_se(streq(c->argv[0], argv0 ?: path));
87 assert_se(streq_ptr(c->argv[1], argv1));
89 assert_se(streq_ptr(c->argv[2], argv2));
90 assert_se(c->ignore == ignore);
93 static void test_config_parse_exec(void) {
94 /* int config_parse_exec(
98 unsigned section_line,
106 ExecCommand *c = NULL, *c1;
109 log_info("/* basic test */");
110 r = config_parse_exec(NULL, "fake", 1, "section", 1,
111 "LValue", 0, "/RValue r1",
114 check_execcommand(c, "/RValue", "/RValue", "r1", NULL, false);
116 r = config_parse_exec(NULL, "fake", 2, "section", 1,
117 "LValue", 0, "/RValue///slashes r1///",
120 log_info("/* test slashes */");
122 c1 = c->command_next;
123 check_execcommand(c1, "/RValue/slashes", "/RValue///slashes", "r1///", NULL, false);
125 log_info("/* trailing slash */");
126 r = config_parse_exec(NULL, "fake", 4, "section", 1,
127 "LValue", 0, "/RValue/ argv0 r1",
130 assert_se(c1->command_next == NULL);
132 log_info("/* honour_argv0 */");
133 r = config_parse_exec(NULL, "fake", 3, "section", 1,
134 "LValue", 0, "@/RValue///slashes2 ///argv0 r1",
137 c1 = c1->command_next;
138 check_execcommand(c1, "/RValue/slashes2", "///argv0", "r1", NULL, false);
140 log_info("/* ignore && honour_argv0 */");
141 r = config_parse_exec(NULL, "fake", 4, "section", 1,
142 "LValue", 0, "-@/RValue///slashes3 argv0a r1",
145 c1 = c1->command_next;
146 check_execcommand(c1, "/RValue/slashes3", "argv0a", "r1", NULL, true);
148 log_info("/* ignore && honour_argv0 */");
149 r = config_parse_exec(NULL, "fake", 4, "section", 1,
150 "LValue", 0, "@-/RValue///slashes4 argv0b r1",
153 c1 = c1->command_next;
154 check_execcommand(c1, "/RValue/slashes4", "argv0b", "r1", NULL, true);
156 log_info("/* ignore && ignore */");
157 r = config_parse_exec(NULL, "fake", 4, "section", 1,
158 "LValue", 0, "--/RValue argv0 r1",
161 assert_se(c1->command_next == NULL);
163 log_info("/* ignore && ignore (2) */");
164 r = config_parse_exec(NULL, "fake", 4, "section", 1,
165 "LValue", 0, "-@-/RValue argv0 r1",
168 assert_se(c1->command_next == NULL);
170 log_info("/* semicolon */");
171 r = config_parse_exec(NULL, "fake", 5, "section", 1,
173 "-@/RValue argv0 r1 ; "
177 c1 = c1->command_next;
178 check_execcommand(c1, "/RValue", "argv0", "r1", NULL, true);
180 c1 = c1->command_next;
181 check_execcommand(c1, "/goo/goo", NULL, "boo", NULL, false);
183 log_info("/* trailing semicolon */");
184 r = config_parse_exec(NULL, "fake", 5, "section", 1,
186 "-@/RValue argv0 r1 ; ",
189 c1 = c1->command_next;
190 check_execcommand(c1, "/RValue", "argv0", "r1", NULL, true);
192 assert_se(c1->command_next == NULL);
194 log_info("/* escaped semicolon */");
195 r = config_parse_exec(NULL, "fake", 5, "section", 1,
200 c1 = c1->command_next;
201 check_execcommand(c1, "/bin/find", NULL, ";", NULL, false);
203 log_info("/* escaped semicolon with following arg */");
204 r = config_parse_exec(NULL, "fake", 5, "section", 1,
209 c1 = c1->command_next;
210 check_execcommand(c1,
211 "/sbin/find", NULL, ";", "x", false);
213 log_info("/* spaces in the filename */");
214 r = config_parse_exec(NULL, "fake", 5, "section", 1,
216 "\"/PATH WITH SPACES/daemon\" -1 -2",
219 c1 = c1->command_next;
220 check_execcommand(c1,
221 "/PATH WITH SPACES/daemon", NULL, "-1", "-2", false);
223 log_info("/* spaces in the filename, no args */");
224 r = config_parse_exec(NULL, "fake", 5, "section", 1,
226 "\"/PATH WITH SPACES/daemon -1 -2\"",
229 c1 = c1->command_next;
230 check_execcommand(c1,
231 "/PATH WITH SPACES/daemon -1 -2", NULL, NULL, NULL, false);
233 log_info("/* spaces in the filename, everything quoted */");
234 r = config_parse_exec(NULL, "fake", 5, "section", 1,
236 "\"/PATH WITH SPACES/daemon\" \"-1\" '-2'",
239 c1 = c1->command_next;
240 check_execcommand(c1,
241 "/PATH WITH SPACES/daemon", NULL, "-1", "-2", false);
243 log_info("/* escaped spaces in the filename */");
244 r = config_parse_exec(NULL, "fake", 5, "section", 1,
246 "\"/PATH\\sWITH\\sSPACES/daemon\" '-1 -2'",
249 c1 = c1->command_next;
250 check_execcommand(c1,
251 "/PATH WITH SPACES/daemon", NULL, "-1 -2", NULL, false);
253 log_info("/* escaped spaces in the filename (2) */");
254 r = config_parse_exec(NULL, "fake", 5, "section", 1,
256 "\"/PATH\\x20WITH\\x20SPACES/daemon\" \"-1 -2\"",
259 c1 = c1->command_next;
260 check_execcommand(c1,
261 "/PATH WITH SPACES/daemon", NULL, "-1 -2", NULL, false);
263 for (ccc = "abfnrtv\\\'\"x"; *ccc; ccc++) {
264 /* \\x is an incomplete hexadecimal sequence, invalid because of the slash */
265 char path[] = "/path\\X";
266 path[sizeof(path) - 2] = *ccc;
268 log_info("/* invalid character: \\%c */", *ccc);
269 r = config_parse_exec(NULL, "fake", 4, "section", 1,
273 assert_se(c1->command_next == NULL);
276 log_info("/* valid character: \\s */");
277 r = config_parse_exec(NULL, "fake", 4, "section", 1,
278 "LValue", 0, "/path\\s",
281 c1 = c1->command_next;
282 check_execcommand(c1, "/path ", NULL, NULL, NULL, false);
284 log_info("/* trailing backslash: \\ */");
285 /* backslash is invalid */
286 r = config_parse_exec(NULL, "fake", 4, "section", 1,
287 "LValue", 0, "/path\\",
290 assert_se(c1->command_next == NULL);
292 exec_command_free_list(c);
310 "#SPAMD_ARGS=\"-d --socketpath=/var/lib/bulwark/spamd \\\n" \
311 "#--nouser-config \\\n" \
317 "HWMON_MODULES=\"coretemp f71882fg\"\n" \
319 "# For compatibility reasons\n" \
321 "MODULE_0=coretemp\n" \
328 static void test_load_env_file_1(void) {
329 _cleanup_strv_free_ char **data = NULL;
332 char name[] = "/tmp/test-load-env-file.XXXXXX";
333 _cleanup_close_ int fd;
335 fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC);
337 assert_se(write(fd, env_file_1, sizeof(env_file_1)) == sizeof(env_file_1));
339 r = load_env_file(NULL, name, NULL, &data);
341 assert_se(streq(data[0], "a=a"));
342 assert_se(streq(data[1], "b=bc"));
343 assert_se(streq(data[2], "d=def"));
344 assert_se(streq(data[3], "g=g "));
345 assert_se(streq(data[4], "h=h"));
346 assert_se(streq(data[5], "i=i"));
347 assert_se(data[6] == NULL);
351 static void test_load_env_file_2(void) {
352 _cleanup_strv_free_ char **data = NULL;
355 char name[] = "/tmp/test-load-env-file.XXXXXX";
356 _cleanup_close_ int fd;
358 fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC);
360 assert_se(write(fd, env_file_2, sizeof(env_file_2)) == sizeof(env_file_2));
362 r = load_env_file(NULL, name, NULL, &data);
364 assert_se(streq(data[0], "a=a"));
365 assert_se(data[1] == NULL);
369 static void test_load_env_file_3(void) {
370 _cleanup_strv_free_ char **data = NULL;
373 char name[] = "/tmp/test-load-env-file.XXXXXX";
374 _cleanup_close_ int fd;
376 fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC);
378 assert_se(write(fd, env_file_3, sizeof(env_file_3)) == sizeof(env_file_3));
380 r = load_env_file(NULL, name, NULL, &data);
382 assert_se(data == NULL);
386 static void test_load_env_file_4(void) {
387 _cleanup_strv_free_ char **data = NULL;
388 char name[] = "/tmp/test-load-env-file.XXXXXX";
389 _cleanup_close_ int fd;
392 fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC);
394 assert_se(write(fd, env_file_4, sizeof(env_file_4)) == sizeof(env_file_4));
396 r = load_env_file(NULL, name, NULL, &data);
398 assert_se(streq(data[0], "HWMON_MODULES=coretemp f71882fg"));
399 assert_se(streq(data[1], "MODULE_0=coretemp"));
400 assert_se(streq(data[2], "MODULE_1=f71882fg"));
401 assert_se(data[3] == NULL);
405 static void test_load_env_file_5(void) {
406 _cleanup_strv_free_ char **data = NULL;
409 char name[] = "/tmp/test-load-env-file.XXXXXX";
410 _cleanup_close_ int fd;
412 fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC);
414 assert_se(write(fd, env_file_5, sizeof(env_file_5)) == sizeof(env_file_5));
416 r = load_env_file(NULL, name, NULL, &data);
418 assert_se(streq(data[0], "a="));
419 assert_se(streq(data[1], "b="));
420 assert_se(data[2] == NULL);
424 static void test_install_printf(void) {
425 char name[] = "name.service",
426 path[] = "/run/systemd/system/name.service",
427 user[] = "xxxx-no-such-user";
428 InstallInfo i = {name, path, user};
429 InstallInfo i2 = {name, path, NULL};
430 char name3[] = "name@inst.service",
431 path3[] = "/run/systemd/system/name.service";
432 InstallInfo i3 = {name3, path3, user};
433 InstallInfo i4 = {name3, path3, NULL};
435 _cleanup_free_ char *mid, *bid, *host;
437 assert_se(specifier_machine_id('m', NULL, NULL, &mid) >= 0 && mid);
438 assert_se(specifier_boot_id('b', NULL, NULL, &bid) >= 0 && bid);
439 assert_se((host = gethostname_malloc()));
441 #define expect(src, pattern, result) \
443 _cleanup_free_ char *t = NULL; \
444 _cleanup_free_ char \
445 *d1 = strdup(i.name), \
446 *d2 = strdup(i.path), \
447 *d3 = strdup(i.user); \
448 assert_se(install_full_printf(&src, pattern, &t) >= 0 || !result); \
449 memzero(i.name, strlen(i.name)); \
450 memzero(i.path, strlen(i.path)); \
451 memzero(i.user, strlen(i.user)); \
452 assert_se(d1 && d2 && d3); \
455 assert_se(streq(t, result)); \
456 } else assert_se(t == NULL); \
457 strcpy(i.name, d1); \
458 strcpy(i.path, d2); \
459 strcpy(i.user, d3); \
462 assert_se(setenv("USER", "root", 1) == 0);
464 expect(i, "%n", "name.service");
465 expect(i, "%N", "name");
466 expect(i, "%p", "name");
468 expect(i, "%u", "xxxx-no-such-user");
470 DISABLE_WARNING_NONNULL;
471 expect(i, "%U", NULL);
474 expect(i, "%m", mid);
475 expect(i, "%b", bid);
476 expect(i, "%H", host);
478 expect(i2, "%u", "root");
479 expect(i2, "%U", "0");
481 expect(i3, "%n", "name@inst.service");
482 expect(i3, "%N", "name@inst");
483 expect(i3, "%p", "name");
484 expect(i3, "%u", "xxxx-no-such-user");
486 DISABLE_WARNING_NONNULL;
487 expect(i3, "%U", NULL);
490 expect(i3, "%m", mid);
491 expect(i3, "%b", bid);
492 expect(i3, "%H", host);
494 expect(i4, "%u", "root");
495 expect(i4, "%U", "0");
498 int main(int argc, char *argv[]) {
501 log_parse_environment();
504 r = test_unit_file_get_set();
505 test_config_parse_exec();
506 test_load_env_file_1();
507 test_load_env_file_2();
508 test_load_env_file_3();
509 test_load_env_file_4();
510 test_load_env_file_5();
511 TEST_REQ_RUNNING_SYSTEMD(test_install_printf());