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