]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/test/test-unit-file.c
test-unit-file: don't access out-of-bounds memory
[thirdparty/systemd.git] / src / test / test-unit-file.c
CommitLineData
b5b46d59
LP
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
b9893505 7 Copyright 2013 Zbigniew Jędrzejewski-Szmek
b5b46d59
LP
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 <assert.h>
24#include <stdio.h>
25#include <stddef.h>
26#include <string.h>
b9893505 27#include <unistd.h>
2d5bdf5b 28#include <fcntl.h>
b5b46d59
LP
29
30#include "install.h"
7742f7e9
ZJS
31#include "install-printf.h"
32#include "specifier.h"
b5b46d59
LP
33#include "util.h"
34#include "macro.h"
35#include "hashmap.h"
2c5417ad 36#include "load-fragment.h"
b9893505 37#include "strv.h"
a5c32cff 38#include "fileio.h"
143bfdaf 39#include "test-helper.h"
b5b46d59 40
751e7576 41static int test_unit_file_get_set(void) {
b5b46d59
LP
42 int r;
43 Hashmap *h;
44 Iterator i;
45 UnitFileList *p;
46
d5099efc 47 h = hashmap_new(&string_hash_ops);
bdf7026e 48 assert_se(h);
b5b46d59
LP
49
50 r = unit_file_get_list(UNIT_FILE_SYSTEM, NULL, h);
552c693e
CR
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
751e7576
CH
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;
b5b46d59
LP
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);
751e7576
CH
66
67 return 0;
2c5417ad
ZJS
68}
69
70static void check_execcommand(ExecCommand *c,
71 const char* path,
72 const char* argv0,
73 const char* argv1,
503dbda6 74 const char* argv2,
2c5417ad 75 bool ignore) {
4d8629de
ZJS
76 size_t n;
77
2c5417ad 78 assert_se(c);
c8539536
ZJS
79 log_info("expect: \"%s\" [\"%s\" \"%s\" \"%s\"]",
80 path, argv0 ?: path, argv1, argv2);
4d8629de 81 n = strv_length(c->argv);
c8539536 82 log_info("actual: \"%s\" [\"%s\" \"%s\" \"%s\"]",
4d8629de 83 c->path, c->argv[0], n > 0 ? c->argv[1] : NULL, n > 1 ? c->argv[2] : NULL);
2c5417ad 84 assert_se(streq(c->path, path));
c8539536 85 assert_se(streq(c->argv[0], argv0 ?: path));
4d8629de
ZJS
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));
2c5417ad
ZJS
90 assert_se(c->ignore == ignore);
91}
92
93static void test_config_parse_exec(void) {
c8539536
ZJS
94 /* int config_parse_exec(
95 const char *filename,
96 unsigned line,
97 const char *section,
98 unsigned section_line,
99 const char *lvalue,
100 int ltype,
101 const char *rvalue,
102 void *data,
103 void *userdata) */
2c5417ad
ZJS
104 int r;
105
106 ExecCommand *c = NULL, *c1;
c8539536 107 const char *ccc;
2c5417ad 108
c8539536 109 log_info("/* basic test */");
71a61510 110 r = config_parse_exec(NULL, "fake", 1, "section", 1,
2c5417ad
ZJS
111 "LValue", 0, "/RValue r1",
112 &c, NULL);
113 assert_se(r >= 0);
503dbda6 114 check_execcommand(c, "/RValue", "/RValue", "r1", NULL, false);
2c5417ad 115
71a61510 116 r = config_parse_exec(NULL, "fake", 2, "section", 1,
c8539536 117 "LValue", 0, "/RValue///slashes r1///",
2c5417ad 118 &c, NULL);
c8539536
ZJS
119
120 log_info("/* test slashes */");
2c5417ad
ZJS
121 assert_se(r >= 0);
122 c1 = c->command_next;
c8539536 123 check_execcommand(c1, "/RValue/slashes", "/RValue///slashes", "r1///", NULL, false);
2c5417ad 124
c8539536
ZJS
125 log_info("/* trailing slash */");
126 r = config_parse_exec(NULL, "fake", 4, "section", 1,
127 "LValue", 0, "/RValue/ argv0 r1",
128 &c, NULL);
129 assert_se(r == 0);
130 assert_se(c1->command_next == NULL);
131
132 log_info("/* honour_argv0 */");
71a61510 133 r = config_parse_exec(NULL, "fake", 3, "section", 1,
c8539536 134 "LValue", 0, "@/RValue///slashes2 ///argv0 r1",
2c5417ad
ZJS
135 &c, NULL);
136 assert_se(r >= 0);
137 c1 = c1->command_next;
c8539536 138 check_execcommand(c1, "/RValue/slashes2", "///argv0", "r1", NULL, false);
2c5417ad 139
c8539536 140 log_info("/* ignore && honour_argv0 */");
71a61510 141 r = config_parse_exec(NULL, "fake", 4, "section", 1,
c8539536 142 "LValue", 0, "-@/RValue///slashes3 argv0a r1",
2c5417ad
ZJS
143 &c, NULL);
144 assert_se(r >= 0);
145 c1 = c1->command_next;
503dbda6 146 check_execcommand(c1, "/RValue/slashes3", "argv0a", "r1", NULL, true);
2c5417ad 147
c8539536 148 log_info("/* ignore && honour_argv0 */");
71a61510 149 r = config_parse_exec(NULL, "fake", 4, "section", 1,
c8539536 150 "LValue", 0, "@-/RValue///slashes4 argv0b r1",
0f67f1ef
ZJS
151 &c, NULL);
152 assert_se(r >= 0);
153 c1 = c1->command_next;
503dbda6 154 check_execcommand(c1, "/RValue/slashes4", "argv0b", "r1", NULL, true);
0f67f1ef 155
c8539536 156 log_info("/* ignore && ignore */");
71a61510 157 r = config_parse_exec(NULL, "fake", 4, "section", 1,
0f67f1ef
ZJS
158 "LValue", 0, "--/RValue argv0 r1",
159 &c, NULL);
160 assert_se(r == 0);
161 assert_se(c1->command_next == NULL);
162
c8539536 163 log_info("/* ignore && ignore (2) */");
71a61510 164 r = config_parse_exec(NULL, "fake", 4, "section", 1,
0f67f1ef
ZJS
165 "LValue", 0, "-@-/RValue argv0 r1",
166 &c, NULL);
167 assert_se(r == 0);
168 assert_se(c1->command_next == NULL);
169
c8539536 170 log_info("/* semicolon */");
71a61510 171 r = config_parse_exec(NULL, "fake", 5, "section", 1,
2c5417ad
ZJS
172 "LValue", 0,
173 "-@/RValue argv0 r1 ; "
174 "/goo/goo boo",
175 &c, NULL);
176 assert_se(r >= 0);
177 c1 = c1->command_next;
503dbda6 178 check_execcommand(c1, "/RValue", "argv0", "r1", NULL, true);
2c5417ad
ZJS
179
180 c1 = c1->command_next;
c8539536 181 check_execcommand(c1, "/goo/goo", NULL, "boo", NULL, false);
2c5417ad 182
c8539536 183 log_info("/* trailing semicolon */");
71a61510 184 r = config_parse_exec(NULL, "fake", 5, "section", 1,
2c5417ad
ZJS
185 "LValue", 0,
186 "-@/RValue argv0 r1 ; ",
187 &c, NULL);
188 assert_se(r >= 0);
189 c1 = c1->command_next;
503dbda6 190 check_execcommand(c1, "/RValue", "argv0", "r1", NULL, true);
2c5417ad
ZJS
191
192 assert_se(c1->command_next == NULL);
193
c8539536 194 log_info("/* escaped semicolon */");
71a61510 195 r = config_parse_exec(NULL, "fake", 5, "section", 1,
7e1a84f5 196 "LValue", 0,
503dbda6
ZJS
197 "/bin/find \\;",
198 &c, NULL);
199 assert_se(r >= 0);
200 c1 = c1->command_next;
c8539536 201 check_execcommand(c1, "/bin/find", NULL, ";", NULL, false);
503dbda6 202
c8539536 203 log_info("/* escaped semicolon with following arg */");
503dbda6
ZJS
204 r = config_parse_exec(NULL, "fake", 5, "section", 1,
205 "LValue", 0,
206 "/sbin/find \\; x",
7e1a84f5
OS
207 &c, NULL);
208 assert_se(r >= 0);
209 c1 = c1->command_next;
210 check_execcommand(c1,
c8539536
ZJS
211 "/sbin/find", NULL, ";", "x", false);
212
213 log_info("/* spaces in the filename */");
214 r = config_parse_exec(NULL, "fake", 5, "section", 1,
215 "LValue", 0,
216 "\"/PATH WITH SPACES/daemon\" -1 -2",
217 &c, NULL);
218 assert_se(r >= 0);
219 c1 = c1->command_next;
220 check_execcommand(c1,
221 "/PATH WITH SPACES/daemon", NULL, "-1", "-2", false);
222
223 log_info("/* spaces in the filename, no args */");
224 r = config_parse_exec(NULL, "fake", 5, "section", 1,
225 "LValue", 0,
226 "\"/PATH WITH SPACES/daemon -1 -2\"",
227 &c, NULL);
228 assert_se(r >= 0);
229 c1 = c1->command_next;
230 check_execcommand(c1,
231 "/PATH WITH SPACES/daemon -1 -2", NULL, NULL, NULL, false);
232
233 log_info("/* spaces in the filename, everything quoted */");
234 r = config_parse_exec(NULL, "fake", 5, "section", 1,
235 "LValue", 0,
236 "\"/PATH WITH SPACES/daemon\" \"-1\" '-2'",
237 &c, NULL);
238 assert_se(r >= 0);
239 c1 = c1->command_next;
240 check_execcommand(c1,
241 "/PATH WITH SPACES/daemon", NULL, "-1", "-2", false);
242
243 log_info("/* escaped spaces in the filename */");
244 r = config_parse_exec(NULL, "fake", 5, "section", 1,
245 "LValue", 0,
246 "\"/PATH\\sWITH\\sSPACES/daemon\" '-1 -2'",
247 &c, NULL);
248 assert_se(r >= 0);
249 c1 = c1->command_next;
250 check_execcommand(c1,
251 "/PATH WITH SPACES/daemon", NULL, "-1 -2", NULL, false);
252
253 log_info("/* escaped spaces in the filename (2) */");
254 r = config_parse_exec(NULL, "fake", 5, "section", 1,
255 "LValue", 0,
256 "\"/PATH\\x20WITH\\x20SPACES/daemon\" \"-1 -2\"",
257 &c, NULL);
258 assert_se(r >= 0);
259 c1 = c1->command_next;
260 check_execcommand(c1,
261 "/PATH WITH SPACES/daemon", NULL, "-1 -2", NULL, false);
262
263 for (ccc = "abfnrtv\\\'\"x"; *ccc; ccc++) {
264 /* \\x is an incomplete hexadecimal sequence, invalid because of the slash */
265 char path[] = "/path\\X";
266 path[sizeof(path) - 2] = *ccc;
267
268 log_info("/* invalid character: \\%c */", *ccc);
269 r = config_parse_exec(NULL, "fake", 4, "section", 1,
270 "LValue", 0, path,
271 &c, NULL);
272 assert_se(r == 0);
273 assert_se(c1->command_next == NULL);
274 }
275
276 log_info("/* valid character: \\s */");
277 r = config_parse_exec(NULL, "fake", 4, "section", 1,
278 "LValue", 0, "/path\\s",
279 &c, NULL);
280 assert_se(r >= 0);
281 c1 = c1->command_next;
282 check_execcommand(c1, "/path ", NULL, NULL, NULL, false);
283
284 log_info("/* trailing backslash: \\ */");
285 /* backslash is invalid */
286 r = config_parse_exec(NULL, "fake", 4, "section", 1,
287 "LValue", 0, "/path\\",
288 &c, NULL);
289 assert_se(r == 0);
290 assert_se(c1->command_next == NULL);
7e1a84f5 291
2c5417ad
ZJS
292 exec_command_free_list(c);
293}
294
f73141d7
LP
295#define env_file_1 \
296 "a=a\n" \
297 "b=b\\\n" \
298 "c\n" \
299 "d=d\\\n" \
300 "e\\\n" \
301 "f\n" \
302 "g=g\\ \n" \
303 "h=h\n" \
304 "i=i\\"
305
306#define env_file_2 \
307 "a=a\\\n"
b9893505 308
a3aa7ee6
ZJS
309#define env_file_3 \
310 "#SPAMD_ARGS=\"-d --socketpath=/var/lib/bulwark/spamd \\\n" \
311 "#--nouser-config \\\n" \
312 "normal=line"
313
d3b6d0c2
ZJS
314#define env_file_4 \
315 "# Generated\n" \
316 "\n" \
317 "HWMON_MODULES=\"coretemp f71882fg\"\n" \
318 "\n" \
319 "# For compatibility reasons\n" \
320 "\n" \
321 "MODULE_0=coretemp\n" \
322 "MODULE_1=f71882fg"
323
58f10d40
ILG
324#define env_file_5 \
325 "a=\n" \
326 "b="
d3b6d0c2 327
b9893505 328static void test_load_env_file_1(void) {
7fd1b19b 329 _cleanup_strv_free_ char **data = NULL;
b9893505
ZJS
330 int r;
331
332 char name[] = "/tmp/test-load-env-file.XXXXXX";
2d5bdf5b
LP
333 _cleanup_close_ int fd;
334
335 fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC);
bdf7026e 336 assert_se(fd >= 0);
b9893505
ZJS
337 assert_se(write(fd, env_file_1, sizeof(env_file_1)) == sizeof(env_file_1));
338
717603e3 339 r = load_env_file(NULL, name, NULL, &data);
bdf7026e
TA
340 assert_se(r == 0);
341 assert_se(streq(data[0], "a=a"));
342 assert_se(streq(data[1], "b=bc"));
343 assert_se(streq(data[2], "d=def"));
344 assert_se(streq(data[3], "g=g "));
345 assert_se(streq(data[4], "h=h"));
346 assert_se(streq(data[5], "i=i"));
347 assert_se(data[6] == NULL);
b9893505
ZJS
348 unlink(name);
349}
350
351static void test_load_env_file_2(void) {
7fd1b19b 352 _cleanup_strv_free_ char **data = NULL;
b9893505
ZJS
353 int r;
354
355 char name[] = "/tmp/test-load-env-file.XXXXXX";
2d5bdf5b
LP
356 _cleanup_close_ int fd;
357
358 fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC);
bdf7026e 359 assert_se(fd >= 0);
b9893505
ZJS
360 assert_se(write(fd, env_file_2, sizeof(env_file_2)) == sizeof(env_file_2));
361
717603e3 362 r = load_env_file(NULL, name, NULL, &data);
bdf7026e
TA
363 assert_se(r == 0);
364 assert_se(streq(data[0], "a=a"));
365 assert_se(data[1] == NULL);
b9893505
ZJS
366 unlink(name);
367}
368
a3aa7ee6 369static void test_load_env_file_3(void) {
7fd1b19b 370 _cleanup_strv_free_ char **data = NULL;
a3aa7ee6
ZJS
371 int r;
372
373 char name[] = "/tmp/test-load-env-file.XXXXXX";
2d5bdf5b
LP
374 _cleanup_close_ int fd;
375
376 fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC);
bdf7026e 377 assert_se(fd >= 0);
a3aa7ee6
ZJS
378 assert_se(write(fd, env_file_3, sizeof(env_file_3)) == sizeof(env_file_3));
379
717603e3 380 r = load_env_file(NULL, name, NULL, &data);
bdf7026e
TA
381 assert_se(r == 0);
382 assert_se(data == NULL);
a3aa7ee6
ZJS
383 unlink(name);
384}
385
d3b6d0c2 386static void test_load_env_file_4(void) {
7fd1b19b 387 _cleanup_strv_free_ char **data = NULL;
2d5bdf5b
LP
388 char name[] = "/tmp/test-load-env-file.XXXXXX";
389 _cleanup_close_ int fd;
d3b6d0c2
ZJS
390 int r;
391
2d5bdf5b 392 fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC);
bdf7026e 393 assert_se(fd >= 0);
d3b6d0c2
ZJS
394 assert_se(write(fd, env_file_4, sizeof(env_file_4)) == sizeof(env_file_4));
395
717603e3 396 r = load_env_file(NULL, name, NULL, &data);
bdf7026e
TA
397 assert_se(r == 0);
398 assert_se(streq(data[0], "HWMON_MODULES=coretemp f71882fg"));
399 assert_se(streq(data[1], "MODULE_0=coretemp"));
400 assert_se(streq(data[2], "MODULE_1=f71882fg"));
401 assert_se(data[3] == NULL);
d3b6d0c2
ZJS
402 unlink(name);
403}
404
58f10d40
ILG
405static void test_load_env_file_5(void) {
406 _cleanup_strv_free_ char **data = NULL;
407 int r;
408
409 char name[] = "/tmp/test-load-env-file.XXXXXX";
410 _cleanup_close_ int fd;
411
412 fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC);
413 assert_se(fd >= 0);
414 assert_se(write(fd, env_file_5, sizeof(env_file_5)) == sizeof(env_file_5));
415
416 r = load_env_file(NULL, name, NULL, &data);
417 assert_se(r == 0);
418 assert_se(streq(data[0], "a="));
419 assert_se(streq(data[1], "b="));
420 assert_se(data[2] == NULL);
421 unlink(name);
422}
d3b6d0c2 423
7742f7e9
ZJS
424static void test_install_printf(void) {
425 char name[] = "name.service",
ad88e758 426 path[] = "/run/systemd/system/name.service",
7742f7e9
ZJS
427 user[] = "xxxx-no-such-user";
428 InstallInfo i = {name, path, user};
429 InstallInfo i2 = {name, path, NULL};
430 char name3[] = "name@inst.service",
ad88e758 431 path3[] = "/run/systemd/system/name.service";
7742f7e9
ZJS
432 InstallInfo i3 = {name3, path3, user};
433 InstallInfo i4 = {name3, path3, NULL};
434
7fd1b19b 435 _cleanup_free_ char *mid, *bid, *host;
7742f7e9 436
19f6d710
LP
437 assert_se(specifier_machine_id('m', NULL, NULL, &mid) >= 0 && mid);
438 assert_se(specifier_boot_id('b', NULL, NULL, &bid) >= 0 && bid);
7742f7e9
ZJS
439 assert_se((host = gethostname_malloc()));
440
441#define expect(src, pattern, result) \
f73141d7 442 do { \
19f6d710 443 _cleanup_free_ char *t = NULL; \
7fd1b19b 444 _cleanup_free_ char \
7742f7e9
ZJS
445 *d1 = strdup(i.name), \
446 *d2 = strdup(i.path), \
447 *d3 = strdup(i.user); \
19f6d710 448 assert_se(install_full_printf(&src, pattern, &t) >= 0 || !result); \
7742f7e9
ZJS
449 memzero(i.name, strlen(i.name)); \
450 memzero(i.path, strlen(i.path)); \
451 memzero(i.user, strlen(i.user)); \
bdf7026e 452 assert_se(d1 && d2 && d3); \
7742f7e9
ZJS
453 if (result) { \
454 printf("%s\n", t); \
bdf7026e
TA
455 assert_se(streq(t, result)); \
456 } else assert_se(t == NULL); \
7742f7e9
ZJS
457 strcpy(i.name, d1); \
458 strcpy(i.path, d2); \
459 strcpy(i.user, d3); \
f73141d7 460 } while(false)
7742f7e9
ZJS
461
462 assert_se(setenv("USER", "root", 1) == 0);
463
464 expect(i, "%n", "name.service");
465 expect(i, "%N", "name");
466 expect(i, "%p", "name");
467 expect(i, "%i", "");
468 expect(i, "%u", "xxxx-no-such-user");
8fca4e30
LP
469
470 DISABLE_WARNING_NONNULL;
7742f7e9 471 expect(i, "%U", NULL);
8fca4e30
LP
472 REENABLE_WARNING;
473
7742f7e9
ZJS
474 expect(i, "%m", mid);
475 expect(i, "%b", bid);
476 expect(i, "%H", host);
477
478 expect(i2, "%u", "root");
479 expect(i2, "%U", "0");
480
481 expect(i3, "%n", "name@inst.service");
482 expect(i3, "%N", "name@inst");
483 expect(i3, "%p", "name");
484 expect(i3, "%u", "xxxx-no-such-user");
8fca4e30
LP
485
486 DISABLE_WARNING_NONNULL;
7742f7e9 487 expect(i3, "%U", NULL);
8fca4e30
LP
488 REENABLE_WARNING;
489
7742f7e9
ZJS
490 expect(i3, "%m", mid);
491 expect(i3, "%b", bid);
492 expect(i3, "%H", host);
493
494 expect(i4, "%u", "root");
495 expect(i4, "%U", "0");
496}
b9893505 497
2c5417ad 498int main(int argc, char *argv[]) {
751e7576 499 int r;
2c5417ad 500
c1b6628d
ZJS
501 log_parse_environment();
502 log_open();
503
751e7576 504 r = test_unit_file_get_set();
2c5417ad 505 test_config_parse_exec();
b9893505
ZJS
506 test_load_env_file_1();
507 test_load_env_file_2();
a3aa7ee6 508 test_load_env_file_3();
d3b6d0c2 509 test_load_env_file_4();
58f10d40 510 test_load_env_file_5();
143bfdaf 511 TEST_REQ_RUNNING_SYSTEMD(test_install_printf());
b5b46d59 512
751e7576 513 return r;
b5b46d59 514}