]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/test/test-load-fragment.c
tree-wide: define iterator inside of the macro
[thirdparty/systemd.git] / src / test / test-load-fragment.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #include <fcntl.h>
4 #include <stddef.h>
5 #include <stdio.h>
6 #include <unistd.h>
7
8 #include "all-units.h"
9 #include "alloc-util.h"
10 #include "capability-util.h"
11 #include "conf-parser.h"
12 #include "fd-util.h"
13 #include "format-util.h"
14 #include "fs-util.h"
15 #include "hashmap.h"
16 #include "hostname-util.h"
17 #include "install-printf.h"
18 #include "install.h"
19 #include "load-fragment.h"
20 #include "macro.h"
21 #include "memory-util.h"
22 #include "rm-rf.h"
23 #include "specifier.h"
24 #include "string-util.h"
25 #include "strv.h"
26 #include "tests.h"
27 #include "tmpfile-util.h"
28 #include "user-util.h"
29
30 /* Nontrivial value serves as a placeholder to check that parsing function (didn't) change it */
31 #define CGROUP_LIMIT_DUMMY 3
32
33 static int test_unit_file_get_set(void) {
34 int r;
35 Hashmap *h;
36 UnitFileList *p;
37
38 h = hashmap_new(&string_hash_ops);
39 assert_se(h);
40
41 r = unit_file_get_list(UNIT_FILE_SYSTEM, NULL, h, NULL, NULL);
42 if (IN_SET(r, -EPERM, -EACCES))
43 return log_tests_skipped_errno(r, "unit_file_get_list");
44
45 log_full_errno(r == 0 ? LOG_INFO : LOG_ERR, r,
46 "unit_file_get_list: %m");
47 if (r < 0)
48 return EXIT_FAILURE;
49
50 HASHMAP_FOREACH(p, h)
51 printf("%s = %s\n", p->path, unit_file_state_to_string(p->state));
52
53 unit_file_list_free(h);
54
55 return 0;
56 }
57
58 static void check_execcommand(ExecCommand *c,
59 const char* path,
60 const char* argv0,
61 const char* argv1,
62 const char* argv2,
63 bool ignore) {
64 size_t n;
65
66 assert_se(c);
67 log_info("expect: \"%s\" [\"%s\" \"%s\" \"%s\"]",
68 path, argv0 ?: path, argv1, argv2);
69 n = strv_length(c->argv);
70 log_info("actual: \"%s\" [\"%s\" \"%s\" \"%s\"]",
71 c->path, c->argv[0], n > 0 ? c->argv[1] : NULL, n > 1 ? c->argv[2] : NULL);
72 assert_se(streq(c->path, path));
73 assert_se(streq(c->argv[0], argv0 ?: path));
74 if (n > 0)
75 assert_se(streq_ptr(c->argv[1], argv1));
76 if (n > 1)
77 assert_se(streq_ptr(c->argv[2], argv2));
78 assert_se(!!(c->flags & EXEC_COMMAND_IGNORE_FAILURE) == ignore);
79 }
80
81 static void test_config_parse_exec(void) {
82 /* int config_parse_exec(
83 const char *unit,
84 const char *filename,
85 unsigned line,
86 const char *section,
87 unsigned section_line,
88 const char *lvalue,
89 int ltype,
90 const char *rvalue,
91 void *data,
92 void *userdata) */
93 int r;
94
95 ExecCommand *c = NULL, *c1;
96 const char *ccc;
97 _cleanup_(manager_freep) Manager *m = NULL;
98 _cleanup_(unit_freep) Unit *u = NULL;
99
100 r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_MINIMAL, &m);
101 if (manager_errno_skip_test(r)) {
102 log_notice_errno(r, "Skipping test: manager_new: %m");
103 return;
104 }
105
106 assert_se(r >= 0);
107 assert_se(manager_startup(m, NULL, NULL) >= 0);
108
109 assert_se(u = unit_new(m, sizeof(Service)));
110
111 log_info("/* basic test */");
112 r = config_parse_exec(NULL, "fake", 1, "section", 1,
113 "LValue", 0, "/RValue r1",
114 &c, u);
115 assert_se(r >= 0);
116 check_execcommand(c, "/RValue", "/RValue", "r1", NULL, false);
117
118 r = config_parse_exec(NULL, "fake", 2, "section", 1,
119 "LValue", 0, "/RValue///slashes r1///",
120 &c, u);
121
122 log_info("/* test slashes */");
123 assert_se(r >= 0);
124 c1 = c->command_next;
125 check_execcommand(c1, "/RValue/slashes", "/RValue///slashes", "r1///", NULL, false);
126
127 log_info("/* trailing slash */");
128 r = config_parse_exec(NULL, "fake", 4, "section", 1,
129 "LValue", 0, "/RValue/ argv0 r1",
130 &c, u);
131 assert_se(r == -ENOEXEC);
132 assert_se(c1->command_next == NULL);
133
134 log_info("/* honour_argv0 */");
135 r = config_parse_exec(NULL, "fake", 3, "section", 1,
136 "LValue", 0, "@/RValue///slashes2 ///argv0 r1",
137 &c, u);
138 assert_se(r >= 0);
139 c1 = c1->command_next;
140 check_execcommand(c1, "/RValue/slashes2", "///argv0", "r1", NULL, false);
141
142 log_info("/* honour_argv0, no args */");
143 r = config_parse_exec(NULL, "fake", 3, "section", 1,
144 "LValue", 0, "@/RValue",
145 &c, u);
146 assert_se(r == -ENOEXEC);
147 assert_se(c1->command_next == NULL);
148
149 log_info("/* no command, whitespace only, reset */");
150 r = config_parse_exec(NULL, "fake", 3, "section", 1,
151 "LValue", 0, "",
152 &c, u);
153 assert_se(r == 0);
154 assert_se(c == NULL);
155
156 log_info("/* ignore && honour_argv0 */");
157 r = config_parse_exec(NULL, "fake", 4, "section", 1,
158 "LValue", 0, "-@/RValue///slashes3 argv0a r1",
159 &c, u);
160 assert_se(r >= 0);
161 c1 = c;
162 check_execcommand(c1, "/RValue/slashes3", "argv0a", "r1", NULL, true);
163
164 log_info("/* ignore && honour_argv0 */");
165 r = config_parse_exec(NULL, "fake", 4, "section", 1,
166 "LValue", 0, "@-/RValue///slashes4 argv0b r1",
167 &c, u);
168 assert_se(r >= 0);
169 c1 = c1->command_next;
170 check_execcommand(c1, "/RValue/slashes4", "argv0b", "r1", NULL, true);
171
172 log_info("/* ignore && ignore */");
173 r = config_parse_exec(NULL, "fake", 4, "section", 1,
174 "LValue", 0, "--/RValue argv0 r1",
175 &c, u);
176 assert_se(r == 0);
177 assert_se(c1->command_next == NULL);
178
179 log_info("/* ignore && ignore (2) */");
180 r = config_parse_exec(NULL, "fake", 4, "section", 1,
181 "LValue", 0, "-@-/RValue argv0 r1",
182 &c, u);
183 assert_se(r == 0);
184 assert_se(c1->command_next == NULL);
185
186 log_info("/* semicolon */");
187 r = config_parse_exec(NULL, "fake", 5, "section", 1,
188 "LValue", 0,
189 "-@/RValue argv0 r1 ; "
190 "/goo/goo boo",
191 &c, u);
192 assert_se(r >= 0);
193 c1 = c1->command_next;
194 check_execcommand(c1, "/RValue", "argv0", "r1", NULL, true);
195
196 c1 = c1->command_next;
197 check_execcommand(c1, "/goo/goo", NULL, "boo", NULL, false);
198
199 log_info("/* two semicolons in a row */");
200 r = config_parse_exec(NULL, "fake", 5, "section", 1,
201 "LValue", 0,
202 "-@/RValue argv0 r1 ; ; "
203 "/goo/goo boo",
204 &c, u);
205 assert_se(r == -ENOEXEC);
206 c1 = c1->command_next;
207 check_execcommand(c1, "/RValue", "argv0", "r1", NULL, true);
208
209 /* second command fails because the executable name is ";" */
210 assert_se(c1->command_next == NULL);
211
212 log_info("/* trailing semicolon */");
213 r = config_parse_exec(NULL, "fake", 5, "section", 1,
214 "LValue", 0,
215 "-@/RValue argv0 r1 ; ",
216 &c, u);
217 assert_se(r >= 0);
218 c1 = c1->command_next;
219 check_execcommand(c1, "/RValue", "argv0", "r1", NULL, true);
220
221 assert_se(c1->command_next == NULL);
222
223 log_info("/* trailing semicolon, no whitespace */");
224 r = config_parse_exec(NULL, "fake", 5, "section", 1,
225 "LValue", 0,
226 "-@/RValue argv0 r1 ;",
227 &c, u);
228 assert_se(r >= 0);
229 c1 = c1->command_next;
230 check_execcommand(c1, "/RValue", "argv0", "r1", NULL, true);
231
232 assert_se(c1->command_next == NULL);
233
234 log_info("/* trailing semicolon in single quotes */");
235 r = config_parse_exec(NULL, "fake", 5, "section", 1,
236 "LValue", 0,
237 "-@/RValue argv0 r1 ';'",
238 &c, u);
239 assert_se(r >= 0);
240 c1 = c1->command_next;
241 check_execcommand(c1, "/RValue", "argv0", "r1", ";", true);
242
243 log_info("/* escaped semicolon */");
244 r = config_parse_exec(NULL, "fake", 5, "section", 1,
245 "LValue", 0,
246 "/bin/find \\;",
247 &c, u);
248 assert_se(r >= 0);
249 c1 = c1->command_next;
250 check_execcommand(c1, "/bin/find", NULL, ";", NULL, false);
251
252 log_info("/* escaped semicolon with following arg */");
253 r = config_parse_exec(NULL, "fake", 5, "section", 1,
254 "LValue", 0,
255 "/sbin/find \\; /x",
256 &c, u);
257 assert_se(r >= 0);
258 c1 = c1->command_next;
259 check_execcommand(c1,
260 "/sbin/find", NULL, ";", "/x", false);
261
262 log_info("/* escaped semicolon as part of an expression */");
263 r = config_parse_exec(NULL, "fake", 5, "section", 1,
264 "LValue", 0,
265 "/sbin/find \\;x",
266 &c, u);
267 assert_se(r >= 0);
268 c1 = c1->command_next;
269 check_execcommand(c1,
270 "/sbin/find", NULL, "\\;x", NULL, false);
271
272 log_info("/* encoded semicolon */");
273 r = config_parse_exec(NULL, "fake", 5, "section", 1,
274 "LValue", 0,
275 "/bin/find \\073",
276 &c, u);
277 assert_se(r >= 0);
278 c1 = c1->command_next;
279 check_execcommand(c1, "/bin/find", NULL, ";", NULL, false);
280
281 log_info("/* quoted semicolon */");
282 r = config_parse_exec(NULL, "fake", 5, "section", 1,
283 "LValue", 0,
284 "/bin/find \";\"",
285 &c, u);
286 assert_se(r >= 0);
287 c1 = c1->command_next;
288 check_execcommand(c1, "/bin/find", NULL, ";", NULL, false);
289
290 log_info("/* quoted semicolon with following arg */");
291 r = config_parse_exec(NULL, "fake", 5, "section", 1,
292 "LValue", 0,
293 "/sbin/find \";\" /x",
294 &c, u);
295 assert_se(r >= 0);
296 c1 = c1->command_next;
297 check_execcommand(c1,
298 "/sbin/find", NULL, ";", "/x", false);
299
300 log_info("/* spaces in the filename */");
301 r = config_parse_exec(NULL, "fake", 5, "section", 1,
302 "LValue", 0,
303 "\"/PATH WITH SPACES/daemon\" -1 -2",
304 &c, u);
305 assert_se(r >= 0);
306 c1 = c1->command_next;
307 check_execcommand(c1,
308 "/PATH WITH SPACES/daemon", NULL, "-1", "-2", false);
309
310 log_info("/* spaces in the filename, no args */");
311 r = config_parse_exec(NULL, "fake", 5, "section", 1,
312 "LValue", 0,
313 "\"/PATH WITH SPACES/daemon -1 -2\"",
314 &c, u);
315 assert_se(r >= 0);
316 c1 = c1->command_next;
317 check_execcommand(c1,
318 "/PATH WITH SPACES/daemon -1 -2", NULL, NULL, NULL, false);
319
320 log_info("/* spaces in the filename, everything quoted */");
321 r = config_parse_exec(NULL, "fake", 5, "section", 1,
322 "LValue", 0,
323 "\"/PATH WITH SPACES/daemon\" \"-1\" '-2'",
324 &c, u);
325 assert_se(r >= 0);
326 c1 = c1->command_next;
327 check_execcommand(c1,
328 "/PATH WITH SPACES/daemon", NULL, "-1", "-2", false);
329
330 log_info("/* escaped spaces in the filename */");
331 r = config_parse_exec(NULL, "fake", 5, "section", 1,
332 "LValue", 0,
333 "\"/PATH\\sWITH\\sSPACES/daemon\" '-1 -2'",
334 &c, u);
335 assert_se(r >= 0);
336 c1 = c1->command_next;
337 check_execcommand(c1,
338 "/PATH WITH SPACES/daemon", NULL, "-1 -2", NULL, false);
339
340 log_info("/* escaped spaces in the filename (2) */");
341 r = config_parse_exec(NULL, "fake", 5, "section", 1,
342 "LValue", 0,
343 "\"/PATH\\x20WITH\\x20SPACES/daemon\" \"-1 -2\"",
344 &c, u);
345 assert_se(r >= 0);
346 c1 = c1->command_next;
347 check_execcommand(c1,
348 "/PATH WITH SPACES/daemon", NULL, "-1 -2", NULL, false);
349
350 for (ccc = "abfnrtv\\\'\"x"; *ccc; ccc++) {
351 /* \\x is an incomplete hexadecimal sequence, invalid because of the slash */
352 char path[] = "/path\\X";
353 path[sizeof(path) - 2] = *ccc;
354
355 log_info("/* invalid character: \\%c */", *ccc);
356 r = config_parse_exec(NULL, "fake", 4, "section", 1,
357 "LValue", 0, path,
358 &c, u);
359 assert_se(r == -ENOEXEC);
360 assert_se(c1->command_next == NULL);
361 }
362
363 log_info("/* valid character: \\s */");
364 r = config_parse_exec(NULL, "fake", 4, "section", 1,
365 "LValue", 0, "/path\\s",
366 &c, u);
367 assert_se(r >= 0);
368 c1 = c1->command_next;
369 check_execcommand(c1, "/path ", NULL, NULL, NULL, false);
370
371 log_info("/* quoted backslashes */");
372 r = config_parse_exec(NULL, "fake", 5, "section", 1,
373 "LValue", 0,
374 "/bin/grep '\\w+\\K'",
375 &c, u);
376 assert_se(r >= 0);
377 c1 = c1->command_next;
378 check_execcommand(c1, "/bin/grep", NULL, "\\w+\\K", NULL, false);
379
380 log_info("/* trailing backslash: \\ */");
381 /* backslash is invalid */
382 r = config_parse_exec(NULL, "fake", 4, "section", 1,
383 "LValue", 0, "/path\\",
384 &c, u);
385 assert_se(r == -ENOEXEC);
386 assert_se(c1->command_next == NULL);
387
388 log_info("/* missing ending ' */");
389 r = config_parse_exec(NULL, "fake", 4, "section", 1,
390 "LValue", 0, "/path 'foo",
391 &c, u);
392 assert_se(r == -ENOEXEC);
393 assert_se(c1->command_next == NULL);
394
395 log_info("/* missing ending ' with trailing backslash */");
396 r = config_parse_exec(NULL, "fake", 4, "section", 1,
397 "LValue", 0, "/path 'foo\\",
398 &c, u);
399 assert_se(r == -ENOEXEC);
400 assert_se(c1->command_next == NULL);
401
402 log_info("/* invalid space between modifiers */");
403 r = config_parse_exec(NULL, "fake", 4, "section", 1,
404 "LValue", 0, "- /path",
405 &c, u);
406 assert_se(r == 0);
407 assert_se(c1->command_next == NULL);
408
409 log_info("/* only modifiers, no path */");
410 r = config_parse_exec(NULL, "fake", 4, "section", 1,
411 "LValue", 0, "-",
412 &c, u);
413 assert_se(r == 0);
414 assert_se(c1->command_next == NULL);
415
416 log_info("/* empty argument, reset */");
417 r = config_parse_exec(NULL, "fake", 4, "section", 1,
418 "LValue", 0, "",
419 &c, u);
420 assert_se(r == 0);
421 assert_se(c == NULL);
422
423 exec_command_free_list(c);
424 }
425
426 static void test_config_parse_log_extra_fields(void) {
427 /* int config_parse_log_extra_fields(
428 const char *unit,
429 const char *filename,
430 unsigned line,
431 const char *section,
432 unsigned section_line,
433 const char *lvalue,
434 int ltype,
435 const char *rvalue,
436 void *data,
437 void *userdata) */
438
439 int r;
440
441 _cleanup_(manager_freep) Manager *m = NULL;
442 _cleanup_(unit_freep) Unit *u = NULL;
443 ExecContext c = {};
444
445 r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_MINIMAL, &m);
446 if (manager_errno_skip_test(r)) {
447 log_notice_errno(r, "Skipping test: manager_new: %m");
448 return;
449 }
450
451 assert_se(r >= 0);
452 assert_se(manager_startup(m, NULL, NULL) >= 0);
453
454 assert_se(u = unit_new(m, sizeof(Service)));
455
456 log_info("/* %s – basic test */", __func__);
457 r = config_parse_log_extra_fields(NULL, "fake", 1, "section", 1,
458 "LValue", 0, "FOO=BAR \"QOOF=quux ' ' \"",
459 &c, u);
460 assert_se(r >= 0);
461 assert_se(c.n_log_extra_fields == 2);
462 assert_se(strneq(c.log_extra_fields[0].iov_base, "FOO=BAR", c.log_extra_fields[0].iov_len));
463 assert_se(strneq(c.log_extra_fields[1].iov_base, "QOOF=quux ' ' ", c.log_extra_fields[1].iov_len));
464
465 log_info("/* %s – add some */", __func__);
466 r = config_parse_log_extra_fields(NULL, "fake", 1, "section", 1,
467 "LValue", 0, "FOO2=BAR2 QOOF2=quux ' '",
468 &c, u);
469 assert_se(r >= 0);
470 assert_se(c.n_log_extra_fields == 4);
471 assert_se(strneq(c.log_extra_fields[0].iov_base, "FOO=BAR", c.log_extra_fields[0].iov_len));
472 assert_se(strneq(c.log_extra_fields[1].iov_base, "QOOF=quux ' ' ", c.log_extra_fields[1].iov_len));
473 assert_se(strneq(c.log_extra_fields[2].iov_base, "FOO2=BAR2", c.log_extra_fields[2].iov_len));
474 assert_se(strneq(c.log_extra_fields[3].iov_base, "QOOF2=quux", c.log_extra_fields[3].iov_len));
475
476 exec_context_dump(&c, stdout, " --> ");
477
478 log_info("/* %s – reset */", __func__);
479 r = config_parse_log_extra_fields(NULL, "fake", 1, "section", 1,
480 "LValue", 0, "",
481 &c, u);
482 assert_se(r >= 0);
483 assert_se(c.n_log_extra_fields == 0);
484
485 exec_context_free_log_extra_fields(&c);
486
487 log_info("/* %s – bye */", __func__);
488 }
489
490 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, };
499
500 _cleanup_free_ char *mid = NULL, *bid = NULL, *host = NULL, *gid = NULL, *group = NULL, *uid = NULL, *user = NULL;
501
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);
509
510 #define expect(src, pattern, result) \
511 do { \
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); \
520 if (result) { \
521 printf("%s\n", t); \
522 assert_se(streq(t, result)); \
523 } else assert_se(t == NULL); \
524 strcpy(i.name, d1); \
525 strcpy(i.path, d2); \
526 } while (false)
527
528 expect(i, "%n", "name.service");
529 expect(i, "%N", "name");
530 expect(i, "%p", "name");
531 expect(i, "%i", "");
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);
537
538 expect(i, "%m", mid);
539 expect(i, "%b", bid);
540 expect(i, "%H", host);
541
542 expect(i2, "%g", group);
543 expect(i2, "%G", gid);
544 expect(i2, "%u", user);
545 expect(i2, "%U", uid);
546
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);
554
555 expect(i3, "%m", mid);
556 expect(i3, "%b", bid);
557 expect(i3, "%H", host);
558
559 expect(i4, "%g", group);
560 expect(i4, "%G", gid);
561 expect(i4, "%u", user);
562 expect(i4, "%U", uid);
563 }
564
565 static uint64_t make_cap(int cap) {
566 return ((uint64_t) 1ULL << (uint64_t) cap);
567 }
568
569 static void test_config_parse_capability_set(void) {
570 /* int config_parse_capability_set(
571 const char *unit,
572 const char *filename,
573 unsigned line,
574 const char *section,
575 unsigned section_line,
576 const char *lvalue,
577 int ltype,
578 const char *rvalue,
579 void *data,
580 void *userdata) */
581 int r;
582 uint64_t capability_bounding_set = 0;
583
584 r = config_parse_capability_set(NULL, "fake", 1, "section", 1,
585 "CapabilityBoundingSet", 0, "CAP_NET_RAW",
586 &capability_bounding_set, NULL);
587 assert_se(r >= 0);
588 assert_se(capability_bounding_set == make_cap(CAP_NET_RAW));
589
590 r = config_parse_capability_set(NULL, "fake", 1, "section", 1,
591 "CapabilityBoundingSet", 0, "CAP_NET_ADMIN",
592 &capability_bounding_set, NULL);
593 assert_se(r >= 0);
594 assert_se(capability_bounding_set == (make_cap(CAP_NET_RAW) | make_cap(CAP_NET_ADMIN)));
595
596 r = config_parse_capability_set(NULL, "fake", 1, "section", 1,
597 "CapabilityBoundingSet", 0, "~CAP_NET_ADMIN",
598 &capability_bounding_set, NULL);
599 assert_se(r >= 0);
600 assert_se(capability_bounding_set == make_cap(CAP_NET_RAW));
601
602 r = config_parse_capability_set(NULL, "fake", 1, "section", 1,
603 "CapabilityBoundingSet", 0, "",
604 &capability_bounding_set, NULL);
605 assert_se(r >= 0);
606 assert_se(capability_bounding_set == UINT64_C(0));
607
608 r = config_parse_capability_set(NULL, "fake", 1, "section", 1,
609 "CapabilityBoundingSet", 0, "~",
610 &capability_bounding_set, NULL);
611 assert_se(r >= 0);
612 assert_se(cap_test_all(capability_bounding_set));
613
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);
618 assert_se(r >= 0);
619 assert_se(capability_bounding_set == (make_cap(CAP_NET_RAW) | make_cap(CAP_NET_ADMIN)));
620 }
621
622 static void test_config_parse_rlimit(void) {
623 struct rlimit * rl[_RLIMIT_MAX] = {};
624
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);
629
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);
634
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);
639
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);
644
645 rl[RLIMIT_NOFILE]->rlim_cur = 10;
646 rl[RLIMIT_NOFILE]->rlim_max = 20;
647
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);
653
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);
658
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);
663
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);
668
669 rl[RLIMIT_NOFILE] = mfree(rl[RLIMIT_NOFILE]);
670
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);
675
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);
680
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);
685
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);
690
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);
695
696 rl[RLIMIT_CPU] = mfree(rl[RLIMIT_CPU]);
697
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);
702
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);
707
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);
712
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);
717
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);
722
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);
727
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);
732
733 rl[RLIMIT_RTTIME] = mfree(rl[RLIMIT_RTTIME]);
734 }
735
736 static void test_config_parse_pass_environ(void) {
737 /* int config_parse_pass_environ(
738 const char *unit,
739 const char *filename,
740 unsigned line,
741 const char *section,
742 unsigned section_line,
743 const char *lvalue,
744 int ltype,
745 const char *rvalue,
746 void *data,
747 void *userdata) */
748 int r;
749 _cleanup_strv_free_ char **passenv = NULL;
750
751 r = config_parse_pass_environ(NULL, "fake", 1, "section", 1,
752 "PassEnvironment", 0, "A B",
753 &passenv, NULL);
754 assert_se(r >= 0);
755 assert_se(strv_length(passenv) == 2);
756 assert_se(streq(passenv[0], "A"));
757 assert_se(streq(passenv[1], "B"));
758
759 r = config_parse_pass_environ(NULL, "fake", 1, "section", 1,
760 "PassEnvironment", 0, "",
761 &passenv, NULL);
762 assert_se(r >= 0);
763 assert_se(strv_isempty(passenv));
764
765 r = config_parse_pass_environ(NULL, "fake", 1, "section", 1,
766 "PassEnvironment", 0, "'invalid name' 'normal_name' A=1 \\",
767 &passenv, NULL);
768 assert_se(r >= 0);
769 assert_se(strv_length(passenv) == 1);
770 assert_se(streq(passenv[0], "normal_name"));
771
772 }
773
774 static void test_unit_dump_config_items(void) {
775 unit_dump_config_items(stdout);
776 }
777
778 static void test_config_parse_memory_limit(void) {
779 /* int config_parse_memory_limit(
780 const char *unit,
781 const char *filename,
782 unsigned line,
783 const char *section,
784 unsigned section_line,
785 const char *lvalue,
786 int ltype,
787 const char *rvalue,
788 void *data,
789 void *userdata) */
790 CGroupContext c;
791 struct limit_test {
792 const char *limit;
793 const char *value;
794 uint64_t *result;
795 uint64_t expected;
796 } limit_tests[]= {
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 },
813 };
814 size_t i;
815 int r;
816
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);
828 assert_se(r >= 0);
829 assert_se(*limit_tests[i].result == limit_tests[i].expected);
830 }
831
832 }
833
834 int main(int argc, char *argv[]) {
835 _cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL;
836 int r;
837
838 test_setup_logging(LOG_INFO);
839
840 r = enter_cgroup_subroot(NULL);
841 if (r == -ENOMEDIUM)
842 return log_tests_skipped("cgroupfs not available");
843
844 assert_se(runtime_dir = setup_fake_runtime_dir());
845
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();
855
856 return r;
857 }