]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/test/test-unit-file.c
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"
39 #include "hostname-util.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(
99 unsigned section_line,
107 ExecCommand
*c
= NULL
, *c1
;
110 log_info("/* basic test */");
111 r
= config_parse_exec(NULL
, "fake", 1, "section", 1,
112 "LValue", 0, "/RValue r1",
115 check_execcommand(c
, "/RValue", "/RValue", "r1", NULL
, false);
117 r
= config_parse_exec(NULL
, "fake", 2, "section", 1,
118 "LValue", 0, "/RValue///slashes r1///",
121 log_info("/* test slashes */");
123 c1
= c
->command_next
;
124 check_execcommand(c1
, "/RValue/slashes", "/RValue///slashes", "r1///", NULL
, false);
126 log_info("/* trailing slash */");
127 r
= config_parse_exec(NULL
, "fake", 4, "section", 1,
128 "LValue", 0, "/RValue/ argv0 r1",
131 assert_se(c1
->command_next
== NULL
);
133 log_info("/* honour_argv0 */");
134 r
= config_parse_exec(NULL
, "fake", 3, "section", 1,
135 "LValue", 0, "@/RValue///slashes2 ///argv0 r1",
138 c1
= c1
->command_next
;
139 check_execcommand(c1
, "/RValue/slashes2", "///argv0", "r1", NULL
, false);
141 log_info("/* honour_argv0, no args */");
142 r
= config_parse_exec(NULL
, "fake", 3, "section", 1,
143 "LValue", 0, "@/RValue",
146 assert_se(c1
->command_next
== NULL
);
148 log_info("/* no command, check for bad memory access */");
149 r
= config_parse_exec(NULL
, "fake", 3, "section", 1,
153 assert_se(c1
->command_next
== NULL
);
155 log_info("/* ignore && honour_argv0 */");
156 r
= config_parse_exec(NULL
, "fake", 4, "section", 1,
157 "LValue", 0, "-@/RValue///slashes3 argv0a r1",
160 c1
= c1
->command_next
;
161 check_execcommand(c1
, "/RValue/slashes3", "argv0a", "r1", NULL
, true);
163 log_info("/* ignore && honour_argv0 */");
164 r
= config_parse_exec(NULL
, "fake", 4, "section", 1,
165 "LValue", 0, "@-/RValue///slashes4 argv0b r1",
168 c1
= c1
->command_next
;
169 check_execcommand(c1
, "/RValue/slashes4", "argv0b", "r1", NULL
, true);
171 log_info("/* ignore && ignore */");
172 r
= config_parse_exec(NULL
, "fake", 4, "section", 1,
173 "LValue", 0, "--/RValue argv0 r1",
176 assert_se(c1
->command_next
== NULL
);
178 log_info("/* ignore && ignore (2) */");
179 r
= config_parse_exec(NULL
, "fake", 4, "section", 1,
180 "LValue", 0, "-@-/RValue argv0 r1",
183 assert_se(c1
->command_next
== NULL
);
185 log_info("/* semicolon */");
186 r
= config_parse_exec(NULL
, "fake", 5, "section", 1,
188 "-@/RValue argv0 r1 ; "
192 c1
= c1
->command_next
;
193 check_execcommand(c1
, "/RValue", "argv0", "r1", NULL
, true);
195 c1
= c1
->command_next
;
196 check_execcommand(c1
, "/goo/goo", NULL
, "boo", NULL
, false);
198 log_info("/* trailing semicolon */");
199 r
= config_parse_exec(NULL
, "fake", 5, "section", 1,
201 "-@/RValue argv0 r1 ; ",
204 c1
= c1
->command_next
;
205 check_execcommand(c1
, "/RValue", "argv0", "r1", NULL
, true);
207 assert_se(c1
->command_next
== NULL
);
209 log_info("/* escaped semicolon */");
210 r
= config_parse_exec(NULL
, "fake", 5, "section", 1,
215 c1
= c1
->command_next
;
216 check_execcommand(c1
, "/bin/find", NULL
, ";", NULL
, false);
218 log_info("/* escaped semicolon with following arg */");
219 r
= config_parse_exec(NULL
, "fake", 5, "section", 1,
224 c1
= c1
->command_next
;
225 check_execcommand(c1
,
226 "/sbin/find", NULL
, ";", "x", false);
228 log_info("/* spaces in the filename */");
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("/* spaces in the filename, no args */");
239 r
= config_parse_exec(NULL
, "fake", 5, "section", 1,
241 "\"/PATH WITH SPACES/daemon -1 -2\"",
244 c1
= c1
->command_next
;
245 check_execcommand(c1
,
246 "/PATH WITH SPACES/daemon -1 -2", NULL
, NULL
, NULL
, false);
248 log_info("/* spaces in the filename, everything quoted */");
249 r
= config_parse_exec(NULL
, "fake", 5, "section", 1,
251 "\"/PATH WITH SPACES/daemon\" \"-1\" '-2'",
254 c1
= c1
->command_next
;
255 check_execcommand(c1
,
256 "/PATH WITH SPACES/daemon", NULL
, "-1", "-2", false);
258 log_info("/* escaped spaces in the filename */");
259 r
= config_parse_exec(NULL
, "fake", 5, "section", 1,
261 "\"/PATH\\sWITH\\sSPACES/daemon\" '-1 -2'",
264 c1
= c1
->command_next
;
265 check_execcommand(c1
,
266 "/PATH WITH SPACES/daemon", NULL
, "-1 -2", NULL
, false);
268 log_info("/* escaped spaces in the filename (2) */");
269 r
= config_parse_exec(NULL
, "fake", 5, "section", 1,
271 "\"/PATH\\x20WITH\\x20SPACES/daemon\" \"-1 -2\"",
274 c1
= c1
->command_next
;
275 check_execcommand(c1
,
276 "/PATH WITH SPACES/daemon", NULL
, "-1 -2", NULL
, false);
278 for (ccc
= "abfnrtv\\\'\"x"; *ccc
; ccc
++) {
279 /* \\x is an incomplete hexadecimal sequence, invalid because of the slash */
280 char path
[] = "/path\\X";
281 path
[sizeof(path
) - 2] = *ccc
;
283 log_info("/* invalid character: \\%c */", *ccc
);
284 r
= config_parse_exec(NULL
, "fake", 4, "section", 1,
288 assert_se(c1
->command_next
== NULL
);
291 log_info("/* valid character: \\s */");
292 r
= config_parse_exec(NULL
, "fake", 4, "section", 1,
293 "LValue", 0, "/path\\s",
296 c1
= c1
->command_next
;
297 check_execcommand(c1
, "/path ", NULL
, NULL
, NULL
, false);
299 log_info("/* trailing backslash: \\ */");
300 /* backslash is invalid */
301 r
= config_parse_exec(NULL
, "fake", 4, "section", 1,
302 "LValue", 0, "/path\\",
305 assert_se(c1
->command_next
== NULL
);
307 log_info("/* missing ending ' */");
308 r
= config_parse_exec(NULL
, "fake", 4, "section", 1,
309 "LValue", 0, "/path 'foo",
312 assert_se(c1
->command_next
== NULL
);
314 log_info("/* missing ending ' with trailing backslash */");
315 r
= config_parse_exec(NULL
, "fake", 4, "section", 1,
316 "LValue", 0, "/path 'foo\\",
319 assert_se(c1
->command_next
== NULL
);
321 log_info("/* invalid space between modifiers */");
322 r
= config_parse_exec(NULL
, "fake", 4, "section", 1,
323 "LValue", 0, "- /path",
326 assert_se(c1
->command_next
== NULL
);
328 log_info("/* only modifiers, no path */");
329 r
= config_parse_exec(NULL
, "fake", 4, "section", 1,
333 assert_se(c1
->command_next
== NULL
);
335 log_info("/* empty argument, reset */");
336 r
= config_parse_exec(NULL
, "fake", 4, "section", 1,
340 assert_se(c
== NULL
);
342 exec_command_free_list(c
);
360 "#SPAMD_ARGS=\"-d --socketpath=/var/lib/bulwark/spamd \\\n" \
361 "#--nouser-config \\\n" \
367 "HWMON_MODULES=\"coretemp f71882fg\"\n" \
369 "# For compatibility reasons\n" \
371 "MODULE_0=coretemp\n" \
378 static void test_load_env_file_1(void) {
379 _cleanup_strv_free_
char **data
= NULL
;
382 char name
[] = "/tmp/test-load-env-file.XXXXXX";
383 _cleanup_close_
int fd
;
385 fd
= mkostemp_safe(name
, O_RDWR
|O_CLOEXEC
);
387 assert_se(write(fd
, env_file_1
, sizeof(env_file_1
)) == sizeof(env_file_1
));
389 r
= load_env_file(NULL
, name
, NULL
, &data
);
391 assert_se(streq(data
[0], "a=a"));
392 assert_se(streq(data
[1], "b=bc"));
393 assert_se(streq(data
[2], "d=def"));
394 assert_se(streq(data
[3], "g=g "));
395 assert_se(streq(data
[4], "h=h"));
396 assert_se(streq(data
[5], "i=i"));
397 assert_se(data
[6] == NULL
);
401 static void test_load_env_file_2(void) {
402 _cleanup_strv_free_
char **data
= NULL
;
405 char name
[] = "/tmp/test-load-env-file.XXXXXX";
406 _cleanup_close_
int fd
;
408 fd
= mkostemp_safe(name
, O_RDWR
|O_CLOEXEC
);
410 assert_se(write(fd
, env_file_2
, sizeof(env_file_2
)) == sizeof(env_file_2
));
412 r
= load_env_file(NULL
, name
, NULL
, &data
);
414 assert_se(streq(data
[0], "a=a"));
415 assert_se(data
[1] == NULL
);
419 static void test_load_env_file_3(void) {
420 _cleanup_strv_free_
char **data
= NULL
;
423 char name
[] = "/tmp/test-load-env-file.XXXXXX";
424 _cleanup_close_
int fd
;
426 fd
= mkostemp_safe(name
, O_RDWR
|O_CLOEXEC
);
428 assert_se(write(fd
, env_file_3
, sizeof(env_file_3
)) == sizeof(env_file_3
));
430 r
= load_env_file(NULL
, name
, NULL
, &data
);
432 assert_se(data
== NULL
);
436 static void test_load_env_file_4(void) {
437 _cleanup_strv_free_
char **data
= NULL
;
438 char name
[] = "/tmp/test-load-env-file.XXXXXX";
439 _cleanup_close_
int fd
;
442 fd
= mkostemp_safe(name
, O_RDWR
|O_CLOEXEC
);
444 assert_se(write(fd
, env_file_4
, sizeof(env_file_4
)) == sizeof(env_file_4
));
446 r
= load_env_file(NULL
, name
, NULL
, &data
);
448 assert_se(streq(data
[0], "HWMON_MODULES=coretemp f71882fg"));
449 assert_se(streq(data
[1], "MODULE_0=coretemp"));
450 assert_se(streq(data
[2], "MODULE_1=f71882fg"));
451 assert_se(data
[3] == NULL
);
455 static void test_load_env_file_5(void) {
456 _cleanup_strv_free_
char **data
= NULL
;
459 char name
[] = "/tmp/test-load-env-file.XXXXXX";
460 _cleanup_close_
int fd
;
462 fd
= mkostemp_safe(name
, O_RDWR
|O_CLOEXEC
);
464 assert_se(write(fd
, env_file_5
, sizeof(env_file_5
)) == sizeof(env_file_5
));
466 r
= load_env_file(NULL
, name
, NULL
, &data
);
468 assert_se(streq(data
[0], "a="));
469 assert_se(streq(data
[1], "b="));
470 assert_se(data
[2] == NULL
);
474 static void test_install_printf(void) {
475 char name
[] = "name.service",
476 path
[] = "/run/systemd/system/name.service",
477 user
[] = "xxxx-no-such-user";
478 UnitFileInstallInfo i
= {name
, path
, user
};
479 UnitFileInstallInfo i2
= {name
, path
, NULL
};
480 char name3
[] = "name@inst.service",
481 path3
[] = "/run/systemd/system/name.service";
482 UnitFileInstallInfo i3
= {name3
, path3
, user
};
483 UnitFileInstallInfo i4
= {name3
, path3
, NULL
};
485 _cleanup_free_
char *mid
, *bid
, *host
;
487 assert_se(specifier_machine_id('m', NULL
, NULL
, &mid
) >= 0 && mid
);
488 assert_se(specifier_boot_id('b', NULL
, NULL
, &bid
) >= 0 && bid
);
489 assert_se((host
= gethostname_malloc()));
491 #define expect(src, pattern, result) \
493 _cleanup_free_ char *t = NULL; \
494 _cleanup_free_ char \
495 *d1 = strdup(i.name), \
496 *d2 = strdup(i.path), \
497 *d3 = strdup(i.user); \
498 assert_se(install_full_printf(&src, pattern, &t) >= 0 || !result); \
499 memzero(i.name, strlen(i.name)); \
500 memzero(i.path, strlen(i.path)); \
501 memzero(i.user, strlen(i.user)); \
502 assert_se(d1 && d2 && d3); \
505 assert_se(streq(t, result)); \
506 } else assert_se(t == NULL); \
507 strcpy(i.name, d1); \
508 strcpy(i.path, d2); \
509 strcpy(i.user, d3); \
512 assert_se(setenv("USER", "root", 1) == 0);
514 expect(i
, "%n", "name.service");
515 expect(i
, "%N", "name");
516 expect(i
, "%p", "name");
518 expect(i
, "%u", "xxxx-no-such-user");
520 DISABLE_WARNING_NONNULL
;
521 expect(i
, "%U", NULL
);
524 expect(i
, "%m", mid
);
525 expect(i
, "%b", bid
);
526 expect(i
, "%H", host
);
528 expect(i2
, "%u", "root");
529 expect(i2
, "%U", "0");
531 expect(i3
, "%n", "name@inst.service");
532 expect(i3
, "%N", "name@inst");
533 expect(i3
, "%p", "name");
534 expect(i3
, "%u", "xxxx-no-such-user");
536 DISABLE_WARNING_NONNULL
;
537 expect(i3
, "%U", NULL
);
540 expect(i3
, "%m", mid
);
541 expect(i3
, "%b", bid
);
542 expect(i3
, "%H", host
);
544 expect(i4
, "%u", "root");
545 expect(i4
, "%U", "0");
548 int main(int argc
, char *argv
[]) {
551 log_parse_environment();
554 r
= test_unit_file_get_set();
555 test_config_parse_exec();
556 test_load_env_file_1();
557 test_load_env_file_2();
558 test_load_env_file_3();
559 test_load_env_file_4();
560 test_load_env_file_5();
561 TEST_REQ_RUNNING_SYSTEMD(test_install_printf());