chiark / gitweb /
remove unused includes
[elogind.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 }