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