]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/test/test-unit-file.c
remove unused includes
[thirdparty/systemd.git] / src / test / test-unit-file.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2012 Lennart Poettering
7 Copyright 2013 Zbigniew Jędrzejewski-Szmek
8
9 systemd is free software; you can redistribute it and/or modify it
10 under the terms of the GNU Lesser General Public License as published by
11 the Free Software Foundation; either version 2.1 of the License, or
12 (at your option) any later version.
13
14 systemd is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Lesser General Public License for more details.
18
19 You should have received a copy of the GNU Lesser General Public License
20 along with systemd; If not, see <http://www.gnu.org/licenses/>.
21 ***/
22
23 #include <stdio.h>
24 #include <stddef.h>
25 #include <string.h>
26 #include <unistd.h>
27 #include <fcntl.h>
28
29 #include "install.h"
30 #include "install-printf.h"
31 #include "specifier.h"
32 #include "util.h"
33 #include "macro.h"
34 #include "hashmap.h"
35 #include "load-fragment.h"
36 #include "strv.h"
37 #include "fileio.h"
38 #include "test-helper.h"
39
40 static int test_unit_file_get_set(void) {
41 int r;
42 Hashmap *h;
43 Iterator i;
44 UnitFileList *p;
45
46 h = hashmap_new(&string_hash_ops);
47 assert_se(h);
48
49 r = unit_file_get_list(UNIT_FILE_SYSTEM, NULL, h);
50
51 if (r == -EPERM || r == -EACCES) {
52 printf("Skipping test: unit_file_get_list: %s", strerror(-r));
53 return EXIT_TEST_SKIP;
54 }
55
56 log_full(r == 0 ? LOG_INFO : LOG_ERR,
57 "unit_file_get_list: %s", strerror(-r));
58 if (r < 0)
59 return EXIT_FAILURE;
60
61 HASHMAP_FOREACH(p, h, i)
62 printf("%s = %s\n", p->path, unit_file_state_to_string(p->state));
63
64 unit_file_list_free(h);
65
66 return 0;
67 }
68
69 static void check_execcommand(ExecCommand *c,
70 const char* path,
71 const char* argv0,
72 const char* argv1,
73 const char* argv2,
74 bool ignore) {
75 size_t n;
76
77 assert_se(c);
78 log_info("expect: \"%s\" [\"%s\" \"%s\" \"%s\"]",
79 path, argv0 ?: path, argv1, argv2);
80 n = strv_length(c->argv);
81 log_info("actual: \"%s\" [\"%s\" \"%s\" \"%s\"]",
82 c->path, c->argv[0], n > 0 ? c->argv[1] : NULL, n > 1 ? c->argv[2] : NULL);
83 assert_se(streq(c->path, path));
84 assert_se(streq(c->argv[0], argv0 ?: path));
85 if (n > 0)
86 assert_se(streq_ptr(c->argv[1], argv1));
87 if (n > 1)
88 assert_se(streq_ptr(c->argv[2], argv2));
89 assert_se(c->ignore == ignore);
90 }
91
92 static void test_config_parse_exec(void) {
93 /* int config_parse_exec(
94 const char *filename,
95 unsigned line,
96 const char *section,
97 unsigned section_line,
98 const char *lvalue,
99 int ltype,
100 const char *rvalue,
101 void *data,
102 void *userdata) */
103 int r;
104
105 ExecCommand *c = NULL, *c1;
106 const char *ccc;
107
108 log_info("/* basic test */");
109 r = config_parse_exec(NULL, "fake", 1, "section", 1,
110 "LValue", 0, "/RValue r1",
111 &c, NULL);
112 assert_se(r >= 0);
113 check_execcommand(c, "/RValue", "/RValue", "r1", NULL, false);
114
115 r = config_parse_exec(NULL, "fake", 2, "section", 1,
116 "LValue", 0, "/RValue///slashes r1///",
117 &c, NULL);
118
119 log_info("/* test slashes */");
120 assert_se(r >= 0);
121 c1 = c->command_next;
122 check_execcommand(c1, "/RValue/slashes", "/RValue///slashes", "r1///", NULL, false);
123
124 log_info("/* trailing slash */");
125 r = config_parse_exec(NULL, "fake", 4, "section", 1,
126 "LValue", 0, "/RValue/ argv0 r1",
127 &c, NULL);
128 assert_se(r == 0);
129 assert_se(c1->command_next == NULL);
130
131 log_info("/* honour_argv0 */");
132 r = config_parse_exec(NULL, "fake", 3, "section", 1,
133 "LValue", 0, "@/RValue///slashes2 ///argv0 r1",
134 &c, NULL);
135 assert_se(r >= 0);
136 c1 = c1->command_next;
137 check_execcommand(c1, "/RValue/slashes2", "///argv0", "r1", NULL, false);
138
139 log_info("/* honour_argv0, no args */");
140 r = config_parse_exec(NULL, "fake", 3, "section", 1,
141 "LValue", 0, "@/RValue",
142 &c, NULL);
143 assert_se(r == 0);
144 assert_se(c1->command_next == NULL);
145
146 log_info("/* no command, check for bad memory access */");
147 r = config_parse_exec(NULL, "fake", 3, "section", 1,
148 "LValue", 0, " ",
149 &c, NULL);
150 assert_se(r == 0);
151 assert_se(c1->command_next == NULL);
152
153 log_info("/* ignore && honour_argv0 */");
154 r = config_parse_exec(NULL, "fake", 4, "section", 1,
155 "LValue", 0, "-@/RValue///slashes3 argv0a r1",
156 &c, NULL);
157 assert_se(r >= 0);
158 c1 = c1->command_next;
159 check_execcommand(c1, "/RValue/slashes3", "argv0a", "r1", NULL, true);
160
161 log_info("/* ignore && honour_argv0 */");
162 r = config_parse_exec(NULL, "fake", 4, "section", 1,
163 "LValue", 0, "@-/RValue///slashes4 argv0b r1",
164 &c, NULL);
165 assert_se(r >= 0);
166 c1 = c1->command_next;
167 check_execcommand(c1, "/RValue/slashes4", "argv0b", "r1", NULL, true);
168
169 log_info("/* ignore && ignore */");
170 r = config_parse_exec(NULL, "fake", 4, "section", 1,
171 "LValue", 0, "--/RValue argv0 r1",
172 &c, NULL);
173 assert_se(r == 0);
174 assert_se(c1->command_next == NULL);
175
176 log_info("/* ignore && ignore (2) */");
177 r = config_parse_exec(NULL, "fake", 4, "section", 1,
178 "LValue", 0, "-@-/RValue argv0 r1",
179 &c, NULL);
180 assert_se(r == 0);
181 assert_se(c1->command_next == NULL);
182
183 log_info("/* semicolon */");
184 r = config_parse_exec(NULL, "fake", 5, "section", 1,
185 "LValue", 0,
186 "-@/RValue argv0 r1 ; "
187 "/goo/goo boo",
188 &c, NULL);
189 assert_se(r >= 0);
190 c1 = c1->command_next;
191 check_execcommand(c1, "/RValue", "argv0", "r1", NULL, true);
192
193 c1 = c1->command_next;
194 check_execcommand(c1, "/goo/goo", NULL, "boo", NULL, false);
195
196 log_info("/* trailing semicolon */");
197 r = config_parse_exec(NULL, "fake", 5, "section", 1,
198 "LValue", 0,
199 "-@/RValue argv0 r1 ; ",
200 &c, NULL);
201 assert_se(r >= 0);
202 c1 = c1->command_next;
203 check_execcommand(c1, "/RValue", "argv0", "r1", NULL, true);
204
205 assert_se(c1->command_next == NULL);
206
207 log_info("/* escaped semicolon */");
208 r = config_parse_exec(NULL, "fake", 5, "section", 1,
209 "LValue", 0,
210 "/bin/find \\;",
211 &c, NULL);
212 assert_se(r >= 0);
213 c1 = c1->command_next;
214 check_execcommand(c1, "/bin/find", NULL, ";", NULL, false);
215
216 log_info("/* escaped semicolon with following arg */");
217 r = config_parse_exec(NULL, "fake", 5, "section", 1,
218 "LValue", 0,
219 "/sbin/find \\; x",
220 &c, NULL);
221 assert_se(r >= 0);
222 c1 = c1->command_next;
223 check_execcommand(c1,
224 "/sbin/find", NULL, ";", "x", false);
225
226 log_info("/* spaces in the filename */");
227 r = config_parse_exec(NULL, "fake", 5, "section", 1,
228 "LValue", 0,
229 "\"/PATH WITH SPACES/daemon\" -1 -2",
230 &c, NULL);
231 assert_se(r >= 0);
232 c1 = c1->command_next;
233 check_execcommand(c1,
234 "/PATH WITH SPACES/daemon", NULL, "-1", "-2", false);
235
236 log_info("/* spaces in the filename, no args */");
237 r = config_parse_exec(NULL, "fake", 5, "section", 1,
238 "LValue", 0,
239 "\"/PATH WITH SPACES/daemon -1 -2\"",
240 &c, NULL);
241 assert_se(r >= 0);
242 c1 = c1->command_next;
243 check_execcommand(c1,
244 "/PATH WITH SPACES/daemon -1 -2", NULL, NULL, NULL, false);
245
246 log_info("/* spaces in the filename, everything quoted */");
247 r = config_parse_exec(NULL, "fake", 5, "section", 1,
248 "LValue", 0,
249 "\"/PATH WITH SPACES/daemon\" \"-1\" '-2'",
250 &c, NULL);
251 assert_se(r >= 0);
252 c1 = c1->command_next;
253 check_execcommand(c1,
254 "/PATH WITH SPACES/daemon", NULL, "-1", "-2", false);
255
256 log_info("/* escaped spaces in the filename */");
257 r = config_parse_exec(NULL, "fake", 5, "section", 1,
258 "LValue", 0,
259 "\"/PATH\\sWITH\\sSPACES/daemon\" '-1 -2'",
260 &c, NULL);
261 assert_se(r >= 0);
262 c1 = c1->command_next;
263 check_execcommand(c1,
264 "/PATH WITH SPACES/daemon", NULL, "-1 -2", NULL, false);
265
266 log_info("/* escaped spaces in the filename (2) */");
267 r = config_parse_exec(NULL, "fake", 5, "section", 1,
268 "LValue", 0,
269 "\"/PATH\\x20WITH\\x20SPACES/daemon\" \"-1 -2\"",
270 &c, NULL);
271 assert_se(r >= 0);
272 c1 = c1->command_next;
273 check_execcommand(c1,
274 "/PATH WITH SPACES/daemon", NULL, "-1 -2", NULL, false);
275
276 for (ccc = "abfnrtv\\\'\"x"; *ccc; ccc++) {
277 /* \\x is an incomplete hexadecimal sequence, invalid because of the slash */
278 char path[] = "/path\\X";
279 path[sizeof(path) - 2] = *ccc;
280
281 log_info("/* invalid character: \\%c */", *ccc);
282 r = config_parse_exec(NULL, "fake", 4, "section", 1,
283 "LValue", 0, path,
284 &c, NULL);
285 assert_se(r == 0);
286 assert_se(c1->command_next == NULL);
287 }
288
289 log_info("/* valid character: \\s */");
290 r = config_parse_exec(NULL, "fake", 4, "section", 1,
291 "LValue", 0, "/path\\s",
292 &c, NULL);
293 assert_se(r >= 0);
294 c1 = c1->command_next;
295 check_execcommand(c1, "/path ", NULL, NULL, NULL, false);
296
297 log_info("/* trailing backslash: \\ */");
298 /* backslash is invalid */
299 r = config_parse_exec(NULL, "fake", 4, "section", 1,
300 "LValue", 0, "/path\\",
301 &c, NULL);
302 assert_se(r == 0);
303 assert_se(c1->command_next == NULL);
304
305 exec_command_free_list(c);
306 }
307
308 #define env_file_1 \
309 "a=a\n" \
310 "b=b\\\n" \
311 "c\n" \
312 "d=d\\\n" \
313 "e\\\n" \
314 "f\n" \
315 "g=g\\ \n" \
316 "h=h\n" \
317 "i=i\\"
318
319 #define env_file_2 \
320 "a=a\\\n"
321
322 #define env_file_3 \
323 "#SPAMD_ARGS=\"-d --socketpath=/var/lib/bulwark/spamd \\\n" \
324 "#--nouser-config \\\n" \
325 "normal=line"
326
327 #define env_file_4 \
328 "# Generated\n" \
329 "\n" \
330 "HWMON_MODULES=\"coretemp f71882fg\"\n" \
331 "\n" \
332 "# For compatibility reasons\n" \
333 "\n" \
334 "MODULE_0=coretemp\n" \
335 "MODULE_1=f71882fg"
336
337 #define env_file_5 \
338 "a=\n" \
339 "b="
340
341 static void test_load_env_file_1(void) {
342 _cleanup_strv_free_ char **data = NULL;
343 int r;
344
345 char name[] = "/tmp/test-load-env-file.XXXXXX";
346 _cleanup_close_ int fd;
347
348 fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC);
349 assert_se(fd >= 0);
350 assert_se(write(fd, env_file_1, sizeof(env_file_1)) == sizeof(env_file_1));
351
352 r = load_env_file(NULL, name, NULL, &data);
353 assert_se(r == 0);
354 assert_se(streq(data[0], "a=a"));
355 assert_se(streq(data[1], "b=bc"));
356 assert_se(streq(data[2], "d=def"));
357 assert_se(streq(data[3], "g=g "));
358 assert_se(streq(data[4], "h=h"));
359 assert_se(streq(data[5], "i=i"));
360 assert_se(data[6] == NULL);
361 unlink(name);
362 }
363
364 static void test_load_env_file_2(void) {
365 _cleanup_strv_free_ char **data = NULL;
366 int r;
367
368 char name[] = "/tmp/test-load-env-file.XXXXXX";
369 _cleanup_close_ int fd;
370
371 fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC);
372 assert_se(fd >= 0);
373 assert_se(write(fd, env_file_2, sizeof(env_file_2)) == sizeof(env_file_2));
374
375 r = load_env_file(NULL, name, NULL, &data);
376 assert_se(r == 0);
377 assert_se(streq(data[0], "a=a"));
378 assert_se(data[1] == NULL);
379 unlink(name);
380 }
381
382 static void test_load_env_file_3(void) {
383 _cleanup_strv_free_ char **data = NULL;
384 int r;
385
386 char name[] = "/tmp/test-load-env-file.XXXXXX";
387 _cleanup_close_ int fd;
388
389 fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC);
390 assert_se(fd >= 0);
391 assert_se(write(fd, env_file_3, sizeof(env_file_3)) == sizeof(env_file_3));
392
393 r = load_env_file(NULL, name, NULL, &data);
394 assert_se(r == 0);
395 assert_se(data == NULL);
396 unlink(name);
397 }
398
399 static void test_load_env_file_4(void) {
400 _cleanup_strv_free_ char **data = NULL;
401 char name[] = "/tmp/test-load-env-file.XXXXXX";
402 _cleanup_close_ int fd;
403 int r;
404
405 fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC);
406 assert_se(fd >= 0);
407 assert_se(write(fd, env_file_4, sizeof(env_file_4)) == sizeof(env_file_4));
408
409 r = load_env_file(NULL, name, NULL, &data);
410 assert_se(r == 0);
411 assert_se(streq(data[0], "HWMON_MODULES=coretemp f71882fg"));
412 assert_se(streq(data[1], "MODULE_0=coretemp"));
413 assert_se(streq(data[2], "MODULE_1=f71882fg"));
414 assert_se(data[3] == NULL);
415 unlink(name);
416 }
417
418 static void test_load_env_file_5(void) {
419 _cleanup_strv_free_ char **data = NULL;
420 int r;
421
422 char name[] = "/tmp/test-load-env-file.XXXXXX";
423 _cleanup_close_ int fd;
424
425 fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC);
426 assert_se(fd >= 0);
427 assert_se(write(fd, env_file_5, sizeof(env_file_5)) == sizeof(env_file_5));
428
429 r = load_env_file(NULL, name, NULL, &data);
430 assert_se(r == 0);
431 assert_se(streq(data[0], "a="));
432 assert_se(streq(data[1], "b="));
433 assert_se(data[2] == NULL);
434 unlink(name);
435 }
436
437 static void test_install_printf(void) {
438 char name[] = "name.service",
439 path[] = "/run/systemd/system/name.service",
440 user[] = "xxxx-no-such-user";
441 InstallInfo i = {name, path, user};
442 InstallInfo i2 = {name, path, NULL};
443 char name3[] = "name@inst.service",
444 path3[] = "/run/systemd/system/name.service";
445 InstallInfo i3 = {name3, path3, user};
446 InstallInfo i4 = {name3, path3, NULL};
447
448 _cleanup_free_ char *mid, *bid, *host;
449
450 assert_se(specifier_machine_id('m', NULL, NULL, &mid) >= 0 && mid);
451 assert_se(specifier_boot_id('b', NULL, NULL, &bid) >= 0 && bid);
452 assert_se((host = gethostname_malloc()));
453
454 #define expect(src, pattern, result) \
455 do { \
456 _cleanup_free_ char *t = NULL; \
457 _cleanup_free_ char \
458 *d1 = strdup(i.name), \
459 *d2 = strdup(i.path), \
460 *d3 = strdup(i.user); \
461 assert_se(install_full_printf(&src, pattern, &t) >= 0 || !result); \
462 memzero(i.name, strlen(i.name)); \
463 memzero(i.path, strlen(i.path)); \
464 memzero(i.user, strlen(i.user)); \
465 assert_se(d1 && d2 && d3); \
466 if (result) { \
467 printf("%s\n", t); \
468 assert_se(streq(t, result)); \
469 } else assert_se(t == NULL); \
470 strcpy(i.name, d1); \
471 strcpy(i.path, d2); \
472 strcpy(i.user, d3); \
473 } while(false)
474
475 assert_se(setenv("USER", "root", 1) == 0);
476
477 expect(i, "%n", "name.service");
478 expect(i, "%N", "name");
479 expect(i, "%p", "name");
480 expect(i, "%i", "");
481 expect(i, "%u", "xxxx-no-such-user");
482
483 DISABLE_WARNING_NONNULL;
484 expect(i, "%U", NULL);
485 REENABLE_WARNING;
486
487 expect(i, "%m", mid);
488 expect(i, "%b", bid);
489 expect(i, "%H", host);
490
491 expect(i2, "%u", "root");
492 expect(i2, "%U", "0");
493
494 expect(i3, "%n", "name@inst.service");
495 expect(i3, "%N", "name@inst");
496 expect(i3, "%p", "name");
497 expect(i3, "%u", "xxxx-no-such-user");
498
499 DISABLE_WARNING_NONNULL;
500 expect(i3, "%U", NULL);
501 REENABLE_WARNING;
502
503 expect(i3, "%m", mid);
504 expect(i3, "%b", bid);
505 expect(i3, "%H", host);
506
507 expect(i4, "%u", "root");
508 expect(i4, "%U", "0");
509 }
510
511 int main(int argc, char *argv[]) {
512 int r;
513
514 log_parse_environment();
515 log_open();
516
517 r = test_unit_file_get_set();
518 test_config_parse_exec();
519 test_load_env_file_1();
520 test_load_env_file_2();
521 test_load_env_file_3();
522 test_load_env_file_4();
523 test_load_env_file_5();
524 TEST_REQ_RUNNING_SYSTEMD(test_install_printf());
525
526 return r;
527 }