]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/test/test-env-util.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / test / test-env-util.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright 2010 Lennart Poettering
6 Copyright 2016 Zbigniew Jędrzejewski-Szmek
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <string.h>
23
24 #include "env-util.h"
25 #include "fd-util.h"
26 #include "fileio.h"
27 #include "string-util.h"
28 #include "strv.h"
29 #include "util.h"
30
31 static void test_strv_env_delete(void) {
32 _cleanup_strv_free_ char **a = NULL, **b = NULL, **c = NULL, **d = NULL;
33
34 a = strv_new("FOO=BAR", "WALDO=WALDO", "WALDO=", "PIEP", "SCHLUMPF=SMURF", NULL);
35 assert_se(a);
36
37 b = strv_new("PIEP", "FOO", NULL);
38 assert_se(b);
39
40 c = strv_new("SCHLUMPF", NULL);
41 assert_se(c);
42
43 d = strv_env_delete(a, 2, b, c);
44 assert_se(d);
45
46 assert_se(streq(d[0], "WALDO=WALDO"));
47 assert_se(streq(d[1], "WALDO="));
48 assert_se(strv_length(d) == 2);
49 }
50
51 static void test_strv_env_get(void) {
52 char **l;
53
54 l = STRV_MAKE("ONE_OR_TWO=1", "THREE=3", "ONE_OR_TWO=2", "FOUR=4");
55
56 assert_se(streq(strv_env_get(l, "ONE_OR_TWO"), "2"));
57 assert_se(streq(strv_env_get(l, "THREE"), "3"));
58 assert_se(streq(strv_env_get(l, "FOUR"), "4"));
59 }
60
61 static void test_strv_env_unset(void) {
62 _cleanup_strv_free_ char **l = NULL;
63
64 l = strv_new("PIEP", "SCHLUMPF=SMURFF", "NANANANA=YES", NULL);
65 assert_se(l);
66
67 assert_se(strv_env_unset(l, "SCHLUMPF") == l);
68
69 assert_se(streq(l[0], "PIEP"));
70 assert_se(streq(l[1], "NANANANA=YES"));
71 assert_se(strv_length(l) == 2);
72 }
73
74 static void test_strv_env_set(void) {
75 _cleanup_strv_free_ char **l = NULL, **r = NULL;
76
77 l = strv_new("PIEP", "SCHLUMPF=SMURFF", "NANANANA=YES", NULL);
78 assert_se(l);
79
80 r = strv_env_set(l, "WALDO=WALDO");
81 assert_se(r);
82
83 assert_se(streq(r[0], "PIEP"));
84 assert_se(streq(r[1], "SCHLUMPF=SMURFF"));
85 assert_se(streq(r[2], "NANANANA=YES"));
86 assert_se(streq(r[3], "WALDO=WALDO"));
87 assert_se(strv_length(r) == 4);
88 }
89
90 static void test_strv_env_merge(void) {
91 _cleanup_strv_free_ char **a = NULL, **b = NULL, **r = NULL;
92
93 a = strv_new("FOO=BAR", "WALDO=WALDO", "WALDO=", "PIEP", "SCHLUMPF=SMURF", NULL);
94 assert_se(a);
95
96 b = strv_new("FOO=KKK", "FOO=", "PIEP=", "SCHLUMPF=SMURFF", "NANANANA=YES", NULL);
97 assert_se(b);
98
99 r = strv_env_merge(2, a, b);
100 assert_se(r);
101 assert_se(streq(r[0], "FOO="));
102 assert_se(streq(r[1], "WALDO="));
103 assert_se(streq(r[2], "PIEP"));
104 assert_se(streq(r[3], "SCHLUMPF=SMURFF"));
105 assert_se(streq(r[4], "PIEP="));
106 assert_se(streq(r[5], "NANANANA=YES"));
107 assert_se(strv_length(r) == 6);
108
109 assert_se(strv_env_clean(r) == r);
110 assert_se(streq(r[0], "FOO="));
111 assert_se(streq(r[1], "WALDO="));
112 assert_se(streq(r[2], "SCHLUMPF=SMURFF"));
113 assert_se(streq(r[3], "PIEP="));
114 assert_se(streq(r[4], "NANANANA=YES"));
115 assert_se(strv_length(r) == 5);
116 }
117
118 static void test_env_strv_get_n(void) {
119 const char *_env[] = {
120 "FOO=NO NO NO",
121 "FOO=BAR BAR",
122 "BAR=waldo",
123 "PATH=unset",
124 NULL
125 };
126 char **env = (char**) _env;
127
128 assert_se(streq(strv_env_get_n(env, "FOO__", 3, 0), "BAR BAR"));
129 assert_se(streq(strv_env_get_n(env, "FOO__", 3, REPLACE_ENV_USE_ENVIRONMENT), "BAR BAR"));
130 assert_se(streq(strv_env_get_n(env, "FOO", 3, 0), "BAR BAR"));
131 assert_se(streq(strv_env_get_n(env, "FOO", 3, REPLACE_ENV_USE_ENVIRONMENT), "BAR BAR"));
132
133 assert_se(streq(strv_env_get_n(env, "PATH__", 4, 0), "unset"));
134 assert_se(streq(strv_env_get_n(env, "PATH", 4, 0), "unset"));
135 assert_se(streq(strv_env_get_n(env, "PATH__", 4, REPLACE_ENV_USE_ENVIRONMENT), "unset"));
136 assert_se(streq(strv_env_get_n(env, "PATH", 4, REPLACE_ENV_USE_ENVIRONMENT), "unset"));
137
138 env[3] = NULL; /* kill our $PATH */
139
140 assert_se(!strv_env_get_n(env, "PATH__", 4, 0));
141 assert_se(!strv_env_get_n(env, "PATH", 4, 0));
142 assert_se(streq(strv_env_get_n(env, "PATH__", 4, REPLACE_ENV_USE_ENVIRONMENT),
143 getenv("PATH")));
144 assert_se(streq(strv_env_get_n(env, "PATH", 4, REPLACE_ENV_USE_ENVIRONMENT),
145 getenv("PATH")));
146 }
147
148 static void test_replace_env(bool braceless) {
149 const char *env[] = {
150 "FOO=BAR BAR",
151 "BAR=waldo",
152 NULL
153 };
154 _cleanup_free_ char *t = NULL, *s = NULL, *q = NULL, *r = NULL, *p = NULL;
155 unsigned flags = REPLACE_ENV_ALLOW_BRACELESS*braceless;
156
157 t = replace_env("FOO=$FOO=${FOO}", (char**) env, flags);
158 assert_se(streq(t, braceless ? "FOO=BAR BAR=BAR BAR" : "FOO=$FOO=BAR BAR"));
159
160 s = replace_env("BAR=$BAR=${BAR}", (char**) env, flags);
161 assert_se(streq(s, braceless ? "BAR=waldo=waldo" : "BAR=$BAR=waldo"));
162
163 q = replace_env("BARBAR=$BARBAR=${BARBAR}", (char**) env, flags);
164 assert_se(streq(q, braceless ? "BARBAR==" : "BARBAR=$BARBAR="));
165
166 r = replace_env("BAR=$BAR$BAR${BAR}${BAR}", (char**) env, flags);
167 assert_se(streq(r, braceless ? "BAR=waldowaldowaldowaldo" : "BAR=$BAR$BARwaldowaldo"));
168
169 p = replace_env("${BAR}$BAR$BAR", (char**) env, flags);
170 assert_se(streq(p, braceless ? "waldowaldowaldo" : "waldo$BAR$BAR"));
171 }
172
173 static void test_replace_env2(bool extended) {
174 const char *env[] = {
175 "FOO=foo",
176 "BAR=bar",
177 NULL
178 };
179 _cleanup_free_ char *t = NULL, *s = NULL, *q = NULL, *r = NULL, *p = NULL, *x = NULL;
180 unsigned flags = REPLACE_ENV_ALLOW_EXTENDED*extended;
181
182 t = replace_env("FOO=${FOO:-${BAR}}", (char**) env, flags);
183 assert_se(streq(t, extended ? "FOO=foo" : "FOO=${FOO:-bar}"));
184
185 s = replace_env("BAR=${XXX:-${BAR}}", (char**) env, flags);
186 assert_se(streq(s, extended ? "BAR=bar" : "BAR=${XXX:-bar}"));
187
188 q = replace_env("XXX=${XXX:+${BAR}}", (char**) env, flags);
189 assert_se(streq(q, extended ? "XXX=" : "XXX=${XXX:+bar}"));
190
191 r = replace_env("FOO=${FOO:+${BAR}}", (char**) env, flags);
192 assert_se(streq(r, extended ? "FOO=bar" : "FOO=${FOO:+bar}"));
193
194 p = replace_env("FOO=${FOO:-${BAR}post}", (char**) env, flags);
195 assert_se(streq(p, extended ? "FOO=foo" : "FOO=${FOO:-barpost}"));
196
197 x = replace_env("XXX=${XXX:+${BAR}post}", (char**) env, flags);
198 assert_se(streq(x, extended ? "XXX=" : "XXX=${XXX:+barpost}"));
199 }
200
201 static void test_replace_env_argv(void) {
202 const char *env[] = {
203 "FOO=BAR BAR",
204 "BAR=waldo",
205 NULL
206 };
207 const char *line[] = {
208 "FOO$FOO",
209 "FOO$FOOFOO",
210 "FOO${FOO}$FOO",
211 "FOO${FOO}",
212 "${FOO}",
213 "$FOO",
214 "$FOO$FOO",
215 "${FOO}${BAR}",
216 "${FOO",
217 "FOO$$${FOO}",
218 "$$FOO${FOO}",
219 "${FOO:-${BAR}}",
220 "${QUUX:-${FOO}}",
221 "${FOO:+${BAR}}",
222 "${QUUX:+${BAR}}",
223 "${FOO:+|${BAR}|}}",
224 "${FOO:+|${BAR}{|}",
225 NULL
226 };
227 _cleanup_strv_free_ char **r = NULL;
228
229 r = replace_env_argv((char**) line, (char**) env);
230 assert_se(r);
231 assert_se(streq(r[0], "FOO$FOO"));
232 assert_se(streq(r[1], "FOO$FOOFOO"));
233 assert_se(streq(r[2], "FOOBAR BAR$FOO"));
234 assert_se(streq(r[3], "FOOBAR BAR"));
235 assert_se(streq(r[4], "BAR BAR"));
236 assert_se(streq(r[5], "BAR"));
237 assert_se(streq(r[6], "BAR"));
238 assert_se(streq(r[7], "BAR BARwaldo"));
239 assert_se(streq(r[8], "${FOO"));
240 assert_se(streq(r[9], "FOO$BAR BAR"));
241 assert_se(streq(r[10], "$FOOBAR BAR"));
242 assert_se(streq(r[11], "${FOO:-waldo}"));
243 assert_se(streq(r[12], "${QUUX:-BAR BAR}"));
244 assert_se(streq(r[13], "${FOO:+waldo}"));
245 assert_se(streq(r[14], "${QUUX:+waldo}"));
246 assert_se(streq(r[15], "${FOO:+|waldo|}}"));
247 assert_se(streq(r[16], "${FOO:+|waldo{|}"));
248 assert_se(strv_length(r) == 17);
249 }
250
251 static void test_env_clean(void) {
252 _cleanup_strv_free_ char **e;
253
254 e = strv_new("FOOBAR=WALDO",
255 "FOOBAR=WALDO",
256 "FOOBAR",
257 "F",
258 "X=",
259 "F=F",
260 "=",
261 "=F",
262 "",
263 "0000=000",
264 "äöüß=abcd",
265 "abcd=äöüß",
266 "xyz\n=xyz",
267 "xyz=xyz\n",
268 "another=one",
269 "another=final one",
270 NULL);
271 assert_se(e);
272 assert_se(!strv_env_is_valid(e));
273 assert_se(strv_env_clean(e) == e);
274 assert_se(strv_env_is_valid(e));
275
276 assert_se(streq(e[0], "FOOBAR=WALDO"));
277 assert_se(streq(e[1], "X="));
278 assert_se(streq(e[2], "F=F"));
279 assert_se(streq(e[3], "abcd=äöüß"));
280 assert_se(streq(e[4], "another=final one"));
281 assert_se(e[5] == NULL);
282 }
283
284 static void test_env_name_is_valid(void) {
285 assert_se(env_name_is_valid("test"));
286
287 assert_se(!env_name_is_valid(NULL));
288 assert_se(!env_name_is_valid(""));
289 assert_se(!env_name_is_valid("xxx\a"));
290 assert_se(!env_name_is_valid("xxx\007b"));
291 assert_se(!env_name_is_valid("\007\009"));
292 assert_se(!env_name_is_valid("5_starting_with_a_number_is_wrong"));
293 assert_se(!env_name_is_valid("#¤%&?_only_numbers_letters_and_underscore_allowed"));
294 }
295
296 static void test_env_value_is_valid(void) {
297 assert_se(env_value_is_valid(""));
298 assert_se(env_value_is_valid("głąb kapuściany"));
299 assert_se(env_value_is_valid("printf \"\\x1b]0;<mock-chroot>\\x07<mock-chroot>\""));
300 }
301
302 static void test_env_assignment_is_valid(void) {
303 assert_se(env_assignment_is_valid("a="));
304 assert_se(env_assignment_is_valid("b=głąb kapuściany"));
305 assert_se(env_assignment_is_valid("c=\\007\\009\\011"));
306 assert_se(env_assignment_is_valid("e=printf \"\\x1b]0;<mock-chroot>\\x07<mock-chroot>\""));
307
308 assert_se(!env_assignment_is_valid("="));
309 assert_se(!env_assignment_is_valid("a b="));
310 assert_se(!env_assignment_is_valid("a ="));
311 assert_se(!env_assignment_is_valid(" b="));
312 /* no dots or dashes: http://tldp.org/LDP/abs/html/gotchas.html */
313 assert_se(!env_assignment_is_valid("a.b="));
314 assert_se(!env_assignment_is_valid("a-b="));
315 assert_se(!env_assignment_is_valid("\007=głąb kapuściany"));
316 assert_se(!env_assignment_is_valid("c\009=\007\009\011"));
317 assert_se(!env_assignment_is_valid("głąb=printf \"\x1b]0;<mock-chroot>\x07<mock-chroot>\""));
318 }
319
320 static void test_deserialize_environment(void) {
321 _cleanup_strv_free_ char **env = strv_new("A=1", NULL);
322
323 assert_se(deserialize_environment(&env, "env=B=2") >= 0);
324 assert_se(deserialize_environment(&env, "env=FOO%%=a\\177b\\nc\\td e") >= 0);
325
326 assert_se(strv_equal(env, STRV_MAKE("A=1", "B=2", "FOO%%=a\177b\nc\td e")));
327
328 assert_se(deserialize_environment(&env, "env=foo\\") < 0);
329 assert_se(deserialize_environment(&env, "env=bar\\_baz") < 0);
330 }
331
332 static void test_serialize_environment(void) {
333 char fn[] = "/tmp/test-env-util.XXXXXXX";
334 int fd, r;
335 _cleanup_fclose_ FILE *f = NULL;
336
337 _cleanup_strv_free_ char **env = strv_new("A=1",
338 "B=2",
339 "C=ąęółń",
340 "D=D=a\\x0Ab",
341 "FOO%%=a\177b\nc\td e",
342 NULL);
343 _cleanup_strv_free_ char **env2 = NULL;
344
345 fd = mkostemp_safe(fn);
346 assert_se(fd >= 0);
347
348 assert_se(f = fdopen(fd, "r+"));
349
350 assert_se(serialize_environment(f, env) == 0);
351 assert_se(fflush_and_check(f) == 0);
352
353 rewind(f);
354
355 for (;;) {
356 char line[LINE_MAX];
357 const char *l;
358
359 if (!fgets(line, sizeof line, f))
360 break;
361
362 char_array_0(line);
363 l = strstrip(line);
364
365 r = deserialize_environment(&env2, l);
366 assert_se(r == 1);
367 }
368 assert_se(feof(f));
369
370 assert_se(strv_equal(env, env2));
371
372 unlink(fn);
373 }
374
375 int main(int argc, char *argv[]) {
376 test_strv_env_delete();
377 test_strv_env_get();
378 test_strv_env_unset();
379 test_strv_env_set();
380 test_strv_env_merge();
381 test_env_strv_get_n();
382 test_replace_env(false);
383 test_replace_env(true);
384 test_replace_env2(false);
385 test_replace_env2(true);
386 test_replace_env_argv();
387 test_env_clean();
388 test_env_name_is_valid();
389 test_env_value_is_valid();
390 test_env_assignment_is_valid();
391 test_deserialize_environment();
392 test_serialize_environment();
393
394 return 0;
395 }