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