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