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