1 /* SPDX-License-Identifier: LGPL-2.1+ */
9 #include "alloc-util.h"
10 #include "capability-util.h"
11 #include "conf-parser.h"
13 #include "format-util.h"
16 #include "hostname-util.h"
17 #include "install-printf.h"
19 #include "load-fragment.h"
21 #include "memory-util.h"
23 #include "specifier.h"
24 #include "string-util.h"
27 #include "tmpfile-util.h"
28 #include "user-util.h"
30 /* Nontrivial value serves as a placeholder to check that parsing function (didn't) change it */
31 #define CGROUP_LIMIT_DUMMY 3
33 static int test_unit_file_get_set(void) {
38 h
= hashmap_new(&string_hash_ops
);
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");
45 log_full_errno(r
== 0 ? LOG_INFO
: LOG_ERR
, r
,
46 "unit_file_get_list: %m");
51 printf("%s = %s\n", p
->path
, unit_file_state_to_string(p
->state
));
53 unit_file_list_free(h
);
58 static void check_execcommand(ExecCommand
*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
));
75 assert_se(streq_ptr(c
->argv
[1], argv1
));
77 assert_se(streq_ptr(c
->argv
[2], argv2
));
78 assert_se(!!(c
->flags
& EXEC_COMMAND_IGNORE_FAILURE
) == ignore
);
81 static void test_config_parse_exec(void) {
82 /* int config_parse_exec(
87 unsigned section_line,
95 ExecCommand
*c
= NULL
, *c1
;
97 _cleanup_(manager_freep
) Manager
*m
= NULL
;
98 _cleanup_(unit_freep
) Unit
*u
= NULL
;
100 r
= manager_new(UNIT_FILE_USER
, MANAGER_TEST_RUN_MINIMAL
, &m
);
101 if (manager_errno_skip_test(r
)) {
102 log_notice_errno(r
, "Skipping test: manager_new: %m");
107 assert_se(manager_startup(m
, NULL
, NULL
) >= 0);
109 assert_se(u
= unit_new(m
, sizeof(Service
)));
111 log_info("/* basic test */");
112 r
= config_parse_exec(NULL
, "fake", 1, "section", 1,
113 "LValue", 0, "/RValue r1",
116 check_execcommand(c
, "/RValue", "/RValue", "r1", NULL
, false);
118 r
= config_parse_exec(NULL
, "fake", 2, "section", 1,
119 "LValue", 0, "/RValue///slashes r1///",
122 log_info("/* test slashes */");
124 c1
= c
->command_next
;
125 check_execcommand(c1
, "/RValue/slashes", "/RValue///slashes", "r1///", NULL
, false);
127 log_info("/* trailing slash */");
128 r
= config_parse_exec(NULL
, "fake", 4, "section", 1,
129 "LValue", 0, "/RValue/ argv0 r1",
131 assert_se(r
== -ENOEXEC
);
132 assert_se(c1
->command_next
== NULL
);
134 log_info("/* honour_argv0 */");
135 r
= config_parse_exec(NULL
, "fake", 3, "section", 1,
136 "LValue", 0, "@/RValue///slashes2 ///argv0 r1",
139 c1
= c1
->command_next
;
140 check_execcommand(c1
, "/RValue/slashes2", "///argv0", "r1", NULL
, false);
142 log_info("/* honour_argv0, no args */");
143 r
= config_parse_exec(NULL
, "fake", 3, "section", 1,
144 "LValue", 0, "@/RValue",
146 assert_se(r
== -ENOEXEC
);
147 assert_se(c1
->command_next
== NULL
);
149 log_info("/* no command, whitespace only, reset */");
150 r
= config_parse_exec(NULL
, "fake", 3, "section", 1,
154 assert_se(c
== NULL
);
156 log_info("/* ignore && honour_argv0 */");
157 r
= config_parse_exec(NULL
, "fake", 4, "section", 1,
158 "LValue", 0, "-@/RValue///slashes3 argv0a r1",
162 check_execcommand(c1
, "/RValue/slashes3", "argv0a", "r1", NULL
, true);
164 log_info("/* ignore && honour_argv0 */");
165 r
= config_parse_exec(NULL
, "fake", 4, "section", 1,
166 "LValue", 0, "@-/RValue///slashes4 argv0b r1",
169 c1
= c1
->command_next
;
170 check_execcommand(c1
, "/RValue/slashes4", "argv0b", "r1", NULL
, true);
172 log_info("/* ignore && ignore */");
173 r
= config_parse_exec(NULL
, "fake", 4, "section", 1,
174 "LValue", 0, "--/RValue argv0 r1",
177 assert_se(c1
->command_next
== NULL
);
179 log_info("/* ignore && ignore (2) */");
180 r
= config_parse_exec(NULL
, "fake", 4, "section", 1,
181 "LValue", 0, "-@-/RValue argv0 r1",
184 assert_se(c1
->command_next
== NULL
);
186 log_info("/* semicolon */");
187 r
= config_parse_exec(NULL
, "fake", 5, "section", 1,
189 "-@/RValue argv0 r1 ; "
193 c1
= c1
->command_next
;
194 check_execcommand(c1
, "/RValue", "argv0", "r1", NULL
, true);
196 c1
= c1
->command_next
;
197 check_execcommand(c1
, "/goo/goo", NULL
, "boo", NULL
, false);
199 log_info("/* two semicolons in a row */");
200 r
= config_parse_exec(NULL
, "fake", 5, "section", 1,
202 "-@/RValue argv0 r1 ; ; "
205 assert_se(r
== -ENOEXEC
);
206 c1
= c1
->command_next
;
207 check_execcommand(c1
, "/RValue", "argv0", "r1", NULL
, true);
209 /* second command fails because the executable name is ";" */
210 assert_se(c1
->command_next
== NULL
);
212 log_info("/* trailing semicolon */");
213 r
= config_parse_exec(NULL
, "fake", 5, "section", 1,
215 "-@/RValue argv0 r1 ; ",
218 c1
= c1
->command_next
;
219 check_execcommand(c1
, "/RValue", "argv0", "r1", NULL
, true);
221 assert_se(c1
->command_next
== NULL
);
223 log_info("/* trailing semicolon, no whitespace */");
224 r
= config_parse_exec(NULL
, "fake", 5, "section", 1,
226 "-@/RValue argv0 r1 ;",
229 c1
= c1
->command_next
;
230 check_execcommand(c1
, "/RValue", "argv0", "r1", NULL
, true);
232 assert_se(c1
->command_next
== NULL
);
234 log_info("/* trailing semicolon in single quotes */");
235 r
= config_parse_exec(NULL
, "fake", 5, "section", 1,
237 "-@/RValue argv0 r1 ';'",
240 c1
= c1
->command_next
;
241 check_execcommand(c1
, "/RValue", "argv0", "r1", ";", true);
243 log_info("/* escaped semicolon */");
244 r
= config_parse_exec(NULL
, "fake", 5, "section", 1,
249 c1
= c1
->command_next
;
250 check_execcommand(c1
, "/bin/find", NULL
, ";", NULL
, false);
252 log_info("/* escaped semicolon with following arg */");
253 r
= config_parse_exec(NULL
, "fake", 5, "section", 1,
258 c1
= c1
->command_next
;
259 check_execcommand(c1
,
260 "/sbin/find", NULL
, ";", "/x", false);
262 log_info("/* escaped semicolon as part of an expression */");
263 r
= config_parse_exec(NULL
, "fake", 5, "section", 1,
268 c1
= c1
->command_next
;
269 check_execcommand(c1
,
270 "/sbin/find", NULL
, "\\;x", NULL
, false);
272 log_info("/* encoded semicolon */");
273 r
= config_parse_exec(NULL
, "fake", 5, "section", 1,
278 c1
= c1
->command_next
;
279 check_execcommand(c1
, "/bin/find", NULL
, ";", NULL
, false);
281 log_info("/* quoted semicolon */");
282 r
= config_parse_exec(NULL
, "fake", 5, "section", 1,
287 c1
= c1
->command_next
;
288 check_execcommand(c1
, "/bin/find", NULL
, ";", NULL
, false);
290 log_info("/* quoted semicolon with following arg */");
291 r
= config_parse_exec(NULL
, "fake", 5, "section", 1,
293 "/sbin/find \";\" /x",
296 c1
= c1
->command_next
;
297 check_execcommand(c1
,
298 "/sbin/find", NULL
, ";", "/x", false);
300 log_info("/* spaces in the filename */");
301 r
= config_parse_exec(NULL
, "fake", 5, "section", 1,
303 "\"/PATH WITH SPACES/daemon\" -1 -2",
306 c1
= c1
->command_next
;
307 check_execcommand(c1
,
308 "/PATH WITH SPACES/daemon", NULL
, "-1", "-2", false);
310 log_info("/* spaces in the filename, no args */");
311 r
= config_parse_exec(NULL
, "fake", 5, "section", 1,
313 "\"/PATH WITH SPACES/daemon -1 -2\"",
316 c1
= c1
->command_next
;
317 check_execcommand(c1
,
318 "/PATH WITH SPACES/daemon -1 -2", NULL
, NULL
, NULL
, false);
320 log_info("/* spaces in the filename, everything quoted */");
321 r
= config_parse_exec(NULL
, "fake", 5, "section", 1,
323 "\"/PATH WITH SPACES/daemon\" \"-1\" '-2'",
326 c1
= c1
->command_next
;
327 check_execcommand(c1
,
328 "/PATH WITH SPACES/daemon", NULL
, "-1", "-2", false);
330 log_info("/* escaped spaces in the filename */");
331 r
= config_parse_exec(NULL
, "fake", 5, "section", 1,
333 "\"/PATH\\sWITH\\sSPACES/daemon\" '-1 -2'",
336 c1
= c1
->command_next
;
337 check_execcommand(c1
,
338 "/PATH WITH SPACES/daemon", NULL
, "-1 -2", NULL
, false);
340 log_info("/* escaped spaces in the filename (2) */");
341 r
= config_parse_exec(NULL
, "fake", 5, "section", 1,
343 "\"/PATH\\x20WITH\\x20SPACES/daemon\" \"-1 -2\"",
346 c1
= c1
->command_next
;
347 check_execcommand(c1
,
348 "/PATH WITH SPACES/daemon", NULL
, "-1 -2", NULL
, false);
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
;
355 log_info("/* invalid character: \\%c */", *ccc
);
356 r
= config_parse_exec(NULL
, "fake", 4, "section", 1,
359 assert_se(r
== -ENOEXEC
);
360 assert_se(c1
->command_next
== NULL
);
363 log_info("/* valid character: \\s */");
364 r
= config_parse_exec(NULL
, "fake", 4, "section", 1,
365 "LValue", 0, "/path\\s",
368 c1
= c1
->command_next
;
369 check_execcommand(c1
, "/path ", NULL
, NULL
, NULL
, false);
371 log_info("/* quoted backslashes */");
372 r
= config_parse_exec(NULL
, "fake", 5, "section", 1,
374 "/bin/grep '\\w+\\K'",
377 c1
= c1
->command_next
;
378 check_execcommand(c1
, "/bin/grep", NULL
, "\\w+\\K", NULL
, false);
380 log_info("/* trailing backslash: \\ */");
381 /* backslash is invalid */
382 r
= config_parse_exec(NULL
, "fake", 4, "section", 1,
383 "LValue", 0, "/path\\",
385 assert_se(r
== -ENOEXEC
);
386 assert_se(c1
->command_next
== NULL
);
388 log_info("/* missing ending ' */");
389 r
= config_parse_exec(NULL
, "fake", 4, "section", 1,
390 "LValue", 0, "/path 'foo",
392 assert_se(r
== -ENOEXEC
);
393 assert_se(c1
->command_next
== NULL
);
395 log_info("/* missing ending ' with trailing backslash */");
396 r
= config_parse_exec(NULL
, "fake", 4, "section", 1,
397 "LValue", 0, "/path 'foo\\",
399 assert_se(r
== -ENOEXEC
);
400 assert_se(c1
->command_next
== NULL
);
402 log_info("/* invalid space between modifiers */");
403 r
= config_parse_exec(NULL
, "fake", 4, "section", 1,
404 "LValue", 0, "- /path",
407 assert_se(c1
->command_next
== NULL
);
409 log_info("/* only modifiers, no path */");
410 r
= config_parse_exec(NULL
, "fake", 4, "section", 1,
414 assert_se(c1
->command_next
== NULL
);
416 log_info("/* empty argument, reset */");
417 r
= config_parse_exec(NULL
, "fake", 4, "section", 1,
421 assert_se(c
== NULL
);
423 exec_command_free_list(c
);
426 static void test_config_parse_log_extra_fields(void) {
427 /* int config_parse_log_extra_fields(
429 const char *filename,
432 unsigned section_line,
441 _cleanup_(manager_freep
) Manager
*m
= NULL
;
442 _cleanup_(unit_freep
) Unit
*u
= NULL
;
445 r
= manager_new(UNIT_FILE_USER
, MANAGER_TEST_RUN_MINIMAL
, &m
);
446 if (manager_errno_skip_test(r
)) {
447 log_notice_errno(r
, "Skipping test: manager_new: %m");
452 assert_se(manager_startup(m
, NULL
, NULL
) >= 0);
454 assert_se(u
= unit_new(m
, sizeof(Service
)));
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 ' ' \"",
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
));
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 ' '",
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
));
476 exec_context_dump(&c
, stdout
, " --> ");
478 log_info("/* %s – reset */", __func__
);
479 r
= config_parse_log_extra_fields(NULL
, "fake", 1, "section", 1,
483 assert_se(c
.n_log_extra_fields
== 0);
485 exec_context_free_log_extra_fields(&c
);
487 log_info("/* %s – bye */", __func__
);
490 static void test_install_printf(void) {
491 char name
[] = "name.service",
492 path
[] = "/run/systemd/system/name.service";
493 UnitFileInstallInfo i
= { .name
= name
, .path
= path
, };
494 UnitFileInstallInfo i2
= { .name
= name
, .path
= path
, };
495 char name3
[] = "name@inst.service",
496 path3
[] = "/run/systemd/system/name.service";
497 UnitFileInstallInfo i3
= { .name
= name3
, .path
= path3
, };
498 UnitFileInstallInfo i4
= { .name
= name3
, .path
= path3
, };
500 _cleanup_free_
char *mid
= NULL
, *bid
= NULL
, *host
= NULL
, *gid
= NULL
, *group
= NULL
, *uid
= NULL
, *user
= NULL
;
502 assert_se(specifier_machine_id('m', NULL
, NULL
, &mid
) >= 0 && mid
);
503 assert_se(specifier_boot_id('b', NULL
, NULL
, &bid
) >= 0 && bid
);
504 assert_se(host
= gethostname_malloc());
505 assert_se(group
= gid_to_name(getgid()));
506 assert_se(asprintf(&gid
, UID_FMT
, getgid()) >= 0);
507 assert_se(user
= uid_to_name(getuid()));
508 assert_se(asprintf(&uid
, UID_FMT
, getuid()) >= 0);
510 #define expect(src, pattern, result) \
512 _cleanup_free_ char *t = NULL; \
513 _cleanup_free_ char \
514 *d1 = strdup(i.name), \
515 *d2 = strdup(i.path); \
516 assert_se(install_full_printf(&src, pattern, &t) >= 0 || !result); \
517 memzero(i.name, strlen(i.name)); \
518 memzero(i.path, strlen(i.path)); \
519 assert_se(d1 && d2); \
522 assert_se(streq(t, result)); \
523 } else assert_se(t == NULL); \
524 strcpy(i.name, d1); \
525 strcpy(i.path, d2); \
528 expect(i
, "%n", "name.service");
529 expect(i
, "%N", "name");
530 expect(i
, "%p", "name");
532 expect(i
, "%j", "name");
533 expect(i
, "%g", group
);
534 expect(i
, "%G", gid
);
535 expect(i
, "%u", user
);
536 expect(i
, "%U", uid
);
538 expect(i
, "%m", mid
);
539 expect(i
, "%b", bid
);
540 expect(i
, "%H", host
);
542 expect(i2
, "%g", group
);
543 expect(i2
, "%G", gid
);
544 expect(i2
, "%u", user
);
545 expect(i2
, "%U", uid
);
547 expect(i3
, "%n", "name@inst.service");
548 expect(i3
, "%N", "name@inst");
549 expect(i3
, "%p", "name");
550 expect(i3
, "%g", group
);
551 expect(i3
, "%G", gid
);
552 expect(i3
, "%u", user
);
553 expect(i3
, "%U", uid
);
555 expect(i3
, "%m", mid
);
556 expect(i3
, "%b", bid
);
557 expect(i3
, "%H", host
);
559 expect(i4
, "%g", group
);
560 expect(i4
, "%G", gid
);
561 expect(i4
, "%u", user
);
562 expect(i4
, "%U", uid
);
565 static uint64_t make_cap(int cap
) {
566 return ((uint64_t) 1ULL << (uint64_t) cap
);
569 static void test_config_parse_capability_set(void) {
570 /* int config_parse_capability_set(
572 const char *filename,
575 unsigned section_line,
582 uint64_t capability_bounding_set
= 0;
584 r
= config_parse_capability_set(NULL
, "fake", 1, "section", 1,
585 "CapabilityBoundingSet", 0, "CAP_NET_RAW",
586 &capability_bounding_set
, NULL
);
588 assert_se(capability_bounding_set
== make_cap(CAP_NET_RAW
));
590 r
= config_parse_capability_set(NULL
, "fake", 1, "section", 1,
591 "CapabilityBoundingSet", 0, "CAP_NET_ADMIN",
592 &capability_bounding_set
, NULL
);
594 assert_se(capability_bounding_set
== (make_cap(CAP_NET_RAW
) | make_cap(CAP_NET_ADMIN
)));
596 r
= config_parse_capability_set(NULL
, "fake", 1, "section", 1,
597 "CapabilityBoundingSet", 0, "~CAP_NET_ADMIN",
598 &capability_bounding_set
, NULL
);
600 assert_se(capability_bounding_set
== make_cap(CAP_NET_RAW
));
602 r
= config_parse_capability_set(NULL
, "fake", 1, "section", 1,
603 "CapabilityBoundingSet", 0, "",
604 &capability_bounding_set
, NULL
);
606 assert_se(capability_bounding_set
== UINT64_C(0));
608 r
= config_parse_capability_set(NULL
, "fake", 1, "section", 1,
609 "CapabilityBoundingSet", 0, "~",
610 &capability_bounding_set
, NULL
);
612 assert_se(cap_test_all(capability_bounding_set
));
614 capability_bounding_set
= 0;
615 r
= config_parse_capability_set(NULL
, "fake", 1, "section", 1,
616 "CapabilityBoundingSet", 0, " 'CAP_NET_RAW' WAT_CAP??? CAP_NET_ADMIN CAP'_trailing_garbage",
617 &capability_bounding_set
, NULL
);
619 assert_se(capability_bounding_set
== (make_cap(CAP_NET_RAW
) | make_cap(CAP_NET_ADMIN
)));
622 static void test_config_parse_rlimit(void) {
623 struct rlimit
* rl
[_RLIMIT_MAX
] = {};
625 assert_se(config_parse_rlimit(NULL
, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE
, "55", rl
, NULL
) >= 0);
626 assert_se(rl
[RLIMIT_NOFILE
]);
627 assert_se(rl
[RLIMIT_NOFILE
]->rlim_cur
== 55);
628 assert_se(rl
[RLIMIT_NOFILE
]->rlim_cur
== rl
[RLIMIT_NOFILE
]->rlim_max
);
630 assert_se(config_parse_rlimit(NULL
, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE
, "55:66", rl
, NULL
) >= 0);
631 assert_se(rl
[RLIMIT_NOFILE
]);
632 assert_se(rl
[RLIMIT_NOFILE
]->rlim_cur
== 55);
633 assert_se(rl
[RLIMIT_NOFILE
]->rlim_max
== 66);
635 assert_se(config_parse_rlimit(NULL
, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE
, "infinity", rl
, NULL
) >= 0);
636 assert_se(rl
[RLIMIT_NOFILE
]);
637 assert_se(rl
[RLIMIT_NOFILE
]->rlim_cur
== RLIM_INFINITY
);
638 assert_se(rl
[RLIMIT_NOFILE
]->rlim_cur
== rl
[RLIMIT_NOFILE
]->rlim_max
);
640 assert_se(config_parse_rlimit(NULL
, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE
, "infinity:infinity", rl
, NULL
) >= 0);
641 assert_se(rl
[RLIMIT_NOFILE
]);
642 assert_se(rl
[RLIMIT_NOFILE
]->rlim_cur
== RLIM_INFINITY
);
643 assert_se(rl
[RLIMIT_NOFILE
]->rlim_cur
== rl
[RLIMIT_NOFILE
]->rlim_max
);
645 rl
[RLIMIT_NOFILE
]->rlim_cur
= 10;
646 rl
[RLIMIT_NOFILE
]->rlim_max
= 20;
648 /* Invalid values don't change rl */
649 assert_se(config_parse_rlimit(NULL
, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE
, "10:20:30", rl
, NULL
) >= 0);
650 assert_se(rl
[RLIMIT_NOFILE
]);
651 assert_se(rl
[RLIMIT_NOFILE
]->rlim_cur
== 10);
652 assert_se(rl
[RLIMIT_NOFILE
]->rlim_max
== 20);
654 assert_se(config_parse_rlimit(NULL
, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE
, "wat:wat", rl
, NULL
) >= 0);
655 assert_se(rl
[RLIMIT_NOFILE
]);
656 assert_se(rl
[RLIMIT_NOFILE
]->rlim_cur
== 10);
657 assert_se(rl
[RLIMIT_NOFILE
]->rlim_max
== 20);
659 assert_se(config_parse_rlimit(NULL
, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE
, "66:wat", rl
, NULL
) >= 0);
660 assert_se(rl
[RLIMIT_NOFILE
]);
661 assert_se(rl
[RLIMIT_NOFILE
]->rlim_cur
== 10);
662 assert_se(rl
[RLIMIT_NOFILE
]->rlim_max
== 20);
664 assert_se(config_parse_rlimit(NULL
, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE
, "200:100", rl
, NULL
) >= 0);
665 assert_se(rl
[RLIMIT_NOFILE
]);
666 assert_se(rl
[RLIMIT_NOFILE
]->rlim_cur
== 10);
667 assert_se(rl
[RLIMIT_NOFILE
]->rlim_max
== 20);
669 rl
[RLIMIT_NOFILE
] = mfree(rl
[RLIMIT_NOFILE
]);
671 assert_se(config_parse_rlimit(NULL
, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU
, "56", rl
, NULL
) >= 0);
672 assert_se(rl
[RLIMIT_CPU
]);
673 assert_se(rl
[RLIMIT_CPU
]->rlim_cur
== 56);
674 assert_se(rl
[RLIMIT_CPU
]->rlim_cur
== rl
[RLIMIT_CPU
]->rlim_max
);
676 assert_se(config_parse_rlimit(NULL
, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU
, "57s", rl
, NULL
) >= 0);
677 assert_se(rl
[RLIMIT_CPU
]);
678 assert_se(rl
[RLIMIT_CPU
]->rlim_cur
== 57);
679 assert_se(rl
[RLIMIT_CPU
]->rlim_cur
== rl
[RLIMIT_CPU
]->rlim_max
);
681 assert_se(config_parse_rlimit(NULL
, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU
, "40s:1m", rl
, NULL
) >= 0);
682 assert_se(rl
[RLIMIT_CPU
]);
683 assert_se(rl
[RLIMIT_CPU
]->rlim_cur
== 40);
684 assert_se(rl
[RLIMIT_CPU
]->rlim_max
== 60);
686 assert_se(config_parse_rlimit(NULL
, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU
, "infinity", rl
, NULL
) >= 0);
687 assert_se(rl
[RLIMIT_CPU
]);
688 assert_se(rl
[RLIMIT_CPU
]->rlim_cur
== RLIM_INFINITY
);
689 assert_se(rl
[RLIMIT_CPU
]->rlim_cur
== rl
[RLIMIT_CPU
]->rlim_max
);
691 assert_se(config_parse_rlimit(NULL
, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU
, "1234ms", rl
, NULL
) >= 0);
692 assert_se(rl
[RLIMIT_CPU
]);
693 assert_se(rl
[RLIMIT_CPU
]->rlim_cur
== 2);
694 assert_se(rl
[RLIMIT_CPU
]->rlim_cur
== rl
[RLIMIT_CPU
]->rlim_max
);
696 rl
[RLIMIT_CPU
] = mfree(rl
[RLIMIT_CPU
]);
698 assert_se(config_parse_rlimit(NULL
, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME
, "58", rl
, NULL
) >= 0);
699 assert_se(rl
[RLIMIT_RTTIME
]);
700 assert_se(rl
[RLIMIT_RTTIME
]->rlim_cur
== 58);
701 assert_se(rl
[RLIMIT_RTTIME
]->rlim_cur
== rl
[RLIMIT_RTTIME
]->rlim_max
);
703 assert_se(config_parse_rlimit(NULL
, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME
, "58:60", rl
, NULL
) >= 0);
704 assert_se(rl
[RLIMIT_RTTIME
]);
705 assert_se(rl
[RLIMIT_RTTIME
]->rlim_cur
== 58);
706 assert_se(rl
[RLIMIT_RTTIME
]->rlim_max
== 60);
708 assert_se(config_parse_rlimit(NULL
, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME
, "59s", rl
, NULL
) >= 0);
709 assert_se(rl
[RLIMIT_RTTIME
]);
710 assert_se(rl
[RLIMIT_RTTIME
]->rlim_cur
== 59 * USEC_PER_SEC
);
711 assert_se(rl
[RLIMIT_RTTIME
]->rlim_cur
== rl
[RLIMIT_RTTIME
]->rlim_max
);
713 assert_se(config_parse_rlimit(NULL
, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME
, "59s:123s", rl
, NULL
) >= 0);
714 assert_se(rl
[RLIMIT_RTTIME
]);
715 assert_se(rl
[RLIMIT_RTTIME
]->rlim_cur
== 59 * USEC_PER_SEC
);
716 assert_se(rl
[RLIMIT_RTTIME
]->rlim_max
== 123 * USEC_PER_SEC
);
718 assert_se(config_parse_rlimit(NULL
, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME
, "infinity", rl
, NULL
) >= 0);
719 assert_se(rl
[RLIMIT_RTTIME
]);
720 assert_se(rl
[RLIMIT_RTTIME
]->rlim_cur
== RLIM_INFINITY
);
721 assert_se(rl
[RLIMIT_RTTIME
]->rlim_cur
== rl
[RLIMIT_RTTIME
]->rlim_max
);
723 assert_se(config_parse_rlimit(NULL
, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME
, "infinity:infinity", rl
, NULL
) >= 0);
724 assert_se(rl
[RLIMIT_RTTIME
]);
725 assert_se(rl
[RLIMIT_RTTIME
]->rlim_cur
== RLIM_INFINITY
);
726 assert_se(rl
[RLIMIT_RTTIME
]->rlim_cur
== rl
[RLIMIT_RTTIME
]->rlim_max
);
728 assert_se(config_parse_rlimit(NULL
, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME
, "2345ms", rl
, NULL
) >= 0);
729 assert_se(rl
[RLIMIT_RTTIME
]);
730 assert_se(rl
[RLIMIT_RTTIME
]->rlim_cur
== 2345 * USEC_PER_MSEC
);
731 assert_se(rl
[RLIMIT_RTTIME
]->rlim_cur
== rl
[RLIMIT_RTTIME
]->rlim_max
);
733 rl
[RLIMIT_RTTIME
] = mfree(rl
[RLIMIT_RTTIME
]);
736 static void test_config_parse_pass_environ(void) {
737 /* int config_parse_pass_environ(
739 const char *filename,
742 unsigned section_line,
749 _cleanup_strv_free_
char **passenv
= NULL
;
751 r
= config_parse_pass_environ(NULL
, "fake", 1, "section", 1,
752 "PassEnvironment", 0, "A B",
755 assert_se(strv_length(passenv
) == 2);
756 assert_se(streq(passenv
[0], "A"));
757 assert_se(streq(passenv
[1], "B"));
759 r
= config_parse_pass_environ(NULL
, "fake", 1, "section", 1,
760 "PassEnvironment", 0, "",
763 assert_se(strv_isempty(passenv
));
765 r
= config_parse_pass_environ(NULL
, "fake", 1, "section", 1,
766 "PassEnvironment", 0, "'invalid name' 'normal_name' A=1 \\",
769 assert_se(strv_length(passenv
) == 1);
770 assert_se(streq(passenv
[0], "normal_name"));
774 static void test_unit_dump_config_items(void) {
775 unit_dump_config_items(stdout
);
778 static void test_config_parse_memory_limit(void) {
779 /* int config_parse_memory_limit(
781 const char *filename,
784 unsigned section_line,
797 { "MemoryMin", "", &c
.memory_min
, CGROUP_LIMIT_MIN
},
798 { "MemoryMin", "0", &c
.memory_min
, CGROUP_LIMIT_MIN
},
799 { "MemoryMin", "10", &c
.memory_min
, 10 },
800 { "MemoryMin", "infinity", &c
.memory_min
, CGROUP_LIMIT_MAX
},
801 { "MemoryLow", "", &c
.memory_low
, CGROUP_LIMIT_MIN
},
802 { "MemoryLow", "0", &c
.memory_low
, CGROUP_LIMIT_MIN
},
803 { "MemoryLow", "10", &c
.memory_low
, 10 },
804 { "MemoryLow", "infinity", &c
.memory_low
, CGROUP_LIMIT_MAX
},
805 { "MemoryHigh", "", &c
.memory_high
, CGROUP_LIMIT_MAX
},
806 { "MemoryHigh", "0", &c
.memory_high
, CGROUP_LIMIT_DUMMY
},
807 { "MemoryHigh", "10", &c
.memory_high
, 10 },
808 { "MemoryHigh", "infinity", &c
.memory_high
, CGROUP_LIMIT_MAX
},
809 { "MemoryMax", "", &c
.memory_max
, CGROUP_LIMIT_MAX
},
810 { "MemoryMax", "0", &c
.memory_max
, CGROUP_LIMIT_DUMMY
},
811 { "MemoryMax", "10", &c
.memory_max
, 10 },
812 { "MemoryMax", "infinity", &c
.memory_max
, CGROUP_LIMIT_MAX
},
817 for (i
= 0; i
< ELEMENTSOF(limit_tests
); i
++) {
818 c
.memory_min
= CGROUP_LIMIT_DUMMY
;
819 c
.memory_low
= CGROUP_LIMIT_DUMMY
;
820 c
.memory_high
= CGROUP_LIMIT_DUMMY
;
821 c
.memory_max
= CGROUP_LIMIT_DUMMY
;
822 r
= config_parse_memory_limit(NULL
, "fake", 1, "section", 1,
823 limit_tests
[i
].limit
, 1,
824 limit_tests
[i
].value
, &c
, NULL
);
825 log_info("%s=%s\t%"PRIu64
"==%"PRIu64
"\n",
826 limit_tests
[i
].limit
, limit_tests
[i
].value
,
827 *limit_tests
[i
].result
, limit_tests
[i
].expected
);
829 assert_se(*limit_tests
[i
].result
== limit_tests
[i
].expected
);
834 int main(int argc
, char *argv
[]) {
835 _cleanup_(rm_rf_physical_and_freep
) char *runtime_dir
= NULL
;
838 test_setup_logging(LOG_INFO
);
840 r
= enter_cgroup_subroot(NULL
);
842 return log_tests_skipped("cgroupfs not available");
844 assert_se(runtime_dir
= setup_fake_runtime_dir());
846 r
= test_unit_file_get_set();
847 test_config_parse_exec();
848 test_config_parse_log_extra_fields();
849 test_config_parse_capability_set();
850 test_config_parse_rlimit();
851 test_config_parse_pass_environ();
852 TEST_REQ_RUNNING_SYSTEMD(test_install_printf());
853 test_unit_dump_config_items();
854 test_config_parse_memory_limit();