]>
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/>.
31 #include "hostname-util.h"
32 #include "install-printf.h"
34 #include "load-fragment.h"
36 #include "specifier.h"
37 #include "string-util.h"
39 #include "test-helper.h"
42 static int test_unit_file_get_set(void) {
48 h
= hashmap_new(&string_hash_ops
);
51 r
= unit_file_get_list(UNIT_FILE_SYSTEM
, NULL
, h
);
53 if (r
== -EPERM
|| r
== -EACCES
) {
54 printf("Skipping test: unit_file_get_list: %s", strerror(-r
));
55 return EXIT_TEST_SKIP
;
58 log_full(r
== 0 ? LOG_INFO
: LOG_ERR
,
59 "unit_file_get_list: %s", strerror(-r
));
63 HASHMAP_FOREACH(p
, h
, i
)
64 printf("%s = %s\n", p
->path
, unit_file_state_to_string(p
->state
));
66 unit_file_list_free(h
);
71 static void check_execcommand(ExecCommand
*c
,
80 log_info("expect: \"%s\" [\"%s\" \"%s\" \"%s\"]",
81 path
, argv0
?: path
, argv1
, argv2
);
82 n
= strv_length(c
->argv
);
83 log_info("actual: \"%s\" [\"%s\" \"%s\" \"%s\"]",
84 c
->path
, c
->argv
[0], n
> 0 ? c
->argv
[1] : NULL
, n
> 1 ? c
->argv
[2] : NULL
);
85 assert_se(streq(c
->path
, path
));
86 assert_se(streq(c
->argv
[0], argv0
?: path
));
88 assert_se(streq_ptr(c
->argv
[1], argv1
));
90 assert_se(streq_ptr(c
->argv
[2], argv2
));
91 assert_se(c
->ignore
== ignore
);
94 static void test_config_parse_exec(void) {
95 /* int config_parse_exec(
100 unsigned section_line,
108 ExecCommand
*c
= NULL
, *c1
;
111 log_info("/* basic test */");
112 r
= config_parse_exec(NULL
, "fake", 1, "section", 1,
113 "LValue", 0, "/RValue r1",
116 check_execcommand(c
, "/RValue", "/RValue", "r1", NULL
, false);
118 r
= config_parse_exec(NULL
, "fake", 2, "section", 1,
119 "LValue", 0, "/RValue///slashes r1///",
122 log_info("/* test slashes */");
124 c1
= c
->command_next
;
125 check_execcommand(c1
, "/RValue/slashes", "/RValue///slashes", "r1///", NULL
, false);
127 log_info("/* trailing slash */");
128 r
= config_parse_exec(NULL
, "fake", 4, "section", 1,
129 "LValue", 0, "/RValue/ argv0 r1",
132 assert_se(c1
->command_next
== NULL
);
134 log_info("/* honour_argv0 */");
135 r
= config_parse_exec(NULL
, "fake", 3, "section", 1,
136 "LValue", 0, "@/RValue///slashes2 ///argv0 r1",
139 c1
= c1
->command_next
;
140 check_execcommand(c1
, "/RValue/slashes2", "///argv0", "r1", NULL
, false);
142 log_info("/* honour_argv0, no args */");
143 r
= config_parse_exec(NULL
, "fake", 3, "section", 1,
144 "LValue", 0, "@/RValue",
147 assert_se(c1
->command_next
== NULL
);
149 log_info("/* no command, whitespace only, reset */");
150 r
= config_parse_exec(NULL
, "fake", 3, "section", 1,
154 assert_se(c
== NULL
);
156 log_info("/* ignore && honour_argv0 */");
157 r
= config_parse_exec(NULL
, "fake", 4, "section", 1,
158 "LValue", 0, "-@/RValue///slashes3 argv0a r1",
162 check_execcommand(c1
, "/RValue/slashes3", "argv0a", "r1", NULL
, true);
164 log_info("/* ignore && honour_argv0 */");
165 r
= config_parse_exec(NULL
, "fake", 4, "section", 1,
166 "LValue", 0, "@-/RValue///slashes4 argv0b r1",
169 c1
= c1
->command_next
;
170 check_execcommand(c1
, "/RValue/slashes4", "argv0b", "r1", NULL
, true);
172 log_info("/* ignore && ignore */");
173 r
= config_parse_exec(NULL
, "fake", 4, "section", 1,
174 "LValue", 0, "--/RValue argv0 r1",
177 assert_se(c1
->command_next
== NULL
);
179 log_info("/* ignore && ignore (2) */");
180 r
= config_parse_exec(NULL
, "fake", 4, "section", 1,
181 "LValue", 0, "-@-/RValue argv0 r1",
184 assert_se(c1
->command_next
== NULL
);
186 log_info("/* semicolon */");
187 r
= config_parse_exec(NULL
, "fake", 5, "section", 1,
189 "-@/RValue argv0 r1 ; "
193 c1
= c1
->command_next
;
194 check_execcommand(c1
, "/RValue", "argv0", "r1", NULL
, true);
196 c1
= c1
->command_next
;
197 check_execcommand(c1
, "/goo/goo", NULL
, "boo", NULL
, false);
199 log_info("/* two semicolons in a row */");
200 r
= config_parse_exec(NULL
, "fake", 5, "section", 1,
202 "-@/RValue argv0 r1 ; ; "
206 c1
= c1
->command_next
;
207 check_execcommand(c1
, "/RValue", "argv0", "r1", NULL
, true);
209 /* second command fails because the executable name is ";" */
210 assert_se(c1
->command_next
== NULL
);
212 log_info("/* trailing semicolon */");
213 r
= config_parse_exec(NULL
, "fake", 5, "section", 1,
215 "-@/RValue argv0 r1 ; ",
218 c1
= c1
->command_next
;
219 check_execcommand(c1
, "/RValue", "argv0", "r1", NULL
, true);
221 assert_se(c1
->command_next
== NULL
);
223 log_info("/* trailing semicolon, no whitespace */");
224 r
= config_parse_exec(NULL
, "fake", 5, "section", 1,
226 "-@/RValue argv0 r1 ;",
229 c1
= c1
->command_next
;
230 check_execcommand(c1
, "/RValue", "argv0", "r1", NULL
, true);
232 assert_se(c1
->command_next
== NULL
);
234 log_info("/* trailing semicolon in single quotes */");
235 r
= config_parse_exec(NULL
, "fake", 5, "section", 1,
237 "-@/RValue argv0 r1 ';'",
240 c1
= c1
->command_next
;
241 check_execcommand(c1
, "/RValue", "argv0", "r1", ";", true);
243 log_info("/* escaped semicolon */");
244 r
= config_parse_exec(NULL
, "fake", 5, "section", 1,
249 c1
= c1
->command_next
;
250 check_execcommand(c1
, "/bin/find", NULL
, ";", NULL
, false);
252 log_info("/* escaped semicolon with following arg */");
253 r
= config_parse_exec(NULL
, "fake", 5, "section", 1,
258 c1
= c1
->command_next
;
259 check_execcommand(c1
,
260 "/sbin/find", NULL
, ";", "/x", false);
262 log_info("/* escaped semicolon as part of an expression */");
263 r
= config_parse_exec(NULL
, "fake", 5, "section", 1,
268 c1
= c1
->command_next
;
269 check_execcommand(c1
,
270 "/sbin/find", NULL
, "\\;x", NULL
, false);
272 log_info("/* encoded semicolon */");
273 r
= config_parse_exec(NULL
, "fake", 5, "section", 1,
278 c1
= c1
->command_next
;
279 check_execcommand(c1
, "/bin/find", NULL
, ";", NULL
, false);
281 log_info("/* quoted semicolon */");
282 r
= config_parse_exec(NULL
, "fake", 5, "section", 1,
287 c1
= c1
->command_next
;
288 check_execcommand(c1
, "/bin/find", NULL
, ";", NULL
, false);
290 log_info("/* quoted semicolon with following arg */");
291 r
= config_parse_exec(NULL
, "fake", 5, "section", 1,
293 "/sbin/find \";\" /x",
296 c1
= c1
->command_next
;
297 check_execcommand(c1
,
298 "/sbin/find", NULL
, ";", "/x", false);
300 log_info("/* spaces in the filename */");
301 r
= config_parse_exec(NULL
, "fake", 5, "section", 1,
303 "\"/PATH WITH SPACES/daemon\" -1 -2",
306 c1
= c1
->command_next
;
307 check_execcommand(c1
,
308 "/PATH WITH SPACES/daemon", NULL
, "-1", "-2", false);
310 log_info("/* spaces in the filename, no args */");
311 r
= config_parse_exec(NULL
, "fake", 5, "section", 1,
313 "\"/PATH WITH SPACES/daemon -1 -2\"",
316 c1
= c1
->command_next
;
317 check_execcommand(c1
,
318 "/PATH WITH SPACES/daemon -1 -2", NULL
, NULL
, NULL
, false);
320 log_info("/* spaces in the filename, everything quoted */");
321 r
= config_parse_exec(NULL
, "fake", 5, "section", 1,
323 "\"/PATH WITH SPACES/daemon\" \"-1\" '-2'",
326 c1
= c1
->command_next
;
327 check_execcommand(c1
,
328 "/PATH WITH SPACES/daemon", NULL
, "-1", "-2", false);
330 log_info("/* escaped spaces in the filename */");
331 r
= config_parse_exec(NULL
, "fake", 5, "section", 1,
333 "\"/PATH\\sWITH\\sSPACES/daemon\" '-1 -2'",
336 c1
= c1
->command_next
;
337 check_execcommand(c1
,
338 "/PATH WITH SPACES/daemon", NULL
, "-1 -2", NULL
, false);
340 log_info("/* escaped spaces in the filename (2) */");
341 r
= config_parse_exec(NULL
, "fake", 5, "section", 1,
343 "\"/PATH\\x20WITH\\x20SPACES/daemon\" \"-1 -2\"",
346 c1
= c1
->command_next
;
347 check_execcommand(c1
,
348 "/PATH WITH SPACES/daemon", NULL
, "-1 -2", NULL
, false);
350 for (ccc
= "abfnrtv\\\'\"x"; *ccc
; ccc
++) {
351 /* \\x is an incomplete hexadecimal sequence, invalid because of the slash */
352 char path
[] = "/path\\X";
353 path
[sizeof(path
) - 2] = *ccc
;
355 log_info("/* invalid character: \\%c */", *ccc
);
356 r
= config_parse_exec(NULL
, "fake", 4, "section", 1,
360 assert_se(c1
->command_next
== NULL
);
363 log_info("/* valid character: \\s */");
364 r
= config_parse_exec(NULL
, "fake", 4, "section", 1,
365 "LValue", 0, "/path\\s",
368 c1
= c1
->command_next
;
369 check_execcommand(c1
, "/path ", NULL
, NULL
, NULL
, false);
371 log_info("/* quoted backslashes */");
372 r
= config_parse_exec(NULL
, "fake", 5, "section", 1,
374 "/bin/grep '\\w+\\K'",
377 c1
= c1
->command_next
;
378 check_execcommand(c1
, "/bin/grep", NULL
, "\\w+\\K", NULL
, false);
381 log_info("/* trailing backslash: \\ */");
382 /* backslash is invalid */
383 r
= config_parse_exec(NULL
, "fake", 4, "section", 1,
384 "LValue", 0, "/path\\",
387 assert_se(c1
->command_next
== NULL
);
389 log_info("/* missing ending ' */");
390 r
= config_parse_exec(NULL
, "fake", 4, "section", 1,
391 "LValue", 0, "/path 'foo",
394 assert_se(c1
->command_next
== NULL
);
396 log_info("/* missing ending ' with trailing backslash */");
397 r
= config_parse_exec(NULL
, "fake", 4, "section", 1,
398 "LValue", 0, "/path 'foo\\",
401 assert_se(c1
->command_next
== NULL
);
403 log_info("/* invalid space between modifiers */");
404 r
= config_parse_exec(NULL
, "fake", 4, "section", 1,
405 "LValue", 0, "- /path",
408 assert_se(c1
->command_next
== NULL
);
410 log_info("/* only modifiers, no path */");
411 r
= config_parse_exec(NULL
, "fake", 4, "section", 1,
415 assert_se(c1
->command_next
== NULL
);
417 log_info("/* empty argument, reset */");
418 r
= config_parse_exec(NULL
, "fake", 4, "section", 1,
422 assert_se(c
== NULL
);
424 exec_command_free_list(c
);
442 "#SPAMD_ARGS=\"-d --socketpath=/var/lib/bulwark/spamd \\\n" \
443 "#--nouser-config \\\n" \
449 "HWMON_MODULES=\"coretemp f71882fg\"\n" \
451 "# For compatibility reasons\n" \
453 "MODULE_0=coretemp\n" \
460 static void test_load_env_file_1(void) {
461 _cleanup_strv_free_
char **data
= NULL
;
464 char name
[] = "/tmp/test-load-env-file.XXXXXX";
465 _cleanup_close_
int fd
;
467 fd
= mkostemp_safe(name
, O_RDWR
|O_CLOEXEC
);
469 assert_se(write(fd
, env_file_1
, sizeof(env_file_1
)) == sizeof(env_file_1
));
471 r
= load_env_file(NULL
, name
, NULL
, &data
);
473 assert_se(streq(data
[0], "a=a"));
474 assert_se(streq(data
[1], "b=bc"));
475 assert_se(streq(data
[2], "d=def"));
476 assert_se(streq(data
[3], "g=g "));
477 assert_se(streq(data
[4], "h=h"));
478 assert_se(streq(data
[5], "i=i"));
479 assert_se(data
[6] == NULL
);
483 static void test_load_env_file_2(void) {
484 _cleanup_strv_free_
char **data
= NULL
;
487 char name
[] = "/tmp/test-load-env-file.XXXXXX";
488 _cleanup_close_
int fd
;
490 fd
= mkostemp_safe(name
, O_RDWR
|O_CLOEXEC
);
492 assert_se(write(fd
, env_file_2
, sizeof(env_file_2
)) == sizeof(env_file_2
));
494 r
= load_env_file(NULL
, name
, NULL
, &data
);
496 assert_se(streq(data
[0], "a=a"));
497 assert_se(data
[1] == NULL
);
501 static void test_load_env_file_3(void) {
502 _cleanup_strv_free_
char **data
= NULL
;
505 char name
[] = "/tmp/test-load-env-file.XXXXXX";
506 _cleanup_close_
int fd
;
508 fd
= mkostemp_safe(name
, O_RDWR
|O_CLOEXEC
);
510 assert_se(write(fd
, env_file_3
, sizeof(env_file_3
)) == sizeof(env_file_3
));
512 r
= load_env_file(NULL
, name
, NULL
, &data
);
514 assert_se(data
== NULL
);
518 static void test_load_env_file_4(void) {
519 _cleanup_strv_free_
char **data
= NULL
;
520 char name
[] = "/tmp/test-load-env-file.XXXXXX";
521 _cleanup_close_
int fd
;
524 fd
= mkostemp_safe(name
, O_RDWR
|O_CLOEXEC
);
526 assert_se(write(fd
, env_file_4
, sizeof(env_file_4
)) == sizeof(env_file_4
));
528 r
= load_env_file(NULL
, name
, NULL
, &data
);
530 assert_se(streq(data
[0], "HWMON_MODULES=coretemp f71882fg"));
531 assert_se(streq(data
[1], "MODULE_0=coretemp"));
532 assert_se(streq(data
[2], "MODULE_1=f71882fg"));
533 assert_se(data
[3] == NULL
);
537 static void test_load_env_file_5(void) {
538 _cleanup_strv_free_
char **data
= NULL
;
541 char name
[] = "/tmp/test-load-env-file.XXXXXX";
542 _cleanup_close_
int fd
;
544 fd
= mkostemp_safe(name
, O_RDWR
|O_CLOEXEC
);
546 assert_se(write(fd
, env_file_5
, sizeof(env_file_5
)) == sizeof(env_file_5
));
548 r
= load_env_file(NULL
, name
, NULL
, &data
);
550 assert_se(streq(data
[0], "a="));
551 assert_se(streq(data
[1], "b="));
552 assert_se(data
[2] == NULL
);
556 static void test_install_printf(void) {
557 char name
[] = "name.service",
558 path
[] = "/run/systemd/system/name.service",
559 user
[] = "xxxx-no-such-user";
560 UnitFileInstallInfo i
= {name
, path
, user
};
561 UnitFileInstallInfo i2
= {name
, path
, NULL
};
562 char name3
[] = "name@inst.service",
563 path3
[] = "/run/systemd/system/name.service";
564 UnitFileInstallInfo i3
= {name3
, path3
, user
};
565 UnitFileInstallInfo i4
= {name3
, path3
, NULL
};
567 _cleanup_free_
char *mid
, *bid
, *host
;
569 assert_se(specifier_machine_id('m', NULL
, NULL
, &mid
) >= 0 && mid
);
570 assert_se(specifier_boot_id('b', NULL
, NULL
, &bid
) >= 0 && bid
);
571 assert_se((host
= gethostname_malloc()));
573 #define expect(src, pattern, result) \
575 _cleanup_free_ char *t = NULL; \
576 _cleanup_free_ char \
577 *d1 = strdup(i.name), \
578 *d2 = strdup(i.path), \
579 *d3 = strdup(i.user); \
580 assert_se(install_full_printf(&src, pattern, &t) >= 0 || !result); \
581 memzero(i.name, strlen(i.name)); \
582 memzero(i.path, strlen(i.path)); \
583 memzero(i.user, strlen(i.user)); \
584 assert_se(d1 && d2 && d3); \
587 assert_se(streq(t, result)); \
588 } else assert_se(t == NULL); \
589 strcpy(i.name, d1); \
590 strcpy(i.path, d2); \
591 strcpy(i.user, d3); \
594 assert_se(setenv("USER", "root", 1) == 0);
596 expect(i
, "%n", "name.service");
597 expect(i
, "%N", "name");
598 expect(i
, "%p", "name");
600 expect(i
, "%u", "xxxx-no-such-user");
602 DISABLE_WARNING_NONNULL
;
603 expect(i
, "%U", NULL
);
606 expect(i
, "%m", mid
);
607 expect(i
, "%b", bid
);
608 expect(i
, "%H", host
);
610 expect(i2
, "%u", "root");
611 expect(i2
, "%U", "0");
613 expect(i3
, "%n", "name@inst.service");
614 expect(i3
, "%N", "name@inst");
615 expect(i3
, "%p", "name");
616 expect(i3
, "%u", "xxxx-no-such-user");
618 DISABLE_WARNING_NONNULL
;
619 expect(i3
, "%U", NULL
);
622 expect(i3
, "%m", mid
);
623 expect(i3
, "%b", bid
);
624 expect(i3
, "%H", host
);
626 expect(i4
, "%u", "root");
627 expect(i4
, "%U", "0");
630 int main(int argc
, char *argv
[]) {
633 log_parse_environment();
636 r
= test_unit_file_get_set();
637 test_config_parse_exec();
638 test_load_env_file_1();
639 test_load_env_file_2();
640 test_load_env_file_3();
641 test_load_env_file_4();
642 test_load_env_file_5();
643 TEST_REQ_RUNNING_SYSTEMD(test_install_printf());