]> git.ipfire.org Git - thirdparty/systemd.git/blame - 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
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
c24eb49e
LP
2/***
3 This file is part of systemd.
4
5 Copyright 2010 Lennart Poettering
b8c83cfc 6 Copyright 2016 Zbigniew Jędrzejewski-Szmek
c24eb49e
LP
7
8 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
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
c24eb49e
LP
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
5430f7f2 16 Lesser General Public License for more details.
c24eb49e 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
c24eb49e
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
c24eb49e
LP
22#include <string.h>
23
4d1a6904 24#include "env-util.h"
a096d8c8
ZJS
25#include "fd-util.h"
26#include "fileio.h"
07630cea
LP
27#include "string-util.h"
28#include "strv.h"
29#include "util.h"
c24eb49e 30
940bd473
TA
31static 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);
9b5d6bd9
LP
35 assert_se(a);
36
940bd473 37 b = strv_new("PIEP", "FOO", NULL);
9b5d6bd9
LP
38 assert_se(b);
39
940bd473 40 c = strv_new("SCHLUMPF", NULL);
9b5d6bd9 41 assert_se(c);
940bd473
TA
42
43 d = strv_env_delete(a, 2, b, c);
9b5d6bd9 44 assert_se(d);
940bd473 45
9b5d6bd9
LP
46 assert_se(streq(d[0], "WALDO=WALDO"));
47 assert_se(streq(d[1], "WALDO="));
48 assert_se(strv_length(d) == 2);
940bd473
TA
49}
50
6162512c
RS
51static 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
940bd473
TA
61static void test_strv_env_unset(void) {
62 _cleanup_strv_free_ char **l = NULL;
63
64 l = strv_new("PIEP", "SCHLUMPF=SMURFF", "NANANANA=YES", NULL);
9b5d6bd9 65 assert_se(l);
940bd473 66
9b5d6bd9 67 assert_se(strv_env_unset(l, "SCHLUMPF") == l);
940bd473 68
9b5d6bd9
LP
69 assert_se(streq(l[0], "PIEP"));
70 assert_se(streq(l[1], "NANANANA=YES"));
71 assert_se(strv_length(l) == 2);
940bd473
TA
72}
73
74static 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);
9b5d6bd9 78 assert_se(l);
940bd473
TA
79
80 r = strv_env_set(l, "WALDO=WALDO");
9b5d6bd9 81 assert_se(r);
940bd473 82
9b5d6bd9
LP
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);
940bd473
TA
88}
89
1f28b2de
TA
90static 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);
9b5d6bd9
LP
94 assert_se(a);
95
1f28b2de 96 b = strv_new("FOO=KKK", "FOO=", "PIEP=", "SCHLUMPF=SMURFF", "NANANANA=YES", NULL);
9b5d6bd9 97 assert_se(b);
c24eb49e 98
1f28b2de 99 r = strv_env_merge(2, a, b);
9b5d6bd9
LP
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);
1f28b2de
TA
116}
117
37f3ffca
RS
118static 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
ccad1fd0
ZJS
148static 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
a93236aa
ZJS
166 r = replace_env("BAR=$BAR$BAR${BAR}${BAR}", (char**) env, flags);
167 assert_se(streq(r, braceless ? "BAR=waldowaldowaldowaldo" : "BAR=$BAR$BARwaldowaldo"));
ccad1fd0
ZJS
168
169 p = replace_env("${BAR}$BAR$BAR", (char**) env, flags);
170 assert_se(streq(p, braceless ? "waldowaldowaldo" : "waldo$BAR$BAR"));
171}
172
f50ce8fc
ZJS
173static 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
ccad1fd0 201static void test_replace_env_argv(void) {
c24eb49e
LP
202 const char *env[] = {
203 "FOO=BAR BAR",
204 "BAR=waldo",
205 NULL
206 };
c24eb49e
LP
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",
df553b58
MS
217 "FOO$$${FOO}",
218 "$$FOO${FOO}",
b82f58bf
RS
219 "${FOO:-${BAR}}",
220 "${QUUX:-${FOO}}",
221 "${FOO:+${BAR}}",
222 "${QUUX:+${BAR}}",
223 "${FOO:+|${BAR}|}}",
224 "${FOO:+|${BAR}{|}",
c24eb49e
LP
225 NULL
226 };
1f28b2de 227 _cleanup_strv_free_ char **r = NULL;
c24eb49e
LP
228
229 r = replace_env_argv((char**) line, (char**) env);
9b5d6bd9
LP
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"));
df553b58
MS
240 assert_se(streq(r[9], "FOO$BAR BAR"));
241 assert_se(streq(r[10], "$FOOBAR BAR"));
b82f58bf
RS
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);
1f28b2de 249}
a6ff950e 250
4d1a6904 251static void test_env_clean(void) {
4d1a6904
LP
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);
9b5d6bd9
LP
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));
4d1a6904
LP
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
8354c34e
TA
284static 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(""));
b8c83cfc
ZJS
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"));
8354c34e
TA
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
b8c83cfc
ZJS
296static 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
302static 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
16eefcaf
RC
320static void test_deserialize_environment(void) {
321 _cleanup_strv_free_ char **env = strv_new("A=1", NULL);
322
16eefcaf 323 assert_se(deserialize_environment(&env, "env=B=2") >= 0);
ea43bdd1 324 assert_se(deserialize_environment(&env, "env=FOO%%=a\\177b\\nc\\td e") >= 0);
16eefcaf 325
ea43bdd1 326 assert_se(strv_equal(env, STRV_MAKE("A=1", "B=2", "FOO%%=a\177b\nc\td e")));
c7d797bb
LR
327
328 assert_se(deserialize_environment(&env, "env=foo\\") < 0);
329 assert_se(deserialize_environment(&env, "env=bar\\_baz") < 0);
16eefcaf
RC
330}
331
a096d8c8
ZJS
332static 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",
ea43bdd1 341 "FOO%%=a\177b\nc\td e",
a096d8c8
ZJS
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
1f28b2de 375int main(int argc, char *argv[]) {
940bd473 376 test_strv_env_delete();
6162512c 377 test_strv_env_get();
940bd473
TA
378 test_strv_env_unset();
379 test_strv_env_set();
1f28b2de 380 test_strv_env_merge();
37f3ffca 381 test_env_strv_get_n();
ccad1fd0
ZJS
382 test_replace_env(false);
383 test_replace_env(true);
f50ce8fc
ZJS
384 test_replace_env2(false);
385 test_replace_env2(true);
ccad1fd0 386 test_replace_env_argv();
4d1a6904 387 test_env_clean();
8354c34e 388 test_env_name_is_valid();
b8c83cfc
ZJS
389 test_env_value_is_valid();
390 test_env_assignment_is_valid();
16eefcaf 391 test_deserialize_environment();
a096d8c8 392 test_serialize_environment();
a6ff950e 393
5f7c426e 394 return 0;
c24eb49e 395}