]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/test/test-unit-file.c
tree-wide: drop 'This file is part of systemd' blurb
[thirdparty/systemd.git] / src / test / test-unit-file.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 Copyright 2012 Lennart Poettering
4 Copyright 2013 Zbigniew Jędrzejewski-Szmek
5 ***/
6
7 #include <fcntl.h>
8 #include <stddef.h>
9 #include <stdio.h>
10 #include <string.h>
11 #include <sys/capability.h>
12 #include <unistd.h>
13
14 #include "alloc-util.h"
15 #include "all-units.h"
16 #include "capability-util.h"
17 #include "conf-parser.h"
18 #include "fd-util.h"
19 #include "fileio.h"
20 #include "fs-util.h"
21 #include "hashmap.h"
22 #include "hostname-util.h"
23 #include "install-printf.h"
24 #include "install.h"
25 #include "load-fragment.h"
26 #include "macro.h"
27 #include "rm-rf.h"
28 #include "specifier.h"
29 #include "string-util.h"
30 #include "strv.h"
31 #include "test-helper.h"
32 #include "tests.h"
33 #include "user-util.h"
34 #include "util.h"
35
36 static int test_unit_file_get_set(void) {
37 int r;
38 Hashmap *h;
39 Iterator i;
40 UnitFileList *p;
41
42 h = hashmap_new(&string_hash_ops);
43 assert_se(h);
44
45 r = unit_file_get_list(UNIT_FILE_SYSTEM, NULL, h, NULL, NULL);
46
47 if (IN_SET(r, -EPERM, -EACCES)) {
48 log_notice_errno(r, "Skipping test: unit_file_get_list: %m");
49 return EXIT_TEST_SKIP;
50 }
51
52 log_full_errno(r == 0 ? LOG_INFO : LOG_ERR, r,
53 "unit_file_get_list: %m");
54 if (r < 0)
55 return EXIT_FAILURE;
56
57 HASHMAP_FOREACH(p, h, i)
58 printf("%s = %s\n", p->path, unit_file_state_to_string(p->state));
59
60 unit_file_list_free(h);
61
62 return 0;
63 }
64
65 static void check_execcommand(ExecCommand *c,
66 const char* path,
67 const char* argv0,
68 const char* argv1,
69 const char* argv2,
70 bool ignore) {
71 size_t n;
72
73 assert_se(c);
74 log_info("expect: \"%s\" [\"%s\" \"%s\" \"%s\"]",
75 path, argv0 ?: path, argv1, argv2);
76 n = strv_length(c->argv);
77 log_info("actual: \"%s\" [\"%s\" \"%s\" \"%s\"]",
78 c->path, c->argv[0], n > 0 ? c->argv[1] : NULL, n > 1 ? c->argv[2] : NULL);
79 assert_se(streq(c->path, path));
80 assert_se(streq(c->argv[0], argv0 ?: path));
81 if (n > 0)
82 assert_se(streq_ptr(c->argv[1], argv1));
83 if (n > 1)
84 assert_se(streq_ptr(c->argv[2], argv2));
85 assert_se(!!(c->flags & EXEC_COMMAND_IGNORE_FAILURE) == ignore);
86 }
87
88 static void test_config_parse_exec(void) {
89 /* int config_parse_exec(
90 const char *unit,
91 const char *filename,
92 unsigned line,
93 const char *section,
94 unsigned section_line,
95 const char *lvalue,
96 int ltype,
97 const char *rvalue,
98 void *data,
99 void *userdata) */
100 int r;
101
102 ExecCommand *c = NULL, *c1;
103 const char *ccc;
104 _cleanup_(manager_freep) Manager *m = NULL;
105 _cleanup_(unit_freep) Unit *u = NULL;
106
107 r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_MINIMAL, &m);
108 if (MANAGER_SKIP_TEST(r)) {
109 log_notice_errno(r, "Skipping test: manager_new: %m");
110 return;
111 }
112
113 assert_se(r >= 0);
114 assert_se(manager_startup(m, NULL, NULL) >= 0);
115
116 assert_se(u = unit_new(m, sizeof(Service)));
117
118 log_info("/* basic test */");
119 r = config_parse_exec(NULL, "fake", 1, "section", 1,
120 "LValue", 0, "/RValue r1",
121 &c, u);
122 assert_se(r >= 0);
123 check_execcommand(c, "/RValue", "/RValue", "r1", NULL, false);
124
125 r = config_parse_exec(NULL, "fake", 2, "section", 1,
126 "LValue", 0, "/RValue///slashes r1///",
127 &c, u);
128
129 log_info("/* test slashes */");
130 assert_se(r >= 0);
131 c1 = c->command_next;
132 check_execcommand(c1, "/RValue/slashes", "/RValue///slashes", "r1///", NULL, false);
133
134 log_info("/* trailing slash */");
135 r = config_parse_exec(NULL, "fake", 4, "section", 1,
136 "LValue", 0, "/RValue/ argv0 r1",
137 &c, u);
138 assert_se(r == -ENOEXEC);
139 assert_se(c1->command_next == NULL);
140
141 log_info("/* honour_argv0 */");
142 r = config_parse_exec(NULL, "fake", 3, "section", 1,
143 "LValue", 0, "@/RValue///slashes2 ///argv0 r1",
144 &c, u);
145 assert_se(r >= 0);
146 c1 = c1->command_next;
147 check_execcommand(c1, "/RValue/slashes2", "///argv0", "r1", NULL, false);
148
149 log_info("/* honour_argv0, no args */");
150 r = config_parse_exec(NULL, "fake", 3, "section", 1,
151 "LValue", 0, "@/RValue",
152 &c, u);
153 assert_se(r == -ENOEXEC);
154 assert_se(c1->command_next == NULL);
155
156 log_info("/* no command, whitespace only, reset */");
157 r = config_parse_exec(NULL, "fake", 3, "section", 1,
158 "LValue", 0, " ",
159 &c, u);
160 assert_se(r == 0);
161 assert_se(c == NULL);
162
163 log_info("/* ignore && honour_argv0 */");
164 r = config_parse_exec(NULL, "fake", 4, "section", 1,
165 "LValue", 0, "-@/RValue///slashes3 argv0a r1",
166 &c, u);
167 assert_se(r >= 0);
168 c1 = c;
169 check_execcommand(c1, "/RValue/slashes3", "argv0a", "r1", NULL, true);
170
171 log_info("/* ignore && honour_argv0 */");
172 r = config_parse_exec(NULL, "fake", 4, "section", 1,
173 "LValue", 0, "@-/RValue///slashes4 argv0b r1",
174 &c, u);
175 assert_se(r >= 0);
176 c1 = c1->command_next;
177 check_execcommand(c1, "/RValue/slashes4", "argv0b", "r1", NULL, true);
178
179 log_info("/* ignore && ignore */");
180 r = config_parse_exec(NULL, "fake", 4, "section", 1,
181 "LValue", 0, "--/RValue argv0 r1",
182 &c, u);
183 assert_se(r == 0);
184 assert_se(c1->command_next == NULL);
185
186 log_info("/* ignore && ignore (2) */");
187 r = config_parse_exec(NULL, "fake", 4, "section", 1,
188 "LValue", 0, "-@-/RValue argv0 r1",
189 &c, u);
190 assert_se(r == 0);
191 assert_se(c1->command_next == NULL);
192
193 log_info("/* semicolon */");
194 r = config_parse_exec(NULL, "fake", 5, "section", 1,
195 "LValue", 0,
196 "-@/RValue argv0 r1 ; "
197 "/goo/goo boo",
198 &c, u);
199 assert_se(r >= 0);
200 c1 = c1->command_next;
201 check_execcommand(c1, "/RValue", "argv0", "r1", NULL, true);
202
203 c1 = c1->command_next;
204 check_execcommand(c1, "/goo/goo", NULL, "boo", NULL, false);
205
206 log_info("/* two semicolons in a row */");
207 r = config_parse_exec(NULL, "fake", 5, "section", 1,
208 "LValue", 0,
209 "-@/RValue argv0 r1 ; ; "
210 "/goo/goo boo",
211 &c, u);
212 assert_se(r == -ENOEXEC);
213 c1 = c1->command_next;
214 check_execcommand(c1, "/RValue", "argv0", "r1", NULL, true);
215
216 /* second command fails because the executable name is ";" */
217 assert_se(c1->command_next == NULL);
218
219 log_info("/* trailing semicolon */");
220 r = config_parse_exec(NULL, "fake", 5, "section", 1,
221 "LValue", 0,
222 "-@/RValue argv0 r1 ; ",
223 &c, u);
224 assert_se(r >= 0);
225 c1 = c1->command_next;
226 check_execcommand(c1, "/RValue", "argv0", "r1", NULL, true);
227
228 assert_se(c1->command_next == NULL);
229
230 log_info("/* trailing semicolon, no whitespace */");
231 r = config_parse_exec(NULL, "fake", 5, "section", 1,
232 "LValue", 0,
233 "-@/RValue argv0 r1 ;",
234 &c, u);
235 assert_se(r >= 0);
236 c1 = c1->command_next;
237 check_execcommand(c1, "/RValue", "argv0", "r1", NULL, true);
238
239 assert_se(c1->command_next == NULL);
240
241 log_info("/* trailing semicolon in single quotes */");
242 r = config_parse_exec(NULL, "fake", 5, "section", 1,
243 "LValue", 0,
244 "-@/RValue argv0 r1 ';'",
245 &c, u);
246 assert_se(r >= 0);
247 c1 = c1->command_next;
248 check_execcommand(c1, "/RValue", "argv0", "r1", ";", true);
249
250 log_info("/* escaped semicolon */");
251 r = config_parse_exec(NULL, "fake", 5, "section", 1,
252 "LValue", 0,
253 "/bin/find \\;",
254 &c, u);
255 assert_se(r >= 0);
256 c1 = c1->command_next;
257 check_execcommand(c1, "/bin/find", NULL, ";", NULL, false);
258
259 log_info("/* escaped semicolon with following arg */");
260 r = config_parse_exec(NULL, "fake", 5, "section", 1,
261 "LValue", 0,
262 "/sbin/find \\; /x",
263 &c, u);
264 assert_se(r >= 0);
265 c1 = c1->command_next;
266 check_execcommand(c1,
267 "/sbin/find", NULL, ";", "/x", false);
268
269 log_info("/* escaped semicolon as part of an expression */");
270 r = config_parse_exec(NULL, "fake", 5, "section", 1,
271 "LValue", 0,
272 "/sbin/find \\;x",
273 &c, u);
274 assert_se(r >= 0);
275 c1 = c1->command_next;
276 check_execcommand(c1,
277 "/sbin/find", NULL, "\\;x", NULL, false);
278
279 log_info("/* encoded semicolon */");
280 r = config_parse_exec(NULL, "fake", 5, "section", 1,
281 "LValue", 0,
282 "/bin/find \\073",
283 &c, u);
284 assert_se(r >= 0);
285 c1 = c1->command_next;
286 check_execcommand(c1, "/bin/find", NULL, ";", NULL, false);
287
288 log_info("/* quoted semicolon */");
289 r = config_parse_exec(NULL, "fake", 5, "section", 1,
290 "LValue", 0,
291 "/bin/find \";\"",
292 &c, u);
293 assert_se(r >= 0);
294 c1 = c1->command_next;
295 check_execcommand(c1, "/bin/find", NULL, ";", NULL, false);
296
297 log_info("/* quoted semicolon with following arg */");
298 r = config_parse_exec(NULL, "fake", 5, "section", 1,
299 "LValue", 0,
300 "/sbin/find \";\" /x",
301 &c, u);
302 assert_se(r >= 0);
303 c1 = c1->command_next;
304 check_execcommand(c1,
305 "/sbin/find", NULL, ";", "/x", false);
306
307 log_info("/* spaces in the filename */");
308 r = config_parse_exec(NULL, "fake", 5, "section", 1,
309 "LValue", 0,
310 "\"/PATH WITH SPACES/daemon\" -1 -2",
311 &c, u);
312 assert_se(r >= 0);
313 c1 = c1->command_next;
314 check_execcommand(c1,
315 "/PATH WITH SPACES/daemon", NULL, "-1", "-2", false);
316
317 log_info("/* spaces in the filename, no args */");
318 r = config_parse_exec(NULL, "fake", 5, "section", 1,
319 "LValue", 0,
320 "\"/PATH WITH SPACES/daemon -1 -2\"",
321 &c, u);
322 assert_se(r >= 0);
323 c1 = c1->command_next;
324 check_execcommand(c1,
325 "/PATH WITH SPACES/daemon -1 -2", NULL, NULL, NULL, false);
326
327 log_info("/* spaces in the filename, everything quoted */");
328 r = config_parse_exec(NULL, "fake", 5, "section", 1,
329 "LValue", 0,
330 "\"/PATH WITH SPACES/daemon\" \"-1\" '-2'",
331 &c, u);
332 assert_se(r >= 0);
333 c1 = c1->command_next;
334 check_execcommand(c1,
335 "/PATH WITH SPACES/daemon", NULL, "-1", "-2", false);
336
337 log_info("/* escaped spaces in the filename */");
338 r = config_parse_exec(NULL, "fake", 5, "section", 1,
339 "LValue", 0,
340 "\"/PATH\\sWITH\\sSPACES/daemon\" '-1 -2'",
341 &c, u);
342 assert_se(r >= 0);
343 c1 = c1->command_next;
344 check_execcommand(c1,
345 "/PATH WITH SPACES/daemon", NULL, "-1 -2", NULL, false);
346
347 log_info("/* escaped spaces in the filename (2) */");
348 r = config_parse_exec(NULL, "fake", 5, "section", 1,
349 "LValue", 0,
350 "\"/PATH\\x20WITH\\x20SPACES/daemon\" \"-1 -2\"",
351 &c, u);
352 assert_se(r >= 0);
353 c1 = c1->command_next;
354 check_execcommand(c1,
355 "/PATH WITH SPACES/daemon", NULL, "-1 -2", NULL, false);
356
357 for (ccc = "abfnrtv\\\'\"x"; *ccc; ccc++) {
358 /* \\x is an incomplete hexadecimal sequence, invalid because of the slash */
359 char path[] = "/path\\X";
360 path[sizeof(path) - 2] = *ccc;
361
362 log_info("/* invalid character: \\%c */", *ccc);
363 r = config_parse_exec(NULL, "fake", 4, "section", 1,
364 "LValue", 0, path,
365 &c, u);
366 assert_se(r == -ENOEXEC);
367 assert_se(c1->command_next == NULL);
368 }
369
370 log_info("/* valid character: \\s */");
371 r = config_parse_exec(NULL, "fake", 4, "section", 1,
372 "LValue", 0, "/path\\s",
373 &c, u);
374 assert_se(r >= 0);
375 c1 = c1->command_next;
376 check_execcommand(c1, "/path ", NULL, NULL, NULL, false);
377
378 log_info("/* quoted backslashes */");
379 r = config_parse_exec(NULL, "fake", 5, "section", 1,
380 "LValue", 0,
381 "/bin/grep '\\w+\\K'",
382 &c, u);
383 assert_se(r >= 0);
384 c1 = c1->command_next;
385 check_execcommand(c1, "/bin/grep", NULL, "\\w+\\K", NULL, false);
386
387 log_info("/* trailing backslash: \\ */");
388 /* backslash is invalid */
389 r = config_parse_exec(NULL, "fake", 4, "section", 1,
390 "LValue", 0, "/path\\",
391 &c, u);
392 assert_se(r == -ENOEXEC);
393 assert_se(c1->command_next == NULL);
394
395 log_info("/* missing ending ' */");
396 r = config_parse_exec(NULL, "fake", 4, "section", 1,
397 "LValue", 0, "/path 'foo",
398 &c, u);
399 assert_se(r == -ENOEXEC);
400 assert_se(c1->command_next == NULL);
401
402 log_info("/* missing ending ' with trailing backslash */");
403 r = config_parse_exec(NULL, "fake", 4, "section", 1,
404 "LValue", 0, "/path 'foo\\",
405 &c, u);
406 assert_se(r == -ENOEXEC);
407 assert_se(c1->command_next == NULL);
408
409 log_info("/* invalid space between modifiers */");
410 r = config_parse_exec(NULL, "fake", 4, "section", 1,
411 "LValue", 0, "- /path",
412 &c, u);
413 assert_se(r == 0);
414 assert_se(c1->command_next == NULL);
415
416 log_info("/* only modifiers, no path */");
417 r = config_parse_exec(NULL, "fake", 4, "section", 1,
418 "LValue", 0, "-",
419 &c, u);
420 assert_se(r == 0);
421 assert_se(c1->command_next == NULL);
422
423 log_info("/* empty argument, reset */");
424 r = config_parse_exec(NULL, "fake", 4, "section", 1,
425 "LValue", 0, "",
426 &c, u);
427 assert_se(r == 0);
428 assert_se(c == NULL);
429
430 exec_command_free_list(c);
431 }
432
433 static void test_config_parse_log_extra_fields(void) {
434 /* int config_parse_log_extra_fields(
435 const char *unit,
436 const char *filename,
437 unsigned line,
438 const char *section,
439 unsigned section_line,
440 const char *lvalue,
441 int ltype,
442 const char *rvalue,
443 void *data,
444 void *userdata) */
445
446 int r;
447
448 _cleanup_(manager_freep) Manager *m = NULL;
449 _cleanup_(unit_freep) Unit *u = NULL;
450 ExecContext c = {};
451
452 r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_MINIMAL, &m);
453 if (MANAGER_SKIP_TEST(r)) {
454 log_notice_errno(r, "Skipping test: manager_new: %m");
455 return;
456 }
457
458 assert_se(r >= 0);
459 assert_se(manager_startup(m, NULL, NULL) >= 0);
460
461 assert_se(u = unit_new(m, sizeof(Service)));
462
463 log_info("/* %s – basic test */", __func__);
464 r = config_parse_log_extra_fields(NULL, "fake", 1, "section", 1,
465 "LValue", 0, "FOO=BAR \"QOOF=quux ' ' \"",
466 &c, u);
467 assert_se(r >= 0);
468 assert_se(c.n_log_extra_fields == 2);
469 assert_se(strneq(c.log_extra_fields[0].iov_base, "FOO=BAR", c.log_extra_fields[0].iov_len));
470 assert_se(strneq(c.log_extra_fields[1].iov_base, "QOOF=quux ' ' ", c.log_extra_fields[1].iov_len));
471
472 log_info("/* %s – add some */", __func__);
473 r = config_parse_log_extra_fields(NULL, "fake", 1, "section", 1,
474 "LValue", 0, "FOO2=BAR2 QOOF2=quux ' '",
475 &c, u);
476 assert_se(r >= 0);
477 assert_se(c.n_log_extra_fields == 4);
478 assert_se(strneq(c.log_extra_fields[0].iov_base, "FOO=BAR", c.log_extra_fields[0].iov_len));
479 assert_se(strneq(c.log_extra_fields[1].iov_base, "QOOF=quux ' ' ", c.log_extra_fields[1].iov_len));
480 assert_se(strneq(c.log_extra_fields[2].iov_base, "FOO2=BAR2", c.log_extra_fields[2].iov_len));
481 assert_se(strneq(c.log_extra_fields[3].iov_base, "QOOF2=quux", c.log_extra_fields[3].iov_len));
482
483 exec_context_dump(&c, stdout, " --> ");
484
485 log_info("/* %s – reset */", __func__);
486 r = config_parse_log_extra_fields(NULL, "fake", 1, "section", 1,
487 "LValue", 0, "",
488 &c, u);
489 assert_se(r >= 0);
490 assert_se(c.n_log_extra_fields == 0);
491
492 exec_context_free_log_extra_fields(&c);
493
494 log_info("/* %s – bye */", __func__);
495 }
496
497 #define env_file_1 \
498 "a=a\n" \
499 "b=b\\\n" \
500 "c\n" \
501 "d=d\\\n" \
502 "e\\\n" \
503 "f\n" \
504 "g=g\\ \n" \
505 "h=h\n" \
506 "i=i\\"
507
508 #define env_file_2 \
509 "a=a\\\n"
510
511 #define env_file_3 \
512 "#SPAMD_ARGS=\"-d --socketpath=/var/lib/bulwark/spamd \\\n" \
513 "#--nouser-config \\\n" \
514 "normal=line"
515
516 #define env_file_4 \
517 "# Generated\n" \
518 "\n" \
519 "HWMON_MODULES=\"coretemp f71882fg\"\n" \
520 "\n" \
521 "# For compatibility reasons\n" \
522 "\n" \
523 "MODULE_0=coretemp\n" \
524 "MODULE_1=f71882fg"
525
526 #define env_file_5 \
527 "a=\n" \
528 "b="
529
530 static void test_load_env_file_1(void) {
531 _cleanup_strv_free_ char **data = NULL;
532 int r;
533
534 _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-load-env-file.XXXXXX";
535 _cleanup_close_ int fd;
536
537 fd = mkostemp_safe(name);
538 assert_se(fd >= 0);
539 assert_se(write(fd, env_file_1, sizeof(env_file_1)) == sizeof(env_file_1));
540
541 r = load_env_file(NULL, name, NULL, &data);
542 assert_se(r == 0);
543 assert_se(streq(data[0], "a=a"));
544 assert_se(streq(data[1], "b=bc"));
545 assert_se(streq(data[2], "d=def"));
546 assert_se(streq(data[3], "g=g "));
547 assert_se(streq(data[4], "h=h"));
548 assert_se(streq(data[5], "i=i"));
549 assert_se(data[6] == NULL);
550 }
551
552 static void test_load_env_file_2(void) {
553 _cleanup_strv_free_ char **data = NULL;
554 int r;
555
556 _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-load-env-file.XXXXXX";
557 _cleanup_close_ int fd;
558
559 fd = mkostemp_safe(name);
560 assert_se(fd >= 0);
561 assert_se(write(fd, env_file_2, sizeof(env_file_2)) == sizeof(env_file_2));
562
563 r = load_env_file(NULL, name, NULL, &data);
564 assert_se(r == 0);
565 assert_se(streq(data[0], "a=a"));
566 assert_se(data[1] == NULL);
567 }
568
569 static void test_load_env_file_3(void) {
570 _cleanup_strv_free_ char **data = NULL;
571 int r;
572
573 _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-load-env-file.XXXXXX";
574 _cleanup_close_ int fd;
575
576 fd = mkostemp_safe(name);
577 assert_se(fd >= 0);
578 assert_se(write(fd, env_file_3, sizeof(env_file_3)) == sizeof(env_file_3));
579
580 r = load_env_file(NULL, name, NULL, &data);
581 assert_se(r == 0);
582 assert_se(data == NULL);
583 }
584
585 static void test_load_env_file_4(void) {
586 _cleanup_strv_free_ char **data = NULL;
587 _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-load-env-file.XXXXXX";
588 _cleanup_close_ int fd;
589 int r;
590
591 fd = mkostemp_safe(name);
592 assert_se(fd >= 0);
593 assert_se(write(fd, env_file_4, sizeof(env_file_4)) == sizeof(env_file_4));
594
595 r = load_env_file(NULL, name, NULL, &data);
596 assert_se(r == 0);
597 assert_se(streq(data[0], "HWMON_MODULES=coretemp f71882fg"));
598 assert_se(streq(data[1], "MODULE_0=coretemp"));
599 assert_se(streq(data[2], "MODULE_1=f71882fg"));
600 assert_se(data[3] == NULL);
601 }
602
603 static void test_load_env_file_5(void) {
604 _cleanup_strv_free_ char **data = NULL;
605 int r;
606
607 _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-load-env-file.XXXXXX";
608 _cleanup_close_ int fd;
609
610 fd = mkostemp_safe(name);
611 assert_se(fd >= 0);
612 assert_se(write(fd, env_file_5, sizeof(env_file_5)) == sizeof(env_file_5));
613
614 r = load_env_file(NULL, name, NULL, &data);
615 assert_se(r == 0);
616 assert_se(streq(data[0], "a="));
617 assert_se(streq(data[1], "b="));
618 assert_se(data[2] == NULL);
619 }
620
621 static void test_install_printf(void) {
622 char name[] = "name.service",
623 path[] = "/run/systemd/system/name.service";
624 UnitFileInstallInfo i = { .name = name, .path = path, };
625 UnitFileInstallInfo i2 = { .name= name, .path = path, };
626 char name3[] = "name@inst.service",
627 path3[] = "/run/systemd/system/name.service";
628 UnitFileInstallInfo i3 = { .name = name3, .path = path3, };
629 UnitFileInstallInfo i4 = { .name = name3, .path = path3, };
630
631 _cleanup_free_ char *mid = NULL, *bid = NULL, *host = NULL, *uid = NULL, *user = NULL;
632
633 assert_se(specifier_machine_id('m', NULL, NULL, &mid) >= 0 && mid);
634 assert_se(specifier_boot_id('b', NULL, NULL, &bid) >= 0 && bid);
635 assert_se(host = gethostname_malloc());
636 assert_se(user = uid_to_name(getuid()));
637 assert_se(asprintf(&uid, UID_FMT, getuid()) >= 0);
638
639 #define expect(src, pattern, result) \
640 do { \
641 _cleanup_free_ char *t = NULL; \
642 _cleanup_free_ char \
643 *d1 = strdup(i.name), \
644 *d2 = strdup(i.path); \
645 assert_se(install_full_printf(&src, pattern, &t) >= 0 || !result); \
646 memzero(i.name, strlen(i.name)); \
647 memzero(i.path, strlen(i.path)); \
648 assert_se(d1 && d2); \
649 if (result) { \
650 printf("%s\n", t); \
651 assert_se(streq(t, result)); \
652 } else assert_se(t == NULL); \
653 strcpy(i.name, d1); \
654 strcpy(i.path, d2); \
655 } while (false)
656
657 expect(i, "%n", "name.service");
658 expect(i, "%N", "name");
659 expect(i, "%p", "name");
660 expect(i, "%i", "");
661 expect(i, "%j", "name");
662 expect(i, "%u", user);
663 expect(i, "%U", uid);
664
665 expect(i, "%m", mid);
666 expect(i, "%b", bid);
667 expect(i, "%H", host);
668
669 expect(i2, "%u", user);
670 expect(i2, "%U", uid);
671
672 expect(i3, "%n", "name@inst.service");
673 expect(i3, "%N", "name@inst");
674 expect(i3, "%p", "name");
675 expect(i3, "%u", user);
676 expect(i3, "%U", uid);
677
678 expect(i3, "%m", mid);
679 expect(i3, "%b", bid);
680 expect(i3, "%H", host);
681
682 expect(i4, "%u", user);
683 expect(i4, "%U", uid);
684 }
685
686 static uint64_t make_cap(int cap) {
687 return ((uint64_t) 1ULL << (uint64_t) cap);
688 }
689
690 static void test_config_parse_capability_set(void) {
691 /* int config_parse_capability_set(
692 const char *unit,
693 const char *filename,
694 unsigned line,
695 const char *section,
696 unsigned section_line,
697 const char *lvalue,
698 int ltype,
699 const char *rvalue,
700 void *data,
701 void *userdata) */
702 int r;
703 uint64_t capability_bounding_set = 0;
704
705 r = config_parse_capability_set(NULL, "fake", 1, "section", 1,
706 "CapabilityBoundingSet", 0, "CAP_NET_RAW",
707 &capability_bounding_set, NULL);
708 assert_se(r >= 0);
709 assert_se(capability_bounding_set == make_cap(CAP_NET_RAW));
710
711 r = config_parse_capability_set(NULL, "fake", 1, "section", 1,
712 "CapabilityBoundingSet", 0, "CAP_NET_ADMIN",
713 &capability_bounding_set, NULL);
714 assert_se(r >= 0);
715 assert_se(capability_bounding_set == (make_cap(CAP_NET_RAW) | make_cap(CAP_NET_ADMIN)));
716
717 r = config_parse_capability_set(NULL, "fake", 1, "section", 1,
718 "CapabilityBoundingSet", 0, "~CAP_NET_ADMIN",
719 &capability_bounding_set, NULL);
720 assert_se(r >= 0);
721 assert_se(capability_bounding_set == make_cap(CAP_NET_RAW));
722
723 r = config_parse_capability_set(NULL, "fake", 1, "section", 1,
724 "CapabilityBoundingSet", 0, "",
725 &capability_bounding_set, NULL);
726 assert_se(r >= 0);
727 assert_se(capability_bounding_set == UINT64_C(0));
728
729 r = config_parse_capability_set(NULL, "fake", 1, "section", 1,
730 "CapabilityBoundingSet", 0, "~",
731 &capability_bounding_set, NULL);
732 assert_se(r >= 0);
733 assert_se(cap_test_all(capability_bounding_set));
734
735 capability_bounding_set = 0;
736 r = config_parse_capability_set(NULL, "fake", 1, "section", 1,
737 "CapabilityBoundingSet", 0, " 'CAP_NET_RAW' WAT_CAP??? CAP_NET_ADMIN CAP'_trailing_garbage",
738 &capability_bounding_set, NULL);
739 assert_se(r >= 0);
740 assert_se(capability_bounding_set == (make_cap(CAP_NET_RAW) | make_cap(CAP_NET_ADMIN)));
741 }
742
743 static void test_config_parse_rlimit(void) {
744 struct rlimit * rl[_RLIMIT_MAX] = {};
745
746 assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "55", rl, NULL) >= 0);
747 assert_se(rl[RLIMIT_NOFILE]);
748 assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 55);
749 assert_se(rl[RLIMIT_NOFILE]->rlim_cur == rl[RLIMIT_NOFILE]->rlim_max);
750
751 assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "55:66", rl, NULL) >= 0);
752 assert_se(rl[RLIMIT_NOFILE]);
753 assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 55);
754 assert_se(rl[RLIMIT_NOFILE]->rlim_max == 66);
755
756 assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "infinity", rl, NULL) >= 0);
757 assert_se(rl[RLIMIT_NOFILE]);
758 assert_se(rl[RLIMIT_NOFILE]->rlim_cur == RLIM_INFINITY);
759 assert_se(rl[RLIMIT_NOFILE]->rlim_cur == rl[RLIMIT_NOFILE]->rlim_max);
760
761 assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "infinity:infinity", rl, NULL) >= 0);
762 assert_se(rl[RLIMIT_NOFILE]);
763 assert_se(rl[RLIMIT_NOFILE]->rlim_cur == RLIM_INFINITY);
764 assert_se(rl[RLIMIT_NOFILE]->rlim_cur == rl[RLIMIT_NOFILE]->rlim_max);
765
766 rl[RLIMIT_NOFILE]->rlim_cur = 10;
767 rl[RLIMIT_NOFILE]->rlim_max = 20;
768
769 /* Invalid values don't change rl */
770 assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "10:20:30", rl, NULL) >= 0);
771 assert_se(rl[RLIMIT_NOFILE]);
772 assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 10);
773 assert_se(rl[RLIMIT_NOFILE]->rlim_max == 20);
774
775 assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "wat:wat", rl, NULL) >= 0);
776 assert_se(rl[RLIMIT_NOFILE]);
777 assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 10);
778 assert_se(rl[RLIMIT_NOFILE]->rlim_max == 20);
779
780 assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "66:wat", rl, NULL) >= 0);
781 assert_se(rl[RLIMIT_NOFILE]);
782 assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 10);
783 assert_se(rl[RLIMIT_NOFILE]->rlim_max == 20);
784
785 assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "200:100", rl, NULL) >= 0);
786 assert_se(rl[RLIMIT_NOFILE]);
787 assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 10);
788 assert_se(rl[RLIMIT_NOFILE]->rlim_max == 20);
789
790 rl[RLIMIT_NOFILE] = mfree(rl[RLIMIT_NOFILE]);
791
792 assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "56", rl, NULL) >= 0);
793 assert_se(rl[RLIMIT_CPU]);
794 assert_se(rl[RLIMIT_CPU]->rlim_cur == 56);
795 assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max);
796
797 assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "57s", rl, NULL) >= 0);
798 assert_se(rl[RLIMIT_CPU]);
799 assert_se(rl[RLIMIT_CPU]->rlim_cur == 57);
800 assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max);
801
802 assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "40s:1m", rl, NULL) >= 0);
803 assert_se(rl[RLIMIT_CPU]);
804 assert_se(rl[RLIMIT_CPU]->rlim_cur == 40);
805 assert_se(rl[RLIMIT_CPU]->rlim_max == 60);
806
807 assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "infinity", rl, NULL) >= 0);
808 assert_se(rl[RLIMIT_CPU]);
809 assert_se(rl[RLIMIT_CPU]->rlim_cur == RLIM_INFINITY);
810 assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max);
811
812 assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "1234ms", rl, NULL) >= 0);
813 assert_se(rl[RLIMIT_CPU]);
814 assert_se(rl[RLIMIT_CPU]->rlim_cur == 2);
815 assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max);
816
817 rl[RLIMIT_CPU] = mfree(rl[RLIMIT_CPU]);
818
819 assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "58", rl, NULL) >= 0);
820 assert_se(rl[RLIMIT_RTTIME]);
821 assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 58);
822 assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max);
823
824 assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "58:60", rl, NULL) >= 0);
825 assert_se(rl[RLIMIT_RTTIME]);
826 assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 58);
827 assert_se(rl[RLIMIT_RTTIME]->rlim_max == 60);
828
829 assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "59s", rl, NULL) >= 0);
830 assert_se(rl[RLIMIT_RTTIME]);
831 assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 59 * USEC_PER_SEC);
832 assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max);
833
834 assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "59s:123s", rl, NULL) >= 0);
835 assert_se(rl[RLIMIT_RTTIME]);
836 assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 59 * USEC_PER_SEC);
837 assert_se(rl[RLIMIT_RTTIME]->rlim_max == 123 * USEC_PER_SEC);
838
839 assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "infinity", rl, NULL) >= 0);
840 assert_se(rl[RLIMIT_RTTIME]);
841 assert_se(rl[RLIMIT_RTTIME]->rlim_cur == RLIM_INFINITY);
842 assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max);
843
844 assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "infinity:infinity", rl, NULL) >= 0);
845 assert_se(rl[RLIMIT_RTTIME]);
846 assert_se(rl[RLIMIT_RTTIME]->rlim_cur == RLIM_INFINITY);
847 assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max);
848
849 assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "2345ms", rl, NULL) >= 0);
850 assert_se(rl[RLIMIT_RTTIME]);
851 assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 2345 * USEC_PER_MSEC);
852 assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max);
853
854 rl[RLIMIT_RTTIME] = mfree(rl[RLIMIT_RTTIME]);
855 }
856
857 static void test_config_parse_pass_environ(void) {
858 /* int config_parse_pass_environ(
859 const char *unit,
860 const char *filename,
861 unsigned line,
862 const char *section,
863 unsigned section_line,
864 const char *lvalue,
865 int ltype,
866 const char *rvalue,
867 void *data,
868 void *userdata) */
869 int r;
870 _cleanup_strv_free_ char **passenv = NULL;
871
872 r = config_parse_pass_environ(NULL, "fake", 1, "section", 1,
873 "PassEnvironment", 0, "A B",
874 &passenv, NULL);
875 assert_se(r >= 0);
876 assert_se(strv_length(passenv) == 2);
877 assert_se(streq(passenv[0], "A"));
878 assert_se(streq(passenv[1], "B"));
879
880 r = config_parse_pass_environ(NULL, "fake", 1, "section", 1,
881 "PassEnvironment", 0, "",
882 &passenv, NULL);
883 assert_se(r >= 0);
884 assert_se(strv_isempty(passenv));
885
886 r = config_parse_pass_environ(NULL, "fake", 1, "section", 1,
887 "PassEnvironment", 0, "'invalid name' 'normal_name' A=1 \\",
888 &passenv, NULL);
889 assert_se(r >= 0);
890 assert_se(strv_length(passenv) == 1);
891 assert_se(streq(passenv[0], "normal_name"));
892
893 }
894
895 static void test_unit_dump_config_items(void) {
896 unit_dump_config_items(stdout);
897 }
898
899 int main(int argc, char *argv[]) {
900 _cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL;
901 int r;
902
903 log_parse_environment();
904 log_open();
905
906 r = enter_cgroup_subroot();
907 if (r == -ENOMEDIUM) {
908 log_notice_errno(r, "Skipping test: cgroupfs not available");
909 return EXIT_TEST_SKIP;
910 }
911
912 assert_se(runtime_dir = setup_fake_runtime_dir());
913
914 r = test_unit_file_get_set();
915 test_config_parse_exec();
916 test_config_parse_log_extra_fields();
917 test_config_parse_capability_set();
918 test_config_parse_rlimit();
919 test_config_parse_pass_environ();
920 test_load_env_file_1();
921 test_load_env_file_2();
922 test_load_env_file_3();
923 test_load_env_file_4();
924 test_load_env_file_5();
925 TEST_REQ_RUNNING_SYSTEMD(test_install_printf());
926 test_unit_dump_config_items();
927
928 return r;
929 }