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