]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/test/test-unit-file.c
Merge pull request #10088 from keszybz/man-systemctl-return
[thirdparty/systemd.git] / src / test / test-unit-file.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
b5b46d59 2
07630cea 3#include <fcntl.h>
b5b46d59 4#include <stddef.h>
07630cea 5#include <stdio.h>
b5b46d59 6#include <string.h>
a8107a54 7#include <sys/capability.h>
b9893505 8#include <unistd.h>
b5b46d59 9
b5efdb8a 10#include "alloc-util.h"
57b7a260 11#include "all-units.h"
a103496c 12#include "capability-util.h"
4f424df7 13#include "conf-parser.h"
3ffd4af2 14#include "fd-util.h"
07630cea 15#include "fileio.h"
627d2bac 16#include "fs-util.h"
b5b46d59 17#include "hashmap.h"
07630cea
LP
18#include "hostname-util.h"
19#include "install-printf.h"
20#include "install.h"
2c5417ad 21#include "load-fragment.h"
07630cea 22#include "macro.h"
d2120590 23#include "rm-rf.h"
07630cea
LP
24#include "specifier.h"
25#include "string-util.h"
b9893505 26#include "strv.h"
143bfdaf 27#include "test-helper.h"
d2120590 28#include "tests.h"
79413b67 29#include "user-util.h"
07630cea 30#include "util.h"
b5b46d59 31
751e7576 32static int test_unit_file_get_set(void) {
b5b46d59
LP
33 int r;
34 Hashmap *h;
35 Iterator i;
36 UnitFileList *p;
37
d5099efc 38 h = hashmap_new(&string_hash_ops);
bdf7026e 39 assert_se(h);
b5b46d59 40
313fe66f 41 r = unit_file_get_list(UNIT_FILE_SYSTEM, NULL, h, NULL, NULL);
730d989a
ZJS
42 if (IN_SET(r, -EPERM, -EACCES))
43 return log_tests_skipped_errno(r, "unit_file_get_list");
552c693e 44
9eec7d12
ZJS
45 log_full_errno(r == 0 ? LOG_INFO : LOG_ERR, r,
46 "unit_file_get_list: %m");
751e7576
CH
47 if (r < 0)
48 return EXIT_FAILURE;
b5b46d59
LP
49
50 HASHMAP_FOREACH(p, h, i)
51 printf("%s = %s\n", p->path, unit_file_state_to_string(p->state));
52
53 unit_file_list_free(h);
751e7576
CH
54
55 return 0;
2c5417ad
ZJS
56}
57
58static void check_execcommand(ExecCommand *c,
59 const char* path,
60 const char* argv0,
61 const char* argv1,
503dbda6 62 const char* argv2,
2c5417ad 63 bool ignore) {
4d8629de
ZJS
64 size_t n;
65
2c5417ad 66 assert_se(c);
c8539536
ZJS
67 log_info("expect: \"%s\" [\"%s\" \"%s\" \"%s\"]",
68 path, argv0 ?: path, argv1, argv2);
4d8629de 69 n = strv_length(c->argv);
c8539536 70 log_info("actual: \"%s\" [\"%s\" \"%s\" \"%s\"]",
4d8629de 71 c->path, c->argv[0], n > 0 ? c->argv[1] : NULL, n > 1 ? c->argv[2] : NULL);
2c5417ad 72 assert_se(streq(c->path, path));
c8539536 73 assert_se(streq(c->argv[0], argv0 ?: path));
4d8629de
ZJS
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));
3ed0cd26 78 assert_se(!!(c->flags & EXEC_COMMAND_IGNORE_FAILURE) == ignore);
2c5417ad
ZJS
79}
80
81static void test_config_parse_exec(void) {
c8539536 82 /* int config_parse_exec(
470dca63 83 const char *unit,
c8539536
ZJS
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) */
2c5417ad
ZJS
93 int r;
94
95 ExecCommand *c = NULL, *c1;
c8539536 96 const char *ccc;
c70cac54 97 _cleanup_(manager_freep) Manager *m = NULL;
dc409696 98 _cleanup_(unit_freep) Unit *u = NULL;
139891f0 99
e0a3da1f 100 r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_MINIMAL, &m);
139891f0 101 if (MANAGER_SKIP_TEST(r)) {
9eec7d12 102 log_notice_errno(r, "Skipping test: manager_new: %m");
139891f0
WC
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)));
2c5417ad 110
c8539536 111 log_info("/* basic test */");
71a61510 112 r = config_parse_exec(NULL, "fake", 1, "section", 1,
2c5417ad 113 "LValue", 0, "/RValue r1",
139891f0 114 &c, u);
2c5417ad 115 assert_se(r >= 0);
503dbda6 116 check_execcommand(c, "/RValue", "/RValue", "r1", NULL, false);
2c5417ad 117
71a61510 118 r = config_parse_exec(NULL, "fake", 2, "section", 1,
c8539536 119 "LValue", 0, "/RValue///slashes r1///",
139891f0 120 &c, u);
c8539536
ZJS
121
122 log_info("/* test slashes */");
2c5417ad
ZJS
123 assert_se(r >= 0);
124 c1 = c->command_next;
c8539536 125 check_execcommand(c1, "/RValue/slashes", "/RValue///slashes", "r1///", NULL, false);
2c5417ad 126
c8539536
ZJS
127 log_info("/* trailing slash */");
128 r = config_parse_exec(NULL, "fake", 4, "section", 1,
129 "LValue", 0, "/RValue/ argv0 r1",
139891f0 130 &c, u);
bb28e684 131 assert_se(r == -ENOEXEC);
c8539536
ZJS
132 assert_se(c1->command_next == NULL);
133
134 log_info("/* honour_argv0 */");
71a61510 135 r = config_parse_exec(NULL, "fake", 3, "section", 1,
c8539536 136 "LValue", 0, "@/RValue///slashes2 ///argv0 r1",
139891f0 137 &c, u);
2c5417ad
ZJS
138 assert_se(r >= 0);
139 c1 = c1->command_next;
c8539536 140 check_execcommand(c1, "/RValue/slashes2", "///argv0", "r1", NULL, false);
2c5417ad 141
e01ff428
ZJS
142 log_info("/* honour_argv0, no args */");
143 r = config_parse_exec(NULL, "fake", 3, "section", 1,
144 "LValue", 0, "@/RValue",
139891f0 145 &c, u);
bb28e684 146 assert_se(r == -ENOEXEC);
e01ff428
ZJS
147 assert_se(c1->command_next == NULL);
148
c83f1f30 149 log_info("/* no command, whitespace only, reset */");
e01ff428
ZJS
150 r = config_parse_exec(NULL, "fake", 3, "section", 1,
151 "LValue", 0, " ",
139891f0 152 &c, u);
e01ff428 153 assert_se(r == 0);
c83f1f30 154 assert_se(c == NULL);
e01ff428 155
c8539536 156 log_info("/* ignore && honour_argv0 */");
71a61510 157 r = config_parse_exec(NULL, "fake", 4, "section", 1,
c8539536 158 "LValue", 0, "-@/RValue///slashes3 argv0a r1",
139891f0 159 &c, u);
2c5417ad 160 assert_se(r >= 0);
c83f1f30 161 c1 = c;
503dbda6 162 check_execcommand(c1, "/RValue/slashes3", "argv0a", "r1", NULL, true);
2c5417ad 163
c8539536 164 log_info("/* ignore && honour_argv0 */");
71a61510 165 r = config_parse_exec(NULL, "fake", 4, "section", 1,
c8539536 166 "LValue", 0, "@-/RValue///slashes4 argv0b r1",
139891f0 167 &c, u);
0f67f1ef
ZJS
168 assert_se(r >= 0);
169 c1 = c1->command_next;
503dbda6 170 check_execcommand(c1, "/RValue/slashes4", "argv0b", "r1", NULL, true);
0f67f1ef 171
c8539536 172 log_info("/* ignore && ignore */");
71a61510 173 r = config_parse_exec(NULL, "fake", 4, "section", 1,
0f67f1ef 174 "LValue", 0, "--/RValue argv0 r1",
139891f0 175 &c, u);
0f67f1ef
ZJS
176 assert_se(r == 0);
177 assert_se(c1->command_next == NULL);
178
c8539536 179 log_info("/* ignore && ignore (2) */");
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("/* semicolon */");
71a61510 187 r = config_parse_exec(NULL, "fake", 5, "section", 1,
2c5417ad
ZJS
188 "LValue", 0,
189 "-@/RValue argv0 r1 ; "
190 "/goo/goo boo",
139891f0 191 &c, u);
2c5417ad
ZJS
192 assert_se(r >= 0);
193 c1 = c1->command_next;
503dbda6 194 check_execcommand(c1, "/RValue", "argv0", "r1", NULL, true);
2c5417ad
ZJS
195
196 c1 = c1->command_next;
c8539536 197 check_execcommand(c1, "/goo/goo", NULL, "boo", NULL, false);
2c5417ad 198
0e9800d5
FB
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",
139891f0 204 &c, u);
bb28e684 205 assert_se(r == -ENOEXEC);
0e9800d5
FB
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
c8539536 212 log_info("/* trailing semicolon */");
71a61510 213 r = config_parse_exec(NULL, "fake", 5, "section", 1,
2c5417ad
ZJS
214 "LValue", 0,
215 "-@/RValue argv0 r1 ; ",
139891f0 216 &c, u);
2c5417ad
ZJS
217 assert_se(r >= 0);
218 c1 = c1->command_next;
503dbda6 219 check_execcommand(c1, "/RValue", "argv0", "r1", NULL, true);
2c5417ad
ZJS
220
221 assert_se(c1->command_next == NULL);
222
0e9800d5
FB
223 log_info("/* trailing semicolon, no whitespace */");
224 r = config_parse_exec(NULL, "fake", 5, "section", 1,
225 "LValue", 0,
226 "-@/RValue argv0 r1 ;",
139891f0 227 &c, u);
0e9800d5
FB
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 ';'",
139891f0 238 &c, u);
0e9800d5
FB
239 assert_se(r >= 0);
240 c1 = c1->command_next;
46a0d98a 241 check_execcommand(c1, "/RValue", "argv0", "r1", ";", true);
0e9800d5 242
c8539536 243 log_info("/* escaped semicolon */");
71a61510 244 r = config_parse_exec(NULL, "fake", 5, "section", 1,
7e1a84f5 245 "LValue", 0,
503dbda6 246 "/bin/find \\;",
139891f0 247 &c, u);
503dbda6
ZJS
248 assert_se(r >= 0);
249 c1 = c1->command_next;
c8539536 250 check_execcommand(c1, "/bin/find", NULL, ";", NULL, false);
503dbda6 251
c8539536 252 log_info("/* escaped semicolon with following arg */");
503dbda6
ZJS
253 r = config_parse_exec(NULL, "fake", 5, "section", 1,
254 "LValue", 0,
0e9800d5 255 "/sbin/find \\; /x",
139891f0 256 &c, u);
0e9800d5
FB
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",
139891f0 266 &c, u);
7e1a84f5
OS
267 assert_se(r >= 0);
268 c1 = c1->command_next;
269 check_execcommand(c1,
0e9800d5 270 "/sbin/find", NULL, "\\;x", NULL, false);
c8539536 271
80979f1c
DM
272 log_info("/* encoded semicolon */");
273 r = config_parse_exec(NULL, "fake", 5, "section", 1,
274 "LValue", 0,
275 "/bin/find \\073",
139891f0 276 &c, u);
80979f1c
DM
277 assert_se(r >= 0);
278 c1 = c1->command_next;
ce54255f 279 check_execcommand(c1, "/bin/find", NULL, ";", NULL, false);
80979f1c 280
0e9800d5
FB
281 log_info("/* quoted semicolon */");
282 r = config_parse_exec(NULL, "fake", 5, "section", 1,
283 "LValue", 0,
284 "/bin/find \";\"",
139891f0 285 &c, u);
0e9800d5
FB
286 assert_se(r >= 0);
287 c1 = c1->command_next;
46a0d98a 288 check_execcommand(c1, "/bin/find", NULL, ";", NULL, false);
0e9800d5
FB
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",
139891f0 294 &c, u);
0e9800d5
FB
295 assert_se(r >= 0);
296 c1 = c1->command_next;
297 check_execcommand(c1,
46a0d98a 298 "/sbin/find", NULL, ";", "/x", false);
0e9800d5 299
c8539536
ZJS
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",
139891f0 304 &c, u);
c8539536
ZJS
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\"",
139891f0 314 &c, u);
c8539536
ZJS
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'",
139891f0 324 &c, u);
c8539536
ZJS
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'",
139891f0 334 &c, u);
c8539536
ZJS
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\"",
139891f0 344 &c, u);
c8539536
ZJS
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,
139891f0 358 &c, u);
bb28e684 359 assert_se(r == -ENOEXEC);
c8539536
ZJS
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",
139891f0 366 &c, u);
c8539536
ZJS
367 assert_se(r >= 0);
368 c1 = c1->command_next;
369 check_execcommand(c1, "/path ", NULL, NULL, NULL, false);
370
80979f1c
DM
371 log_info("/* quoted backslashes */");
372 r = config_parse_exec(NULL, "fake", 5, "section", 1,
373 "LValue", 0,
374 "/bin/grep '\\w+\\K'",
139891f0 375 &c, u);
80979f1c
DM
376 assert_se(r >= 0);
377 c1 = c1->command_next;
378 check_execcommand(c1, "/bin/grep", NULL, "\\w+\\K", NULL, false);
379
c8539536
ZJS
380 log_info("/* trailing backslash: \\ */");
381 /* backslash is invalid */
382 r = config_parse_exec(NULL, "fake", 4, "section", 1,
383 "LValue", 0, "/path\\",
139891f0 384 &c, u);
bb28e684 385 assert_se(r == -ENOEXEC);
c8539536 386 assert_se(c1->command_next == NULL);
7e1a84f5 387
470dca63
MP
388 log_info("/* missing ending ' */");
389 r = config_parse_exec(NULL, "fake", 4, "section", 1,
390 "LValue", 0, "/path 'foo",
139891f0 391 &c, u);
bb28e684 392 assert_se(r == -ENOEXEC);
470dca63
MP
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\\",
139891f0 398 &c, u);
bb28e684 399 assert_se(r == -ENOEXEC);
470dca63
MP
400 assert_se(c1->command_next == NULL);
401
35b1078e
MP
402 log_info("/* invalid space between modifiers */");
403 r = config_parse_exec(NULL, "fake", 4, "section", 1,
404 "LValue", 0, "- /path",
139891f0 405 &c, u);
35b1078e
MP
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, "-",
139891f0 412 &c, u);
35b1078e
MP
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, "",
139891f0 419 &c, u);
35b1078e
MP
420 assert_se(r == 0);
421 assert_se(c == NULL);
422
2c5417ad
ZJS
423 exec_command_free_list(c);
424}
425
88bff424
ZJS
426static 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
c70cac54 441 _cleanup_(manager_freep) Manager *m = NULL;
dc409696 442 _cleanup_(unit_freep) Unit *u = NULL;
88bff424
ZJS
443 ExecContext c = {};
444
445 r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_MINIMAL, &m);
446 if (MANAGER_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
88bff424
ZJS
487 log_info("/* %s – bye */", __func__);
488}
489
f73141d7
LP
490#define env_file_1 \
491 "a=a\n" \
492 "b=b\\\n" \
493 "c\n" \
494 "d=d\\\n" \
495 "e\\\n" \
496 "f\n" \
497 "g=g\\ \n" \
498 "h=h\n" \
499 "i=i\\"
500
501#define env_file_2 \
502 "a=a\\\n"
b9893505 503
a3aa7ee6
ZJS
504#define env_file_3 \
505 "#SPAMD_ARGS=\"-d --socketpath=/var/lib/bulwark/spamd \\\n" \
506 "#--nouser-config \\\n" \
507 "normal=line"
508
d3b6d0c2
ZJS
509#define env_file_4 \
510 "# Generated\n" \
511 "\n" \
512 "HWMON_MODULES=\"coretemp f71882fg\"\n" \
513 "\n" \
514 "# For compatibility reasons\n" \
515 "\n" \
516 "MODULE_0=coretemp\n" \
517 "MODULE_1=f71882fg"
518
58f10d40
ILG
519#define env_file_5 \
520 "a=\n" \
521 "b="
d3b6d0c2 522
b9893505 523static void test_load_env_file_1(void) {
7fd1b19b 524 _cleanup_strv_free_ char **data = NULL;
b9893505
ZJS
525 int r;
526
627d2bac 527 _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-load-env-file.XXXXXX";
2d5bdf5b
LP
528 _cleanup_close_ int fd;
529
646853bd 530 fd = mkostemp_safe(name);
bdf7026e 531 assert_se(fd >= 0);
b9893505
ZJS
532 assert_se(write(fd, env_file_1, sizeof(env_file_1)) == sizeof(env_file_1));
533
717603e3 534 r = load_env_file(NULL, name, NULL, &data);
bdf7026e
TA
535 assert_se(r == 0);
536 assert_se(streq(data[0], "a=a"));
537 assert_se(streq(data[1], "b=bc"));
538 assert_se(streq(data[2], "d=def"));
539 assert_se(streq(data[3], "g=g "));
540 assert_se(streq(data[4], "h=h"));
541 assert_se(streq(data[5], "i=i"));
542 assert_se(data[6] == NULL);
b9893505
ZJS
543}
544
545static void test_load_env_file_2(void) {
7fd1b19b 546 _cleanup_strv_free_ char **data = NULL;
b9893505
ZJS
547 int r;
548
627d2bac 549 _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-load-env-file.XXXXXX";
2d5bdf5b
LP
550 _cleanup_close_ int fd;
551
646853bd 552 fd = mkostemp_safe(name);
bdf7026e 553 assert_se(fd >= 0);
b9893505
ZJS
554 assert_se(write(fd, env_file_2, sizeof(env_file_2)) == sizeof(env_file_2));
555
717603e3 556 r = load_env_file(NULL, name, NULL, &data);
bdf7026e
TA
557 assert_se(r == 0);
558 assert_se(streq(data[0], "a=a"));
559 assert_se(data[1] == NULL);
b9893505
ZJS
560}
561
a3aa7ee6 562static void test_load_env_file_3(void) {
7fd1b19b 563 _cleanup_strv_free_ char **data = NULL;
a3aa7ee6
ZJS
564 int r;
565
627d2bac 566 _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-load-env-file.XXXXXX";
2d5bdf5b
LP
567 _cleanup_close_ int fd;
568
646853bd 569 fd = mkostemp_safe(name);
bdf7026e 570 assert_se(fd >= 0);
a3aa7ee6
ZJS
571 assert_se(write(fd, env_file_3, sizeof(env_file_3)) == sizeof(env_file_3));
572
717603e3 573 r = load_env_file(NULL, name, NULL, &data);
bdf7026e
TA
574 assert_se(r == 0);
575 assert_se(data == NULL);
a3aa7ee6
ZJS
576}
577
d3b6d0c2 578static void test_load_env_file_4(void) {
7fd1b19b 579 _cleanup_strv_free_ char **data = NULL;
627d2bac 580 _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-load-env-file.XXXXXX";
2d5bdf5b 581 _cleanup_close_ int fd;
d3b6d0c2
ZJS
582 int r;
583
646853bd 584 fd = mkostemp_safe(name);
bdf7026e 585 assert_se(fd >= 0);
d3b6d0c2
ZJS
586 assert_se(write(fd, env_file_4, sizeof(env_file_4)) == sizeof(env_file_4));
587
717603e3 588 r = load_env_file(NULL, name, NULL, &data);
bdf7026e
TA
589 assert_se(r == 0);
590 assert_se(streq(data[0], "HWMON_MODULES=coretemp f71882fg"));
591 assert_se(streq(data[1], "MODULE_0=coretemp"));
592 assert_se(streq(data[2], "MODULE_1=f71882fg"));
593 assert_se(data[3] == NULL);
d3b6d0c2
ZJS
594}
595
58f10d40
ILG
596static void test_load_env_file_5(void) {
597 _cleanup_strv_free_ char **data = NULL;
598 int r;
599
627d2bac 600 _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-load-env-file.XXXXXX";
58f10d40
ILG
601 _cleanup_close_ int fd;
602
646853bd 603 fd = mkostemp_safe(name);
58f10d40
ILG
604 assert_se(fd >= 0);
605 assert_se(write(fd, env_file_5, sizeof(env_file_5)) == sizeof(env_file_5));
606
607 r = load_env_file(NULL, name, NULL, &data);
608 assert_se(r == 0);
609 assert_se(streq(data[0], "a="));
610 assert_se(streq(data[1], "b="));
611 assert_se(data[2] == NULL);
58f10d40 612}
d3b6d0c2 613
7742f7e9
ZJS
614static void test_install_printf(void) {
615 char name[] = "name.service",
79413b67
LP
616 path[] = "/run/systemd/system/name.service";
617 UnitFileInstallInfo i = { .name = name, .path = path, };
618 UnitFileInstallInfo i2 = { .name= name, .path = path, };
7742f7e9 619 char name3[] = "name@inst.service",
ad88e758 620 path3[] = "/run/systemd/system/name.service";
79413b67
LP
621 UnitFileInstallInfo i3 = { .name = name3, .path = path3, };
622 UnitFileInstallInfo i4 = { .name = name3, .path = path3, };
7742f7e9 623
79413b67 624 _cleanup_free_ char *mid = NULL, *bid = NULL, *host = NULL, *uid = NULL, *user = NULL;
7742f7e9 625
19f6d710
LP
626 assert_se(specifier_machine_id('m', NULL, NULL, &mid) >= 0 && mid);
627 assert_se(specifier_boot_id('b', NULL, NULL, &bid) >= 0 && bid);
dcd6361e
ZJS
628 assert_se(host = gethostname_malloc());
629 assert_se(user = uid_to_name(getuid()));
79413b67 630 assert_se(asprintf(&uid, UID_FMT, getuid()) >= 0);
7742f7e9
ZJS
631
632#define expect(src, pattern, result) \
f73141d7 633 do { \
19f6d710 634 _cleanup_free_ char *t = NULL; \
7fd1b19b 635 _cleanup_free_ char \
7742f7e9 636 *d1 = strdup(i.name), \
79413b67 637 *d2 = strdup(i.path); \
19f6d710 638 assert_se(install_full_printf(&src, pattern, &t) >= 0 || !result); \
7742f7e9
ZJS
639 memzero(i.name, strlen(i.name)); \
640 memzero(i.path, strlen(i.path)); \
79413b67 641 assert_se(d1 && d2); \
7742f7e9
ZJS
642 if (result) { \
643 printf("%s\n", t); \
79413b67
LP
644 assert_se(streq(t, result)); \
645 } else assert_se(t == NULL); \
7742f7e9
ZJS
646 strcpy(i.name, d1); \
647 strcpy(i.path, d2); \
9ed794a3 648 } while (false)
7742f7e9 649
7742f7e9
ZJS
650 expect(i, "%n", "name.service");
651 expect(i, "%N", "name");
652 expect(i, "%p", "name");
653 expect(i, "%i", "");
250e9fad 654 expect(i, "%j", "name");
79413b67
LP
655 expect(i, "%u", user);
656 expect(i, "%U", uid);
8fca4e30 657
7742f7e9
ZJS
658 expect(i, "%m", mid);
659 expect(i, "%b", bid);
660 expect(i, "%H", host);
661
79413b67
LP
662 expect(i2, "%u", user);
663 expect(i2, "%U", uid);
7742f7e9
ZJS
664
665 expect(i3, "%n", "name@inst.service");
666 expect(i3, "%N", "name@inst");
667 expect(i3, "%p", "name");
79413b67
LP
668 expect(i3, "%u", user);
669 expect(i3, "%U", uid);
8fca4e30 670
7742f7e9
ZJS
671 expect(i3, "%m", mid);
672 expect(i3, "%b", bid);
673 expect(i3, "%H", host);
674
79413b67
LP
675 expect(i4, "%u", user);
676 expect(i4, "%U", uid);
7742f7e9 677}
b9893505 678
a8107a54
EV
679static uint64_t make_cap(int cap) {
680 return ((uint64_t) 1ULL << (uint64_t) cap);
681}
682
a103496c
IP
683static void test_config_parse_capability_set(void) {
684 /* int config_parse_capability_set(
a8107a54
EV
685 const char *unit,
686 const char *filename,
687 unsigned line,
688 const char *section,
689 unsigned section_line,
690 const char *lvalue,
691 int ltype,
692 const char *rvalue,
693 void *data,
694 void *userdata) */
695 int r;
a103496c 696 uint64_t capability_bounding_set = 0;
a8107a54 697
a103496c 698 r = config_parse_capability_set(NULL, "fake", 1, "section", 1,
a8107a54 699 "CapabilityBoundingSet", 0, "CAP_NET_RAW",
a103496c 700 &capability_bounding_set, NULL);
a8107a54 701 assert_se(r >= 0);
a103496c 702 assert_se(capability_bounding_set == make_cap(CAP_NET_RAW));
a8107a54 703
a103496c 704 r = config_parse_capability_set(NULL, "fake", 1, "section", 1,
a8107a54 705 "CapabilityBoundingSet", 0, "CAP_NET_ADMIN",
a103496c 706 &capability_bounding_set, NULL);
a8107a54 707 assert_se(r >= 0);
a103496c 708 assert_se(capability_bounding_set == (make_cap(CAP_NET_RAW) | make_cap(CAP_NET_ADMIN)));
a8107a54 709
7dd09746
YW
710 r = config_parse_capability_set(NULL, "fake", 1, "section", 1,
711 "CapabilityBoundingSet", 0, "~CAP_NET_ADMIN",
712 &capability_bounding_set, NULL);
713 assert_se(r >= 0);
714 assert_se(capability_bounding_set == make_cap(CAP_NET_RAW));
715
a103496c 716 r = config_parse_capability_set(NULL, "fake", 1, "section", 1,
a8107a54 717 "CapabilityBoundingSet", 0, "",
a103496c 718 &capability_bounding_set, NULL);
a8107a54 719 assert_se(r >= 0);
a103496c 720 assert_se(capability_bounding_set == UINT64_C(0));
a8107a54 721
a103496c 722 r = config_parse_capability_set(NULL, "fake", 1, "section", 1,
a8107a54 723 "CapabilityBoundingSet", 0, "~",
a103496c 724 &capability_bounding_set, NULL);
a8107a54 725 assert_se(r >= 0);
a103496c 726 assert_se(cap_test_all(capability_bounding_set));
4b03af4a 727
a103496c
IP
728 capability_bounding_set = 0;
729 r = config_parse_capability_set(NULL, "fake", 1, "section", 1,
4b03af4a 730 "CapabilityBoundingSet", 0, " 'CAP_NET_RAW' WAT_CAP??? CAP_NET_ADMIN CAP'_trailing_garbage",
a103496c 731 &capability_bounding_set, NULL);
4b03af4a 732 assert_se(r >= 0);
a103496c 733 assert_se(capability_bounding_set == (make_cap(CAP_NET_RAW) | make_cap(CAP_NET_ADMIN)));
a8107a54
EV
734}
735
a4c18002
LP
736static void test_config_parse_rlimit(void) {
737 struct rlimit * rl[_RLIMIT_MAX] = {};
738
4f424df7 739 assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "55", rl, NULL) >= 0);
a4c18002
LP
740 assert_se(rl[RLIMIT_NOFILE]);
741 assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 55);
742 assert_se(rl[RLIMIT_NOFILE]->rlim_cur == rl[RLIMIT_NOFILE]->rlim_max);
743
4f424df7 744 assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "55:66", rl, NULL) >= 0);
91518d20
KZ
745 assert_se(rl[RLIMIT_NOFILE]);
746 assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 55);
747 assert_se(rl[RLIMIT_NOFILE]->rlim_max == 66);
748
4f424df7 749 assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "infinity", rl, NULL) >= 0);
a4c18002
LP
750 assert_se(rl[RLIMIT_NOFILE]);
751 assert_se(rl[RLIMIT_NOFILE]->rlim_cur == RLIM_INFINITY);
752 assert_se(rl[RLIMIT_NOFILE]->rlim_cur == rl[RLIMIT_NOFILE]->rlim_max);
753
4f424df7 754 assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "infinity:infinity", rl, NULL) >= 0);
91518d20
KZ
755 assert_se(rl[RLIMIT_NOFILE]);
756 assert_se(rl[RLIMIT_NOFILE]->rlim_cur == RLIM_INFINITY);
757 assert_se(rl[RLIMIT_NOFILE]->rlim_cur == rl[RLIMIT_NOFILE]->rlim_max);
758
d0a7c5f6
LP
759 rl[RLIMIT_NOFILE]->rlim_cur = 10;
760 rl[RLIMIT_NOFILE]->rlim_max = 20;
761
762 /* Invalid values don't change rl */
4f424df7 763 assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "10:20:30", rl, NULL) >= 0);
0316f2ae
EV
764 assert_se(rl[RLIMIT_NOFILE]);
765 assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 10);
766 assert_se(rl[RLIMIT_NOFILE]->rlim_max == 20);
767
4f424df7 768 assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "wat:wat", rl, NULL) >= 0);
0316f2ae
EV
769 assert_se(rl[RLIMIT_NOFILE]);
770 assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 10);
771 assert_se(rl[RLIMIT_NOFILE]->rlim_max == 20);
772
4f424df7 773 assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "66:wat", rl, NULL) >= 0);
0316f2ae
EV
774 assert_se(rl[RLIMIT_NOFILE]);
775 assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 10);
776 assert_se(rl[RLIMIT_NOFILE]->rlim_max == 20);
777
4f424df7 778 assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "200:100", rl, NULL) >= 0);
0316f2ae
EV
779 assert_se(rl[RLIMIT_NOFILE]);
780 assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 10);
781 assert_se(rl[RLIMIT_NOFILE]->rlim_max == 20);
782
a4c18002
LP
783 rl[RLIMIT_NOFILE] = mfree(rl[RLIMIT_NOFILE]);
784
4f424df7 785 assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "56", rl, NULL) >= 0);
a4c18002
LP
786 assert_se(rl[RLIMIT_CPU]);
787 assert_se(rl[RLIMIT_CPU]->rlim_cur == 56);
788 assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max);
789
4f424df7 790 assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "57s", rl, NULL) >= 0);
a4c18002
LP
791 assert_se(rl[RLIMIT_CPU]);
792 assert_se(rl[RLIMIT_CPU]->rlim_cur == 57);
793 assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max);
794
4f424df7 795 assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "40s:1m", rl, NULL) >= 0);
91518d20
KZ
796 assert_se(rl[RLIMIT_CPU]);
797 assert_se(rl[RLIMIT_CPU]->rlim_cur == 40);
798 assert_se(rl[RLIMIT_CPU]->rlim_max == 60);
799
4f424df7 800 assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "infinity", rl, NULL) >= 0);
a4c18002
LP
801 assert_se(rl[RLIMIT_CPU]);
802 assert_se(rl[RLIMIT_CPU]->rlim_cur == RLIM_INFINITY);
803 assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max);
804
4f424df7 805 assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "1234ms", rl, NULL) >= 0);
a4c18002
LP
806 assert_se(rl[RLIMIT_CPU]);
807 assert_se(rl[RLIMIT_CPU]->rlim_cur == 2);
808 assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max);
809
810 rl[RLIMIT_CPU] = mfree(rl[RLIMIT_CPU]);
811
4f424df7 812 assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "58", rl, NULL) >= 0);
a4c18002
LP
813 assert_se(rl[RLIMIT_RTTIME]);
814 assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 58);
815 assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max);
816
4f424df7 817 assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "58:60", rl, NULL) >= 0);
91518d20
KZ
818 assert_se(rl[RLIMIT_RTTIME]);
819 assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 58);
820 assert_se(rl[RLIMIT_RTTIME]->rlim_max == 60);
821
4f424df7 822 assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "59s", rl, NULL) >= 0);
a4c18002
LP
823 assert_se(rl[RLIMIT_RTTIME]);
824 assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 59 * USEC_PER_SEC);
825 assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max);
826
4f424df7 827 assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "59s:123s", rl, NULL) >= 0);
91518d20
KZ
828 assert_se(rl[RLIMIT_RTTIME]);
829 assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 59 * USEC_PER_SEC);
830 assert_se(rl[RLIMIT_RTTIME]->rlim_max == 123 * USEC_PER_SEC);
831
4f424df7 832 assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "infinity", rl, NULL) >= 0);
a4c18002
LP
833 assert_se(rl[RLIMIT_RTTIME]);
834 assert_se(rl[RLIMIT_RTTIME]->rlim_cur == RLIM_INFINITY);
835 assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max);
836
4f424df7 837 assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "infinity:infinity", rl, NULL) >= 0);
91518d20
KZ
838 assert_se(rl[RLIMIT_RTTIME]);
839 assert_se(rl[RLIMIT_RTTIME]->rlim_cur == RLIM_INFINITY);
840 assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max);
841
4f424df7 842 assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "2345ms", rl, NULL) >= 0);
a4c18002
LP
843 assert_se(rl[RLIMIT_RTTIME]);
844 assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 2345 * USEC_PER_MSEC);
845 assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max);
846
847 rl[RLIMIT_RTTIME] = mfree(rl[RLIMIT_RTTIME]);
848}
849
4ad4beec
EV
850static void test_config_parse_pass_environ(void) {
851 /* int config_parse_pass_environ(
852 const char *unit,
853 const char *filename,
854 unsigned line,
855 const char *section,
856 unsigned section_line,
857 const char *lvalue,
858 int ltype,
859 const char *rvalue,
860 void *data,
861 void *userdata) */
862 int r;
863 _cleanup_strv_free_ char **passenv = NULL;
864
865 r = config_parse_pass_environ(NULL, "fake", 1, "section", 1,
866 "PassEnvironment", 0, "A B",
867 &passenv, NULL);
868 assert_se(r >= 0);
869 assert_se(strv_length(passenv) == 2);
870 assert_se(streq(passenv[0], "A"));
871 assert_se(streq(passenv[1], "B"));
872
873 r = config_parse_pass_environ(NULL, "fake", 1, "section", 1,
874 "PassEnvironment", 0, "",
875 &passenv, NULL);
876 assert_se(r >= 0);
877 assert_se(strv_isempty(passenv));
878
879 r = config_parse_pass_environ(NULL, "fake", 1, "section", 1,
880 "PassEnvironment", 0, "'invalid name' 'normal_name' A=1 \\",
881 &passenv, NULL);
882 assert_se(r >= 0);
883 assert_se(strv_length(passenv) == 1);
884 assert_se(streq(passenv[0], "normal_name"));
885
886}
887
0c700d39
EV
888static void test_unit_dump_config_items(void) {
889 unit_dump_config_items(stdout);
890}
891
2c5417ad 892int main(int argc, char *argv[]) {
f942504e 893 _cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL;
751e7576 894 int r;
2c5417ad 895
6d7c4033 896 test_setup_logging(LOG_INFO);
c1b6628d 897
651d47d1 898 r = enter_cgroup_subroot();
317bb217
ZJS
899 if (r == -ENOMEDIUM)
900 return log_tests_skipped("cgroupfs not available");
8c759b33 901
d2120590
LP
902 assert_se(runtime_dir = setup_fake_runtime_dir());
903
751e7576 904 r = test_unit_file_get_set();
2c5417ad 905 test_config_parse_exec();
88bff424 906 test_config_parse_log_extra_fields();
a103496c 907 test_config_parse_capability_set();
a4c18002 908 test_config_parse_rlimit();
4ad4beec 909 test_config_parse_pass_environ();
b9893505
ZJS
910 test_load_env_file_1();
911 test_load_env_file_2();
a3aa7ee6 912 test_load_env_file_3();
d3b6d0c2 913 test_load_env_file_4();
58f10d40 914 test_load_env_file_5();
143bfdaf 915 TEST_REQ_RUNNING_SYSTEMD(test_install_printf());
0c700d39 916 test_unit_dump_config_items();
b5b46d59 917
751e7576 918 return r;
b5b46d59 919}