chiark / gitweb /
always use the same code for creating temporary files
[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 <assert.h>
24 #include <stdio.h>
25 #include <stddef.h>
26 #include <string.h>
27 #include <unistd.h>
28 #include <fcntl.h>
29
30 #include "install.h"
31 #include "install-printf.h"
32 #include "specifier.h"
33 #include "util.h"
34 #include "macro.h"
35 #include "hashmap.h"
36 #include "load-fragment.h"
37 #include "strv.h"
38 #include "fileio.h"
39 #include "test-helper.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_func, string_compare_func);
48         assert(h);
49
50         r = unit_file_get_list(UNIT_FILE_SYSTEM, NULL, h);
51         log_full(r == 0 ? LOG_INFO : LOG_ERR,
52                  "unit_file_get_list: %s", strerror(-r));
53         if (r < 0)
54                 return EXIT_FAILURE;
55
56         HASHMAP_FOREACH(p, h, i)
57                 printf("%s = %s\n", p->path, unit_file_state_to_string(p->state));
58
59         unit_file_list_free(h);
60
61         return 0;
62 }
63
64 static void check_execcommand(ExecCommand *c,
65                               const char* path,
66                               const char* argv0,
67                               const char* argv1,
68                               bool ignore) {
69         assert_se(c);
70         log_info("%s %s %s %s",
71                  c->path, c->argv[0], c->argv[1], c->argv[2]);
72         assert_se(streq(c->path, path));
73         assert_se(streq(c->argv[0], argv0));
74         assert_se(streq(c->argv[1], argv1));
75         assert_se(c->argv[2] == NULL);
76         assert_se(c->ignore == ignore);
77 }
78
79 static void test_config_parse_exec(void) {
80         /* int config_parse_exec( */
81         /*         const char *filename, */
82         /*         unsigned line, */
83         /*         const char *section, */
84         /*         unsigned section_line, */
85         /*         const char *lvalue, */
86         /*         int ltype, */
87         /*         const char *rvalue, */
88         /*         void *data, */
89         /*         void *userdata) */
90         int r;
91
92         ExecCommand *c = NULL, *c1;
93
94         /* basic test */
95         r = config_parse_exec(NULL, "fake", 1, "section", 1,
96                               "LValue", 0, "/RValue r1",
97                               &c, NULL);
98         assert_se(r >= 0);
99         check_execcommand(c, "/RValue", "/RValue", "r1", false);
100
101         r = config_parse_exec(NULL, "fake", 2, "section", 1,
102                               "LValue", 0, "/RValue///slashes/// r1",
103                               &c, NULL);
104        /* test slashes */
105         assert_se(r >= 0);
106         c1 = c->command_next;
107         check_execcommand(c1, "/RValue/slashes", "/RValue///slashes///",
108                           "r1", false);
109
110         /* honour_argv0 */
111         r = config_parse_exec(NULL, "fake", 3, "section", 1,
112                               "LValue", 0, "@/RValue///slashes2/// argv0 r1",
113                               &c, NULL);
114         assert_se(r >= 0);
115         c1 = c1->command_next;
116         check_execcommand(c1, "/RValue/slashes2", "argv0", "r1", false);
117
118         /* ignore && honour_argv0 */
119         r = config_parse_exec(NULL, "fake", 4, "section", 1,
120                               "LValue", 0, "-@/RValue///slashes3/// argv0a r1",
121                               &c, NULL);
122         assert_se(r >= 0);
123         c1 = c1->command_next;
124         check_execcommand(c1,
125                           "/RValue/slashes3", "argv0a", "r1", true);
126
127         /* ignore && honour_argv0 */
128         r = config_parse_exec(NULL, "fake", 4, "section", 1,
129                               "LValue", 0, "@-/RValue///slashes4/// argv0b r1",
130                               &c, NULL);
131         assert_se(r >= 0);
132         c1 = c1->command_next;
133         check_execcommand(c1,
134                           "/RValue/slashes4", "argv0b", "r1", true);
135
136         /* ignore && ignore */
137         r = config_parse_exec(NULL, "fake", 4, "section", 1,
138                               "LValue", 0, "--/RValue argv0 r1",
139                               &c, NULL);
140         assert_se(r == 0);
141         assert_se(c1->command_next == NULL);
142
143         /* ignore && ignore */
144         r = config_parse_exec(NULL, "fake", 4, "section", 1,
145                               "LValue", 0, "-@-/RValue argv0 r1",
146                               &c, NULL);
147         assert_se(r == 0);
148         assert_se(c1->command_next == NULL);
149
150         /* semicolon */
151         r = config_parse_exec(NULL, "fake", 5, "section", 1,
152                               "LValue", 0,
153                               "-@/RValue argv0 r1 ; "
154                               "/goo/goo boo",
155                               &c, NULL);
156         assert_se(r >= 0);
157         c1 = c1->command_next;
158         check_execcommand(c1,
159                           "/RValue", "argv0", "r1", true);
160
161         c1 = c1->command_next;
162         check_execcommand(c1,
163                           "/goo/goo", "/goo/goo", "boo", false);
164
165         /* trailing semicolon */
166         r = config_parse_exec(NULL, "fake", 5, "section", 1,
167                               "LValue", 0,
168                               "-@/RValue argv0 r1 ; ",
169                               &c, NULL);
170         assert_se(r >= 0);
171         c1 = c1->command_next;
172         check_execcommand(c1,
173                           "/RValue", "argv0", "r1", true);
174
175         assert_se(c1->command_next == NULL);
176
177         /* escaped semicolon */
178         r = config_parse_exec(NULL, "fake", 5, "section", 1,
179                               "LValue", 0,
180                               "/usr/bin/find \\;",
181                               &c, NULL);
182         assert_se(r >= 0);
183         c1 = c1->command_next;
184         check_execcommand(c1,
185                           "/usr/bin/find", "/usr/bin/find", ";", false);
186
187         exec_command_free_list(c);
188 }
189
190 #define env_file_1                              \
191         "a=a\n"                                 \
192         "b=b\\\n"                               \
193         "c\n"                                   \
194         "d=d\\\n"                               \
195         "e\\\n"                                 \
196         "f\n"                                   \
197         "g=g\\ \n"                              \
198         "h=h\n"                                 \
199         "i=i\\"
200
201 #define env_file_2                              \
202         "a=a\\\n"
203
204 #define env_file_3 \
205         "#SPAMD_ARGS=\"-d --socketpath=/var/lib/bulwark/spamd \\\n" \
206         "#--nouser-config                                     \\\n" \
207         "normal=line"
208
209 #define env_file_4 \
210        "# Generated\n" \
211        "\n" \
212        "HWMON_MODULES=\"coretemp f71882fg\"\n" \
213        "\n" \
214        "# For compatibility reasons\n" \
215        "\n" \
216        "MODULE_0=coretemp\n" \
217        "MODULE_1=f71882fg"
218
219
220 static void test_load_env_file_1(void) {
221         _cleanup_strv_free_ char **data = NULL;
222         int r;
223
224         char name[] = "/tmp/test-load-env-file.XXXXXX";
225         _cleanup_close_ int fd;
226
227         fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC);
228         assert(fd >= 0);
229         assert_se(write(fd, env_file_1, sizeof(env_file_1)) == sizeof(env_file_1));
230
231         r = load_env_file(name, NULL, &data);
232         assert(r == 0);
233         assert(streq(data[0], "a=a"));
234         assert(streq(data[1], "b=bc"));
235         assert(streq(data[2], "d=def"));
236         assert(streq(data[3], "g=g "));
237         assert(streq(data[4], "h=h"));
238         assert(streq(data[5], "i=i"));
239         assert(data[6] == NULL);
240         unlink(name);
241 }
242
243 static void test_load_env_file_2(void) {
244         _cleanup_strv_free_ char **data = NULL;
245         int r;
246
247         char name[] = "/tmp/test-load-env-file.XXXXXX";
248         _cleanup_close_ int fd;
249
250         fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC);
251         assert(fd >= 0);
252         assert_se(write(fd, env_file_2, sizeof(env_file_2)) == sizeof(env_file_2));
253
254         r = load_env_file(name, NULL, &data);
255         assert(r == 0);
256         assert(streq(data[0], "a=a"));
257         assert(data[1] == NULL);
258         unlink(name);
259 }
260
261 static void test_load_env_file_3(void) {
262         _cleanup_strv_free_ char **data = NULL;
263         int r;
264
265         char name[] = "/tmp/test-load-env-file.XXXXXX";
266         _cleanup_close_ int fd;
267
268         fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC);
269         assert(fd >= 0);
270         assert_se(write(fd, env_file_3, sizeof(env_file_3)) == sizeof(env_file_3));
271
272         r = load_env_file(name, NULL, &data);
273         assert(r == 0);
274         assert(data == NULL);
275         unlink(name);
276 }
277
278 static void test_load_env_file_4(void) {
279         _cleanup_strv_free_ char **data = NULL;
280         char name[] = "/tmp/test-load-env-file.XXXXXX";
281         _cleanup_close_ int fd;
282         int r;
283
284         fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC);
285         assert(fd >= 0);
286         assert_se(write(fd, env_file_4, sizeof(env_file_4)) == sizeof(env_file_4));
287
288         r = load_env_file(name, NULL, &data);
289         assert(r == 0);
290         assert(streq(data[0], "HWMON_MODULES=coretemp f71882fg"));
291         assert(streq(data[1], "MODULE_0=coretemp"));
292         assert(streq(data[2], "MODULE_1=f71882fg"));
293         assert(data[3] == NULL);
294         unlink(name);
295 }
296
297
298 #pragma GCC diagnostic push
299 #pragma GCC diagnostic ignored "-Wnonnull"
300
301 static void test_install_printf(void) {
302         char    name[] = "name.service",
303                 path[] = "/run/systemd/system/name.service",
304                 user[] = "xxxx-no-such-user";
305         InstallInfo i = {name, path, user};
306         InstallInfo i2 = {name, path, NULL};
307         char    name3[] = "name@inst.service",
308                 path3[] = "/run/systemd/system/name.service";
309         InstallInfo i3 = {name3, path3, user};
310         InstallInfo i4 = {name3, path3, NULL};
311
312         _cleanup_free_ char *mid, *bid, *host;
313
314         assert_se(specifier_machine_id('m', NULL, NULL, &mid) >= 0 && mid);
315         assert_se(specifier_boot_id('b', NULL, NULL, &bid) >= 0 && bid);
316         assert_se((host = gethostname_malloc()));
317
318 #define expect(src, pattern, result)                                    \
319         do {                                                            \
320                 _cleanup_free_ char *t = NULL;                          \
321                 _cleanup_free_ char                                     \
322                         *d1 = strdup(i.name),                           \
323                         *d2 = strdup(i.path),                           \
324                         *d3 = strdup(i.user);                           \
325                 assert_se(install_full_printf(&src, pattern, &t) >= 0 || !result); \
326                 memzero(i.name, strlen(i.name));                        \
327                 memzero(i.path, strlen(i.path));                        \
328                 memzero(i.user, strlen(i.user));                        \
329                 assert(d1 && d2 && d3);                                 \
330                 if (result) {                                           \
331                         printf("%s\n", t);                              \
332                         assert(streq(t, result));                       \
333                 } else assert(t == NULL);                               \
334                 strcpy(i.name, d1);                                     \
335                 strcpy(i.path, d2);                                     \
336                 strcpy(i.user, d3);                                     \
337         } while(false)
338
339         assert_se(setenv("USER", "root", 1) == 0);
340
341         expect(i, "%n", "name.service");
342         expect(i, "%N", "name");
343         expect(i, "%p", "name");
344         expect(i, "%i", "");
345         expect(i, "%u", "xxxx-no-such-user");
346         expect(i, "%U", NULL);
347         expect(i, "%m", mid);
348         expect(i, "%b", bid);
349         expect(i, "%H", host);
350
351         expect(i2, "%u", "root");
352         expect(i2, "%U", "0");
353
354         expect(i3, "%n", "name@inst.service");
355         expect(i3, "%N", "name@inst");
356         expect(i3, "%p", "name");
357         expect(i3, "%u", "xxxx-no-such-user");
358         expect(i3, "%U", NULL);
359         expect(i3, "%m", mid);
360         expect(i3, "%b", bid);
361         expect(i3, "%H", host);
362
363         expect(i4, "%u", "root");
364         expect(i4, "%U", "0");
365 }
366 #pragma GCC diagnostic pop
367
368 int main(int argc, char *argv[]) {
369         int r;
370
371         log_parse_environment();
372         log_open();
373
374         r = test_unit_file_get_set();
375         test_config_parse_exec();
376         test_load_env_file_1();
377         test_load_env_file_2();
378         test_load_env_file_3();
379         test_load_env_file_4();
380         TEST_REQ_RUNNING_SYSTEMD(test_install_printf());
381
382         return r;
383 }