]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/test/test-load-fragment.c
core: add OpenFile setting
[thirdparty/systemd.git] / src / test / test-load-fragment.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <fcntl.h>
4 #include <stddef.h>
5 #include <stdio.h>
6 #include <unistd.h>
7
8 #include "sd-id128.h"
9
10 #include "all-units.h"
11 #include "alloc-util.h"
12 #include "capability-util.h"
13 #include "conf-parser.h"
14 #include "fd-util.h"
15 #include "fileio.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 "open-file.h"
26 #include "pcre2-util.h"
27 #include "rm-rf.h"
28 #include "specifier.h"
29 #include "string-util.h"
30 #include "strv.h"
31 #include "tests.h"
32 #include "tmpfile-util.h"
33 #include "user-util.h"
34
35 /* Nontrivial value serves as a placeholder to check that parsing function (didn't) change it */
36 #define CGROUP_LIMIT_DUMMY 3
37
38 static char *runtime_dir = NULL;
39
40 STATIC_DESTRUCTOR_REGISTER(runtime_dir, rm_rf_physical_and_freep);
41
42 TEST_RET(unit_file_get_set) {
43 int r;
44 Hashmap *h;
45 UnitFileList *p;
46
47 h = hashmap_new(&string_hash_ops);
48 assert_se(h);
49
50 r = unit_file_get_list(LOOKUP_SCOPE_SYSTEM, NULL, h, NULL, NULL);
51 if (IN_SET(r, -EPERM, -EACCES))
52 return log_tests_skipped_errno(r, "unit_file_get_list");
53
54 log_full_errno(r == 0 ? LOG_INFO : LOG_ERR, r,
55 "unit_file_get_list: %m");
56 if (r < 0)
57 return EXIT_FAILURE;
58
59 HASHMAP_FOREACH(p, h)
60 printf("%s = %s\n", p->path, unit_file_state_to_string(p->state));
61
62 unit_file_list_free(h);
63
64 return 0;
65 }
66
67 static void check_execcommand(ExecCommand *c,
68 const char* path,
69 const char* argv0,
70 const char* argv1,
71 const char* argv2,
72 bool ignore) {
73 size_t n;
74
75 assert_se(c);
76 log_info("expect: \"%s\" [\"%s\" \"%s\" \"%s\"]",
77 path, argv0 ?: path, strnull(argv1), strnull(argv2));
78 n = strv_length(c->argv);
79 log_info("actual: \"%s\" [\"%s\" \"%s\" \"%s\"]",
80 c->path, c->argv[0], n > 0 ? c->argv[1] : "(null)", n > 1 ? c->argv[2] : "(null)");
81 assert_se(streq(c->path, path));
82 assert_se(streq(c->argv[0], argv0 ?: path));
83 if (n > 0)
84 assert_se(streq_ptr(c->argv[1], argv1));
85 if (n > 1)
86 assert_se(streq_ptr(c->argv[2], argv2));
87 assert_se(!!(c->flags & EXEC_COMMAND_IGNORE_FAILURE) == ignore);
88 }
89
90 TEST(config_parse_exec) {
91 /* int config_parse_exec(
92 const char *unit,
93 const char *filename,
94 unsigned line,
95 const char *section,
96 unsigned section_line,
97 const char *lvalue,
98 int ltype,
99 const char *rvalue,
100 void *data,
101 void *userdata) */
102 int r;
103
104 ExecCommand *c = NULL, *c1;
105 const char *ccc;
106 _cleanup_(manager_freep) Manager *m = NULL;
107 _cleanup_(unit_freep) Unit *u = NULL;
108
109 r = manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_MINIMAL, &m);
110 if (manager_errno_skip_test(r)) {
111 log_notice_errno(r, "Skipping test: manager_new: %m");
112 return;
113 }
114
115 assert_se(r >= 0);
116 assert_se(manager_startup(m, NULL, NULL, NULL) >= 0);
117
118 assert_se(u = unit_new(m, sizeof(Service)));
119
120 log_info("/* basic test */");
121 r = config_parse_exec(NULL, "fake", 1, "section", 1,
122 "LValue", 0, "/RValue r1",
123 &c, u);
124 assert_se(r >= 0);
125 check_execcommand(c, "/RValue", "/RValue", "r1", NULL, false);
126
127 r = config_parse_exec(NULL, "fake", 2, "section", 1,
128 "LValue", 0, "/RValue///slashes r1///",
129 &c, u);
130
131 log_info("/* test slashes */");
132 assert_se(r >= 0);
133 c1 = c->command_next;
134 check_execcommand(c1, "/RValue/slashes", "/RValue///slashes", "r1///", NULL, false);
135
136 log_info("/* trailing slash */");
137 r = config_parse_exec(NULL, "fake", 4, "section", 1,
138 "LValue", 0, "/RValue/ argv0 r1",
139 &c, u);
140 assert_se(r == -ENOEXEC);
141 assert_se(c1->command_next == NULL);
142
143 log_info("/* honour_argv0 */");
144 r = config_parse_exec(NULL, "fake", 3, "section", 1,
145 "LValue", 0, "@/RValue///slashes2 ///argv0 r1",
146 &c, u);
147 assert_se(r >= 0);
148 c1 = c1->command_next;
149 check_execcommand(c1, "/RValue/slashes2", "///argv0", "r1", NULL, false);
150
151 log_info("/* honour_argv0, no args */");
152 r = config_parse_exec(NULL, "fake", 3, "section", 1,
153 "LValue", 0, "@/RValue",
154 &c, u);
155 assert_se(r == -ENOEXEC);
156 assert_se(c1->command_next == NULL);
157
158 log_info("/* no command, whitespace only, reset */");
159 r = config_parse_exec(NULL, "fake", 3, "section", 1,
160 "LValue", 0, "",
161 &c, u);
162 assert_se(r == 0);
163 assert_se(c == NULL);
164
165 log_info("/* ignore && honour_argv0 */");
166 r = config_parse_exec(NULL, "fake", 4, "section", 1,
167 "LValue", 0, "-@/RValue///slashes3 argv0a r1",
168 &c, u);
169 assert_se(r >= 0);
170 c1 = c;
171 check_execcommand(c1, "/RValue/slashes3", "argv0a", "r1", NULL, true);
172
173 log_info("/* ignore && honour_argv0 */");
174 r = config_parse_exec(NULL, "fake", 4, "section", 1,
175 "LValue", 0, "@-/RValue///slashes4 argv0b r1",
176 &c, u);
177 assert_se(r >= 0);
178 c1 = c1->command_next;
179 check_execcommand(c1, "/RValue/slashes4", "argv0b", "r1", NULL, true);
180
181 log_info("/* ignore && ignore */");
182 r = config_parse_exec(NULL, "fake", 4, "section", 1,
183 "LValue", 0, "--/RValue argv0 r1",
184 &c, u);
185 assert_se(r == 0);
186 assert_se(c1->command_next == NULL);
187
188 log_info("/* ignore && ignore (2) */");
189 r = config_parse_exec(NULL, "fake", 4, "section", 1,
190 "LValue", 0, "-@-/RValue argv0 r1",
191 &c, u);
192 assert_se(r == 0);
193 assert_se(c1->command_next == NULL);
194
195 log_info("/* semicolon */");
196 r = config_parse_exec(NULL, "fake", 5, "section", 1,
197 "LValue", 0,
198 "-@/RValue argv0 r1 ; "
199 "/goo/goo boo",
200 &c, u);
201 assert_se(r >= 0);
202 c1 = c1->command_next;
203 check_execcommand(c1, "/RValue", "argv0", "r1", NULL, true);
204
205 c1 = c1->command_next;
206 check_execcommand(c1, "/goo/goo", NULL, "boo", NULL, false);
207
208 log_info("/* two semicolons in a row */");
209 r = config_parse_exec(NULL, "fake", 5, "section", 1,
210 "LValue", 0,
211 "-@/RValue argv0 r1 ; ; "
212 "/goo/goo boo",
213 &c, u);
214 assert_se(r >= 0);
215 c1 = c1->command_next;
216 check_execcommand(c1, "/RValue", "argv0", "r1", NULL, true);
217 c1 = c1->command_next;
218 check_execcommand(c1, "/goo/goo", "/goo/goo", "boo", NULL, false);
219
220 log_info("/* trailing semicolon */");
221 r = config_parse_exec(NULL, "fake", 5, "section", 1,
222 "LValue", 0,
223 "-@/RValue argv0 r1 ; ",
224 &c, u);
225 assert_se(r >= 0);
226 c1 = c1->command_next;
227 check_execcommand(c1, "/RValue", "argv0", "r1", NULL, true);
228
229 assert_se(c1->command_next == NULL);
230
231 log_info("/* trailing semicolon, no whitespace */");
232 r = config_parse_exec(NULL, "fake", 5, "section", 1,
233 "LValue", 0,
234 "-@/RValue argv0 r1 ;",
235 &c, u);
236 assert_se(r >= 0);
237 c1 = c1->command_next;
238 check_execcommand(c1, "/RValue", "argv0", "r1", NULL, true);
239
240 assert_se(c1->command_next == NULL);
241
242 log_info("/* trailing semicolon in single quotes */");
243 r = config_parse_exec(NULL, "fake", 5, "section", 1,
244 "LValue", 0,
245 "-@/RValue argv0 r1 ';'",
246 &c, u);
247 assert_se(r >= 0);
248 c1 = c1->command_next;
249 check_execcommand(c1, "/RValue", "argv0", "r1", ";", true);
250
251 log_info("/* escaped semicolon */");
252 r = config_parse_exec(NULL, "fake", 5, "section", 1,
253 "LValue", 0,
254 "/bin/find \\;",
255 &c, u);
256 assert_se(r >= 0);
257 c1 = c1->command_next;
258 check_execcommand(c1, "/bin/find", NULL, ";", NULL, false);
259
260 log_info("/* escaped semicolon with following arg */");
261 r = config_parse_exec(NULL, "fake", 5, "section", 1,
262 "LValue", 0,
263 "/sbin/find \\; /x",
264 &c, u);
265 assert_se(r >= 0);
266 c1 = c1->command_next;
267 check_execcommand(c1,
268 "/sbin/find", NULL, ";", "/x", false);
269
270 log_info("/* escaped semicolon as part of an expression */");
271 r = config_parse_exec(NULL, "fake", 5, "section", 1,
272 "LValue", 0,
273 "/sbin/find \\;x",
274 &c, u);
275 assert_se(r >= 0);
276 c1 = c1->command_next;
277 check_execcommand(c1,
278 "/sbin/find", NULL, "\\;x", NULL, false);
279
280 log_info("/* encoded semicolon */");
281 r = config_parse_exec(NULL, "fake", 5, "section", 1,
282 "LValue", 0,
283 "/bin/find \\073",
284 &c, u);
285 assert_se(r >= 0);
286 c1 = c1->command_next;
287 check_execcommand(c1, "/bin/find", NULL, ";", NULL, false);
288
289 log_info("/* quoted semicolon */");
290 r = config_parse_exec(NULL, "fake", 5, "section", 1,
291 "LValue", 0,
292 "/bin/find \";\"",
293 &c, u);
294 assert_se(r >= 0);
295 c1 = c1->command_next;
296 check_execcommand(c1, "/bin/find", NULL, ";", NULL, false);
297
298 log_info("/* quoted semicolon with following arg */");
299 r = config_parse_exec(NULL, "fake", 5, "section", 1,
300 "LValue", 0,
301 "/sbin/find \";\" /x",
302 &c, u);
303 assert_se(r >= 0);
304 c1 = c1->command_next;
305 check_execcommand(c1,
306 "/sbin/find", NULL, ";", "/x", false);
307
308 log_info("/* spaces in the filename */");
309 r = config_parse_exec(NULL, "fake", 5, "section", 1,
310 "LValue", 0,
311 "\"/PATH WITH SPACES/daemon\" -1 -2",
312 &c, u);
313 assert_se(r >= 0);
314 c1 = c1->command_next;
315 check_execcommand(c1,
316 "/PATH WITH SPACES/daemon", NULL, "-1", "-2", false);
317
318 log_info("/* spaces in the filename, no args */");
319 r = config_parse_exec(NULL, "fake", 5, "section", 1,
320 "LValue", 0,
321 "\"/PATH WITH SPACES/daemon -1 -2\"",
322 &c, u);
323 assert_se(r >= 0);
324 c1 = c1->command_next;
325 check_execcommand(c1,
326 "/PATH WITH SPACES/daemon -1 -2", NULL, NULL, NULL, false);
327
328 log_info("/* spaces in the filename, everything quoted */");
329 r = config_parse_exec(NULL, "fake", 5, "section", 1,
330 "LValue", 0,
331 "\"/PATH WITH SPACES/daemon\" \"-1\" '-2'",
332 &c, u);
333 assert_se(r >= 0);
334 c1 = c1->command_next;
335 check_execcommand(c1,
336 "/PATH WITH SPACES/daemon", NULL, "-1", "-2", false);
337
338 log_info("/* escaped spaces in the filename */");
339 r = config_parse_exec(NULL, "fake", 5, "section", 1,
340 "LValue", 0,
341 "\"/PATH\\sWITH\\sSPACES/daemon\" '-1 -2'",
342 &c, u);
343 assert_se(r >= 0);
344 c1 = c1->command_next;
345 check_execcommand(c1,
346 "/PATH WITH SPACES/daemon", NULL, "-1 -2", NULL, false);
347
348 log_info("/* escaped spaces in the filename (2) */");
349 r = config_parse_exec(NULL, "fake", 5, "section", 1,
350 "LValue", 0,
351 "\"/PATH\\x20WITH\\x20SPACES/daemon\" \"-1 -2\"",
352 &c, u);
353 assert_se(r >= 0);
354 c1 = c1->command_next;
355 check_execcommand(c1,
356 "/PATH WITH SPACES/daemon", NULL, "-1 -2", NULL, false);
357
358 for (ccc = "abfnrtv\\\'\"x"; *ccc; ccc++) {
359 /* \\x is an incomplete hexadecimal sequence, invalid because of the slash */
360 char path[] = "/path\\X";
361 path[sizeof(path) - 2] = *ccc;
362
363 log_info("/* invalid character: \\%c */", *ccc);
364 r = config_parse_exec(NULL, "fake", 4, "section", 1,
365 "LValue", 0, path,
366 &c, u);
367 assert_se(r == -ENOEXEC);
368 assert_se(c1->command_next == NULL);
369 }
370
371 log_info("/* valid character: \\s */");
372 r = config_parse_exec(NULL, "fake", 4, "section", 1,
373 "LValue", 0, "/path\\s",
374 &c, u);
375 assert_se(r >= 0);
376 c1 = c1->command_next;
377 check_execcommand(c1, "/path ", NULL, NULL, NULL, false);
378
379 log_info("/* quoted backslashes */");
380 r = config_parse_exec(NULL, "fake", 5, "section", 1,
381 "LValue", 0,
382 "/bin/grep '\\w+\\K'",
383 &c, u);
384 assert_se(r >= 0);
385 c1 = c1->command_next;
386 check_execcommand(c1, "/bin/grep", NULL, "\\w+\\K", NULL, false);
387
388 log_info("/* trailing backslash: \\ */");
389 /* backslash is invalid */
390 r = config_parse_exec(NULL, "fake", 4, "section", 1,
391 "LValue", 0, "/path\\",
392 &c, u);
393 assert_se(r == -ENOEXEC);
394 assert_se(c1->command_next == NULL);
395
396 log_info("/* missing ending ' */");
397 r = config_parse_exec(NULL, "fake", 4, "section", 1,
398 "LValue", 0, "/path 'foo",
399 &c, u);
400 assert_se(r == -ENOEXEC);
401 assert_se(c1->command_next == NULL);
402
403 log_info("/* missing ending ' with trailing backslash */");
404 r = config_parse_exec(NULL, "fake", 4, "section", 1,
405 "LValue", 0, "/path 'foo\\",
406 &c, u);
407 assert_se(r == -ENOEXEC);
408 assert_se(c1->command_next == NULL);
409
410 log_info("/* invalid space between modifiers */");
411 r = config_parse_exec(NULL, "fake", 4, "section", 1,
412 "LValue", 0, "- /path",
413 &c, u);
414 assert_se(r == 0);
415 assert_se(c1->command_next == NULL);
416
417 log_info("/* only modifiers, no path */");
418 r = config_parse_exec(NULL, "fake", 4, "section", 1,
419 "LValue", 0, "-",
420 &c, u);
421 assert_se(r == 0);
422 assert_se(c1->command_next == NULL);
423
424 log_info("/* long arg */"); /* See issue #22957. */
425
426 char x[LONG_LINE_MAX-100], *y;
427 y = mempcpy(x, "/bin/echo ", STRLEN("/bin/echo "));
428 memset(y, 'x', sizeof(x) - STRLEN("/bin/echo ") - 1);
429 x[sizeof(x) - 1] = '\0';
430
431 r = config_parse_exec(NULL, "fake", 5, "section", 1,
432 "LValue", 0, x,
433 &c, u);
434 assert_se(r >= 0);
435 c1 = c1->command_next;
436 check_execcommand(c1,
437 "/bin/echo", NULL, y, NULL, false);
438
439 log_info("/* empty argument, reset */");
440 r = config_parse_exec(NULL, "fake", 4, "section", 1,
441 "LValue", 0, "",
442 &c, u);
443 assert_se(r == 0);
444 assert_se(c == NULL);
445
446 exec_command_free_list(c);
447 }
448
449 TEST(config_parse_log_extra_fields) {
450 /* int config_parse_log_extra_fields(
451 const char *unit,
452 const char *filename,
453 unsigned line,
454 const char *section,
455 unsigned section_line,
456 const char *lvalue,
457 int ltype,
458 const char *rvalue,
459 void *data,
460 void *userdata) */
461
462 int r;
463
464 _cleanup_(manager_freep) Manager *m = NULL;
465 _cleanup_(unit_freep) Unit *u = NULL;
466 ExecContext c = {};
467
468 r = manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_MINIMAL, &m);
469 if (manager_errno_skip_test(r)) {
470 log_notice_errno(r, "Skipping test: manager_new: %m");
471 return;
472 }
473
474 assert_se(r >= 0);
475 assert_se(manager_startup(m, NULL, NULL, NULL) >= 0);
476
477 assert_se(u = unit_new(m, sizeof(Service)));
478
479 log_info("/* %s – basic test */", __func__);
480 r = config_parse_log_extra_fields(NULL, "fake", 1, "section", 1,
481 "LValue", 0, "FOO=BAR \"QOOF=quux ' ' \"",
482 &c, u);
483 assert_se(r >= 0);
484 assert_se(c.n_log_extra_fields == 2);
485 assert_se(strneq(c.log_extra_fields[0].iov_base, "FOO=BAR", c.log_extra_fields[0].iov_len));
486 assert_se(strneq(c.log_extra_fields[1].iov_base, "QOOF=quux ' ' ", c.log_extra_fields[1].iov_len));
487
488 log_info("/* %s – add some */", __func__);
489 r = config_parse_log_extra_fields(NULL, "fake", 1, "section", 1,
490 "LValue", 0, "FOO2=BAR2 QOOF2=quux ' '",
491 &c, u);
492 assert_se(r >= 0);
493 assert_se(c.n_log_extra_fields == 4);
494 assert_se(strneq(c.log_extra_fields[0].iov_base, "FOO=BAR", c.log_extra_fields[0].iov_len));
495 assert_se(strneq(c.log_extra_fields[1].iov_base, "QOOF=quux ' ' ", c.log_extra_fields[1].iov_len));
496 assert_se(strneq(c.log_extra_fields[2].iov_base, "FOO2=BAR2", c.log_extra_fields[2].iov_len));
497 assert_se(strneq(c.log_extra_fields[3].iov_base, "QOOF2=quux", c.log_extra_fields[3].iov_len));
498
499 exec_context_dump(&c, stdout, " --> ");
500
501 log_info("/* %s – reset */", __func__);
502 r = config_parse_log_extra_fields(NULL, "fake", 1, "section", 1,
503 "LValue", 0, "",
504 &c, u);
505 assert_se(r >= 0);
506 assert_se(c.n_log_extra_fields == 0);
507
508 exec_context_free_log_extra_fields(&c);
509
510 log_info("/* %s – bye */", __func__);
511 }
512
513 TEST(install_printf, .sd_booted = true) {
514 char name[] = "name.service",
515 path[] = "/run/systemd/system/name.service";
516 InstallInfo i = { .name = name, .path = path, };
517 InstallInfo i2 = { .name= name, .path = path, };
518 char name3[] = "name@inst.service",
519 path3[] = "/run/systemd/system/name.service";
520 InstallInfo i3 = { .name = name3, .path = path3, };
521 InstallInfo i4 = { .name = name3, .path = path3, };
522
523 _cleanup_free_ char *mid = NULL, *bid = NULL, *host = NULL, *gid = NULL, *group = NULL, *uid = NULL, *user = NULL;
524
525 if (sd_id128_get_machine(NULL) >= 0)
526 assert_se(specifier_machine_id('m', NULL, NULL, NULL, &mid) >= 0 && mid);
527 if (sd_booted() > 0)
528 assert_se(specifier_boot_id('b', NULL, NULL, NULL, &bid) >= 0 && bid);
529 assert_se(host = gethostname_malloc());
530 assert_se(group = gid_to_name(getgid()));
531 assert_se(asprintf(&gid, UID_FMT, getgid()) >= 0);
532 assert_se(user = uid_to_name(getuid()));
533 assert_se(asprintf(&uid, UID_FMT, getuid()) >= 0);
534
535 #define expect(scope, src, pattern, result) \
536 do { \
537 _cleanup_free_ char *t = NULL, \
538 *d1 = ASSERT_PTR(strdup(i.name)), \
539 *d2 = ASSERT_PTR(strdup(i.path)); \
540 int r = install_name_printf(scope, &src, pattern, &t); \
541 assert_se(result ? r >= 0 : r < 0); \
542 memzero(i.name, strlen(i.name)); \
543 memzero(i.path, strlen(i.path)); \
544 if (result) { \
545 printf("%s\n", t); \
546 assert_se(streq(t, result)); \
547 } else \
548 assert_se(!t); \
549 strcpy(i.name, d1); \
550 strcpy(i.path, d2); \
551 } while (false)
552
553 expect(LOOKUP_SCOPE_SYSTEM, i, "%n", "name.service");
554 expect(LOOKUP_SCOPE_SYSTEM, i, "%N", "name");
555 expect(LOOKUP_SCOPE_SYSTEM, i, "%p", "name");
556 expect(LOOKUP_SCOPE_SYSTEM, i, "%i", "");
557 expect(LOOKUP_SCOPE_SYSTEM, i, "%j", "name");
558 expect(LOOKUP_SCOPE_SYSTEM, i, "%g", "root");
559 expect(LOOKUP_SCOPE_SYSTEM, i, "%G", "0");
560 expect(LOOKUP_SCOPE_SYSTEM, i, "%u", "root");
561 expect(LOOKUP_SCOPE_SYSTEM, i, "%U", "0");
562
563 expect(LOOKUP_SCOPE_SYSTEM, i, "%m", mid);
564 expect(LOOKUP_SCOPE_SYSTEM, i, "%b", bid);
565 expect(LOOKUP_SCOPE_SYSTEM, i, "%H", host);
566
567 expect(LOOKUP_SCOPE_SYSTEM, i2, "%g", "root");
568 expect(LOOKUP_SCOPE_SYSTEM, i2, "%G", "0");
569 expect(LOOKUP_SCOPE_SYSTEM, i2, "%u", "root");
570 expect(LOOKUP_SCOPE_SYSTEM, i2, "%U", "0");
571
572 expect(LOOKUP_SCOPE_USER, i2, "%g", group);
573 expect(LOOKUP_SCOPE_USER, i2, "%G", gid);
574 expect(LOOKUP_SCOPE_USER, i2, "%u", user);
575 expect(LOOKUP_SCOPE_USER, i2, "%U", uid);
576
577 /* gcc-12.0.1-0.9.fc36.x86_64 insist that streq(…, NULL) is called,
578 * even though the call is inside of a conditional where the pointer is checked. :( */
579 #pragma GCC diagnostic push
580 #pragma GCC diagnostic ignored "-Wnonnull"
581 expect(LOOKUP_SCOPE_GLOBAL, i2, "%g", NULL);
582 expect(LOOKUP_SCOPE_GLOBAL, i2, "%G", NULL);
583 expect(LOOKUP_SCOPE_GLOBAL, i2, "%u", NULL);
584 expect(LOOKUP_SCOPE_GLOBAL, i2, "%U", NULL);
585 #pragma GCC diagnostic pop
586
587 expect(LOOKUP_SCOPE_SYSTEM, i3, "%n", "name@inst.service");
588 expect(LOOKUP_SCOPE_SYSTEM, i3, "%N", "name@inst");
589 expect(LOOKUP_SCOPE_SYSTEM, i3, "%p", "name");
590 expect(LOOKUP_SCOPE_USER, i3, "%g", group);
591 expect(LOOKUP_SCOPE_USER, i3, "%G", gid);
592 expect(LOOKUP_SCOPE_USER, i3, "%u", user);
593 expect(LOOKUP_SCOPE_USER, i3, "%U", uid);
594
595 expect(LOOKUP_SCOPE_SYSTEM, i3, "%m", mid);
596 expect(LOOKUP_SCOPE_SYSTEM, i3, "%b", bid);
597 expect(LOOKUP_SCOPE_SYSTEM, i3, "%H", host);
598
599 expect(LOOKUP_SCOPE_USER, i4, "%g", group);
600 expect(LOOKUP_SCOPE_USER, i4, "%G", gid);
601 expect(LOOKUP_SCOPE_USER, i4, "%u", user);
602 expect(LOOKUP_SCOPE_USER, i4, "%U", uid);
603 }
604
605 static uint64_t make_cap(int cap) {
606 return ((uint64_t) 1ULL << (uint64_t) cap);
607 }
608
609 TEST(config_parse_capability_set) {
610 /* int config_parse_capability_set(
611 const char *unit,
612 const char *filename,
613 unsigned line,
614 const char *section,
615 unsigned section_line,
616 const char *lvalue,
617 int ltype,
618 const char *rvalue,
619 void *data,
620 void *userdata) */
621 int r;
622 uint64_t capability_bounding_set = 0;
623
624 r = config_parse_capability_set(NULL, "fake", 1, "section", 1,
625 "CapabilityBoundingSet", 0, "CAP_NET_RAW",
626 &capability_bounding_set, NULL);
627 assert_se(r >= 0);
628 assert_se(capability_bounding_set == make_cap(CAP_NET_RAW));
629
630 r = config_parse_capability_set(NULL, "fake", 1, "section", 1,
631 "CapabilityBoundingSet", 0, "CAP_NET_ADMIN",
632 &capability_bounding_set, NULL);
633 assert_se(r >= 0);
634 assert_se(capability_bounding_set == (make_cap(CAP_NET_RAW) | make_cap(CAP_NET_ADMIN)));
635
636 r = config_parse_capability_set(NULL, "fake", 1, "section", 1,
637 "CapabilityBoundingSet", 0, "~CAP_NET_ADMIN",
638 &capability_bounding_set, NULL);
639 assert_se(r >= 0);
640 assert_se(capability_bounding_set == make_cap(CAP_NET_RAW));
641
642 r = config_parse_capability_set(NULL, "fake", 1, "section", 1,
643 "CapabilityBoundingSet", 0, "",
644 &capability_bounding_set, NULL);
645 assert_se(r >= 0);
646 assert_se(capability_bounding_set == UINT64_C(0));
647
648 r = config_parse_capability_set(NULL, "fake", 1, "section", 1,
649 "CapabilityBoundingSet", 0, "~",
650 &capability_bounding_set, NULL);
651 assert_se(r >= 0);
652 assert_se(cap_test_all(capability_bounding_set));
653
654 capability_bounding_set = 0;
655 r = config_parse_capability_set(NULL, "fake", 1, "section", 1,
656 "CapabilityBoundingSet", 0, " 'CAP_NET_RAW' WAT_CAP??? CAP_NET_ADMIN CAP'_trailing_garbage",
657 &capability_bounding_set, NULL);
658 assert_se(r >= 0);
659 assert_se(capability_bounding_set == (make_cap(CAP_NET_RAW) | make_cap(CAP_NET_ADMIN)));
660 }
661
662 TEST(config_parse_rlimit) {
663 struct rlimit * rl[_RLIMIT_MAX] = {};
664
665 assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "55", rl, NULL) >= 0);
666 assert_se(rl[RLIMIT_NOFILE]);
667 assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 55);
668 assert_se(rl[RLIMIT_NOFILE]->rlim_cur == rl[RLIMIT_NOFILE]->rlim_max);
669
670 assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "55:66", rl, NULL) >= 0);
671 assert_se(rl[RLIMIT_NOFILE]);
672 assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 55);
673 assert_se(rl[RLIMIT_NOFILE]->rlim_max == 66);
674
675 assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "infinity", rl, NULL) >= 0);
676 assert_se(rl[RLIMIT_NOFILE]);
677 assert_se(rl[RLIMIT_NOFILE]->rlim_cur == RLIM_INFINITY);
678 assert_se(rl[RLIMIT_NOFILE]->rlim_cur == rl[RLIMIT_NOFILE]->rlim_max);
679
680 assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "infinity:infinity", rl, NULL) >= 0);
681 assert_se(rl[RLIMIT_NOFILE]);
682 assert_se(rl[RLIMIT_NOFILE]->rlim_cur == RLIM_INFINITY);
683 assert_se(rl[RLIMIT_NOFILE]->rlim_cur == rl[RLIMIT_NOFILE]->rlim_max);
684
685 rl[RLIMIT_NOFILE]->rlim_cur = 10;
686 rl[RLIMIT_NOFILE]->rlim_max = 20;
687
688 /* Invalid values don't change rl */
689 assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "10:20:30", rl, NULL) >= 0);
690 assert_se(rl[RLIMIT_NOFILE]);
691 assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 10);
692 assert_se(rl[RLIMIT_NOFILE]->rlim_max == 20);
693
694 assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "wat:wat", rl, NULL) >= 0);
695 assert_se(rl[RLIMIT_NOFILE]);
696 assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 10);
697 assert_se(rl[RLIMIT_NOFILE]->rlim_max == 20);
698
699 assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "66:wat", rl, NULL) >= 0);
700 assert_se(rl[RLIMIT_NOFILE]);
701 assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 10);
702 assert_se(rl[RLIMIT_NOFILE]->rlim_max == 20);
703
704 assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "200:100", rl, NULL) >= 0);
705 assert_se(rl[RLIMIT_NOFILE]);
706 assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 10);
707 assert_se(rl[RLIMIT_NOFILE]->rlim_max == 20);
708
709 rl[RLIMIT_NOFILE] = mfree(rl[RLIMIT_NOFILE]);
710
711 assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "56", rl, NULL) >= 0);
712 assert_se(rl[RLIMIT_CPU]);
713 assert_se(rl[RLIMIT_CPU]->rlim_cur == 56);
714 assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max);
715
716 assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "57s", rl, NULL) >= 0);
717 assert_se(rl[RLIMIT_CPU]);
718 assert_se(rl[RLIMIT_CPU]->rlim_cur == 57);
719 assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max);
720
721 assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "40s:1m", rl, NULL) >= 0);
722 assert_se(rl[RLIMIT_CPU]);
723 assert_se(rl[RLIMIT_CPU]->rlim_cur == 40);
724 assert_se(rl[RLIMIT_CPU]->rlim_max == 60);
725
726 assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "infinity", rl, NULL) >= 0);
727 assert_se(rl[RLIMIT_CPU]);
728 assert_se(rl[RLIMIT_CPU]->rlim_cur == RLIM_INFINITY);
729 assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max);
730
731 assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "1234ms", rl, NULL) >= 0);
732 assert_se(rl[RLIMIT_CPU]);
733 assert_se(rl[RLIMIT_CPU]->rlim_cur == 2);
734 assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max);
735
736 rl[RLIMIT_CPU] = mfree(rl[RLIMIT_CPU]);
737
738 assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "58", rl, NULL) >= 0);
739 assert_se(rl[RLIMIT_RTTIME]);
740 assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 58);
741 assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max);
742
743 assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "58:60", rl, NULL) >= 0);
744 assert_se(rl[RLIMIT_RTTIME]);
745 assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 58);
746 assert_se(rl[RLIMIT_RTTIME]->rlim_max == 60);
747
748 assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "59s", rl, NULL) >= 0);
749 assert_se(rl[RLIMIT_RTTIME]);
750 assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 59 * USEC_PER_SEC);
751 assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max);
752
753 assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "59s:123s", rl, NULL) >= 0);
754 assert_se(rl[RLIMIT_RTTIME]);
755 assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 59 * USEC_PER_SEC);
756 assert_se(rl[RLIMIT_RTTIME]->rlim_max == 123 * USEC_PER_SEC);
757
758 assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "infinity", rl, NULL) >= 0);
759 assert_se(rl[RLIMIT_RTTIME]);
760 assert_se(rl[RLIMIT_RTTIME]->rlim_cur == RLIM_INFINITY);
761 assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max);
762
763 assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "infinity:infinity", rl, NULL) >= 0);
764 assert_se(rl[RLIMIT_RTTIME]);
765 assert_se(rl[RLIMIT_RTTIME]->rlim_cur == RLIM_INFINITY);
766 assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max);
767
768 assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "2345ms", rl, NULL) >= 0);
769 assert_se(rl[RLIMIT_RTTIME]);
770 assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 2345 * USEC_PER_MSEC);
771 assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max);
772
773 rl[RLIMIT_RTTIME] = mfree(rl[RLIMIT_RTTIME]);
774 }
775
776 TEST(config_parse_pass_environ) {
777 /* int config_parse_pass_environ(
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 int r;
789 _cleanup_strv_free_ char **passenv = NULL;
790
791 r = config_parse_pass_environ(NULL, "fake", 1, "section", 1,
792 "PassEnvironment", 0, "A B",
793 &passenv, NULL);
794 assert_se(r >= 0);
795 assert_se(strv_length(passenv) == 2);
796 assert_se(streq(passenv[0], "A"));
797 assert_se(streq(passenv[1], "B"));
798
799 r = config_parse_pass_environ(NULL, "fake", 1, "section", 1,
800 "PassEnvironment", 0, "",
801 &passenv, NULL);
802 assert_se(r >= 0);
803 assert_se(strv_isempty(passenv));
804
805 r = config_parse_pass_environ(NULL, "fake", 1, "section", 1,
806 "PassEnvironment", 0, "'invalid name' 'normal_name' A=1 'special_name$$' \\",
807 &passenv, NULL);
808 assert_se(r >= 0);
809 assert_se(strv_length(passenv) == 1);
810 assert_se(streq(passenv[0], "normal_name"));
811 }
812
813 TEST(config_parse_unit_env_file) {
814 /* int config_parse_unit_env_file(
815 const char *unit,
816 const char *filename,
817 unsigned line,
818 const char *section,
819 unsigned section_line,
820 const char *lvalue,
821 int ltype,
822 const char *rvalue,
823 void *data,
824 void *userdata) */
825
826 _cleanup_(manager_freep) Manager *m = NULL;
827 Unit *u;
828 _cleanup_strv_free_ char **files = NULL;
829 int r;
830
831 r = manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_MINIMAL, &m);
832 if (manager_errno_skip_test(r)) {
833 log_notice_errno(r, "Skipping test: manager_new: %m");
834 return;
835 }
836
837 assert_se(r >= 0);
838 assert_se(manager_startup(m, NULL, NULL, NULL) >= 0);
839
840 assert_se(u = unit_new(m, sizeof(Service)));
841 assert_se(unit_add_name(u, "foobar.service") == 0);
842
843 r = config_parse_unit_env_file(u->id, "fake", 1, "section", 1,
844 "EnvironmentFile", 0, "not-absolute",
845 &files, u);
846 assert_se(r == 0);
847 assert_se(strv_isempty(files));
848
849 r = config_parse_unit_env_file(u->id, "fake", 1, "section", 1,
850 "EnvironmentFile", 0, "/absolute1",
851 &files, u);
852 assert_se(r == 0);
853 assert_se(strv_length(files) == 1);
854
855 r = config_parse_unit_env_file(u->id, "fake", 1, "section", 1,
856 "EnvironmentFile", 0, "/absolute2",
857 &files, u);
858 assert_se(r == 0);
859 assert_se(strv_length(files) == 2);
860 assert_se(streq(files[0], "/absolute1"));
861 assert_se(streq(files[1], "/absolute2"));
862
863 r = config_parse_unit_env_file(u->id, "fake", 1, "section", 1,
864 "EnvironmentFile", 0, "",
865 &files, u);
866 assert_se(r == 0);
867 assert_se(strv_isempty(files));
868
869 r = config_parse_unit_env_file(u->id, "fake", 1, "section", 1,
870 "EnvironmentFile", 0, "/path/%n.conf",
871 &files, u);
872 assert_se(r == 0);
873 assert_se(strv_length(files) == 1);
874 assert_se(streq(files[0], "/path/foobar.service.conf"));
875 }
876
877 TEST(unit_dump_config_items) {
878 unit_dump_config_items(stdout);
879 }
880
881 TEST(config_parse_memory_limit) {
882 /* int config_parse_memory_limit(
883 const char *unit,
884 const char *filename,
885 unsigned line,
886 const char *section,
887 unsigned section_line,
888 const char *lvalue,
889 int ltype,
890 const char *rvalue,
891 void *data,
892 void *userdata) */
893 CGroupContext c;
894 struct limit_test {
895 const char *limit;
896 const char *value;
897 uint64_t *result;
898 uint64_t expected;
899 } limit_tests[]= {
900 { "MemoryMin", "", &c.memory_min, CGROUP_LIMIT_MIN },
901 { "MemoryMin", "0", &c.memory_min, CGROUP_LIMIT_MIN },
902 { "MemoryMin", "10", &c.memory_min, 10 },
903 { "MemoryMin", "infinity", &c.memory_min, CGROUP_LIMIT_MAX },
904 { "MemoryLow", "", &c.memory_low, CGROUP_LIMIT_MIN },
905 { "MemoryLow", "0", &c.memory_low, CGROUP_LIMIT_MIN },
906 { "MemoryLow", "10", &c.memory_low, 10 },
907 { "MemoryLow", "infinity", &c.memory_low, CGROUP_LIMIT_MAX },
908 { "MemoryHigh", "", &c.memory_high, CGROUP_LIMIT_MAX },
909 { "MemoryHigh", "0", &c.memory_high, CGROUP_LIMIT_DUMMY },
910 { "MemoryHigh", "10", &c.memory_high, 10 },
911 { "MemoryHigh", "infinity", &c.memory_high, CGROUP_LIMIT_MAX },
912 { "MemoryMax", "", &c.memory_max, CGROUP_LIMIT_MAX },
913 { "MemoryMax", "0", &c.memory_max, CGROUP_LIMIT_DUMMY },
914 { "MemoryMax", "10", &c.memory_max, 10 },
915 { "MemoryMax", "infinity", &c.memory_max, CGROUP_LIMIT_MAX },
916 };
917 size_t i;
918 int r;
919
920 for (i = 0; i < ELEMENTSOF(limit_tests); i++) {
921 c.memory_min = CGROUP_LIMIT_DUMMY;
922 c.memory_low = CGROUP_LIMIT_DUMMY;
923 c.memory_high = CGROUP_LIMIT_DUMMY;
924 c.memory_max = CGROUP_LIMIT_DUMMY;
925 r = config_parse_memory_limit(NULL, "fake", 1, "section", 1,
926 limit_tests[i].limit, 1,
927 limit_tests[i].value, &c, NULL);
928 log_info("%s=%s\t%"PRIu64"==%"PRIu64"\n",
929 limit_tests[i].limit, limit_tests[i].value,
930 *limit_tests[i].result, limit_tests[i].expected);
931 assert_se(r >= 0);
932 assert_se(*limit_tests[i].result == limit_tests[i].expected);
933 }
934
935 }
936
937 TEST(contains_instance_specifier_superset) {
938 assert_se(contains_instance_specifier_superset("foobar@a%i"));
939 assert_se(contains_instance_specifier_superset("foobar@%ia"));
940 assert_se(contains_instance_specifier_superset("foobar@%n"));
941 assert_se(contains_instance_specifier_superset("foobar@%n.service"));
942 assert_se(contains_instance_specifier_superset("foobar@%N"));
943 assert_se(contains_instance_specifier_superset("foobar@%N.service"));
944 assert_se(contains_instance_specifier_superset("foobar@baz.%N.service"));
945 assert_se(contains_instance_specifier_superset("@%N.service"));
946 assert_se(contains_instance_specifier_superset("@%N"));
947 assert_se(contains_instance_specifier_superset("@%a%N"));
948
949 assert_se(!contains_instance_specifier_superset("foobar@%i.service"));
950 assert_se(!contains_instance_specifier_superset("foobar%ia.service"));
951 assert_se(!contains_instance_specifier_superset("foobar@%%n.service"));
952 assert_se(!contains_instance_specifier_superset("foobar@baz.service"));
953 assert_se(!contains_instance_specifier_superset("%N.service"));
954 assert_se(!contains_instance_specifier_superset("%N"));
955 assert_se(!contains_instance_specifier_superset("@%aN"));
956 assert_se(!contains_instance_specifier_superset("@%a%b"));
957 }
958
959 TEST(unit_is_recursive_template_dependency) {
960 _cleanup_(manager_freep) Manager *m = NULL;
961 Unit *u;
962 int r;
963
964 r = manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_MINIMAL, &m);
965 if (manager_errno_skip_test(r)) {
966 log_notice_errno(r, "Skipping test: manager_new: %m");
967 return;
968 }
969
970 assert_se(r >= 0);
971 assert_se(manager_startup(m, NULL, NULL, NULL) >= 0);
972
973 assert_se(u = unit_new(m, sizeof(Service)));
974 assert_se(unit_add_name(u, "foobar@1.service") == 0);
975 u->fragment_path = strdup("/foobar@.service");
976
977 assert_se(hashmap_put_strdup(&m->unit_id_map, "foobar@foobar@123.service", "/foobar@.service"));
978 assert_se(hashmap_put_strdup(&m->unit_id_map, "foobar@foobar@456.service", "/custom.service"));
979
980 /* Test that %n, %N and any extension of %i specifiers in the instance are detected as recursive. */
981 assert_se(unit_is_likely_recursive_template_dependency(u, "foobar@foobar@123.service", "foobar@%N.service") == 1);
982 assert_se(unit_is_likely_recursive_template_dependency(u, "foobar@foobar@123.service", "foobar@%n.service") == 1);
983 assert_se(unit_is_likely_recursive_template_dependency(u, "foobar@foobar@123.service", "foobar@a%i.service") == 1);
984 assert_se(unit_is_likely_recursive_template_dependency(u, "foobar@foobar@123.service", "foobar@%ia.service") == 1);
985 assert_se(unit_is_likely_recursive_template_dependency(u, "foobar@foobar@123.service", "foobar@%x%n.service") == 1);
986 /* Test that %i on its own is not detected as recursive. */
987 assert_se(unit_is_likely_recursive_template_dependency(u, "foobar@foobar@123.service", "foobar@%i.service") == 0);
988 /* Test that a specifier other than %i, %n and %N is not detected as recursive. */
989 assert_se(unit_is_likely_recursive_template_dependency(u, "foobar@foobar@123.service", "foobar@%xn.service") == 0);
990 /* Test that an expanded specifier is not detected as recursive. */
991 assert_se(unit_is_likely_recursive_template_dependency(u, "foobar@foobar@123.service", "foobar@foobar@123.service") == 0);
992 /* Test that a dependency with a custom fragment path is not detected as recursive. */
993 assert_se(unit_is_likely_recursive_template_dependency(u, "foobar@foobar@456.service", "foobar@%n.service") == 0);
994 /* Test that a dependency without a fragment path is not detected as recursive. */
995 assert_se(unit_is_likely_recursive_template_dependency(u, "foobar@foobar@789.service", "foobar@%n.service") == 0);
996 /* Test that a dependency with a different prefix is not detected as recursive. */
997 assert_se(unit_is_likely_recursive_template_dependency(u, "quux@foobar@123.service", "quux@%n.service") == 0);
998 /* Test that a dependency of a different type is not detected as recursive. */
999 assert_se(unit_is_likely_recursive_template_dependency(u, "foobar@foobar@123.mount", "foobar@%n.mount") == 0);
1000 }
1001
1002 #define TEST_PATTERN(_regex, _allowed_patterns_count, _denied_patterns_count) \
1003 { \
1004 .regex = _regex, \
1005 .allowed_patterns_count = _allowed_patterns_count, \
1006 .denied_patterns_count = _denied_patterns_count \
1007 }
1008
1009 TEST(config_parse_log_filter_patterns) {
1010 ExecContext c = {};
1011 int r;
1012
1013 static const struct {
1014 const char *regex;
1015 size_t allowed_patterns_count;
1016 size_t denied_patterns_count;
1017 } regex_tests[] = {
1018 TEST_PATTERN("", 0, 0),
1019 TEST_PATTERN(".*", 1, 0),
1020 TEST_PATTERN("~.*", 1, 1),
1021 TEST_PATTERN("", 0, 0),
1022 TEST_PATTERN("~.*", 0, 1),
1023 TEST_PATTERN("[.*", 0, 1), /* Invalid pattern. */
1024 TEST_PATTERN(".*gg.*", 1, 1),
1025 TEST_PATTERN("~.*", 1, 1), /* Already in the patterns list. */
1026 TEST_PATTERN("[.*", 1, 1), /* Invalid pattern. */
1027 TEST_PATTERN("\\x7ehello", 2, 1),
1028 TEST_PATTERN("", 0, 0),
1029 TEST_PATTERN("~foobar", 0, 1),
1030 };
1031
1032 if (ERRNO_IS_NOT_SUPPORTED(dlopen_pcre2()))
1033 return (void) log_tests_skipped("PCRE2 support is not available");
1034
1035 for (size_t i = 0; i < ELEMENTSOF(regex_tests); i++) {
1036 r = config_parse_log_filter_patterns(NULL, "fake", 1, "section", 1, "LogFilterPatterns", 1,
1037 regex_tests[i].regex, &c, NULL);
1038 assert_se(r >= 0);
1039
1040 assert_se(set_size(c.log_filter_allowed_patterns) == regex_tests[i].allowed_patterns_count);
1041 assert_se(set_size(c.log_filter_denied_patterns) == regex_tests[i].denied_patterns_count);
1042
1043 /* Ensure `~` is properly removed */
1044 const char *p;
1045 SET_FOREACH(p, c.log_filter_allowed_patterns)
1046 assert_se(p && p[0] != '~');
1047 SET_FOREACH(p, c.log_filter_denied_patterns)
1048 assert_se(p && p[0] != '~');
1049 }
1050 }
1051
1052 TEST(config_parse_open_file) {
1053 _cleanup_(manager_freep) Manager *m = NULL;
1054 _cleanup_(unit_freep) Unit *u = NULL;
1055 _cleanup_(open_file_freep) OpenFile *of = NULL;
1056 int r;
1057
1058 r = manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_MINIMAL, &m);
1059 if (manager_errno_skip_test(r)) {
1060 log_notice_errno(r, "Skipping test: manager_new: %m");
1061 return;
1062 }
1063
1064 assert_se(r >= 0);
1065 assert_se(manager_startup(m, NULL, NULL, NULL) >= 0);
1066
1067 assert_se(u = unit_new(m, sizeof(Service)));
1068 assert_se(unit_add_name(u, "foobar.service") == 0);
1069
1070 r = config_parse_open_file(NULL, "fake", 1, "section", 1,
1071 "OpenFile", 0, "/proc/1/ns/mnt:host-mount-namespace:read-only",
1072 &of, u);
1073 assert_se(r >= 0);
1074 assert_se(of);
1075 assert_se(streq(of->path, "/proc/1/ns/mnt"));
1076 assert_se(streq(of->fdname, "host-mount-namespace"));
1077 assert_se(of->flags == OPENFILE_READ_ONLY);
1078
1079 of = open_file_free(of);
1080 r = config_parse_open_file(NULL, "fake", 1, "section", 1,
1081 "OpenFile", 0, "/proc/1/ns/mnt::read-only",
1082 &of, u);
1083 assert_se(r >= 0);
1084 assert_se(of);
1085 assert_se(streq(of->path, "/proc/1/ns/mnt"));
1086 assert_se(streq(of->fdname, "mnt"));
1087 assert_se(of->flags == OPENFILE_READ_ONLY);
1088
1089 r = config_parse_open_file(NULL, "fake", 1, "section", 1,
1090 "OpenFile", 0, "",
1091 &of, u);
1092 assert_se(r >= 0);
1093 assert_se(!of);
1094 }
1095
1096 static int intro(void) {
1097 if (enter_cgroup_subroot(NULL) == -ENOMEDIUM)
1098 return log_tests_skipped("cgroupfs not available");
1099
1100 assert_se(runtime_dir = setup_fake_runtime_dir());
1101 return EXIT_SUCCESS;
1102 }
1103
1104 DEFINE_TEST_MAIN_WITH_INTRO(LOG_INFO, intro);