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