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