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