1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2010 Lennart Poettering
6 Copyright 2016 Zbigniew Jędrzejewski-Szmek
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.
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.
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/>.
27 #include "string-util.h"
31 static void test_strv_env_delete(void) {
32 _cleanup_strv_free_
char **a
= NULL
, **b
= NULL
, **c
= NULL
, **d
= NULL
;
34 a
= strv_new("FOO=BAR", "WALDO=WALDO", "WALDO=", "PIEP", "SCHLUMPF=SMURF", NULL
);
37 b
= strv_new("PIEP", "FOO", NULL
);
40 c
= strv_new("SCHLUMPF", NULL
);
43 d
= strv_env_delete(a
, 2, b
, c
);
46 assert_se(streq(d
[0], "WALDO=WALDO"));
47 assert_se(streq(d
[1], "WALDO="));
48 assert_se(strv_length(d
) == 2);
51 static void test_strv_env_get(void) {
54 l
= STRV_MAKE("ONE_OR_TWO=1", "THREE=3", "ONE_OR_TWO=2", "FOUR=4");
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"));
61 static void test_strv_env_unset(void) {
62 _cleanup_strv_free_
char **l
= NULL
;
64 l
= strv_new("PIEP", "SCHLUMPF=SMURFF", "NANANANA=YES", NULL
);
67 assert_se(strv_env_unset(l
, "SCHLUMPF") == l
);
69 assert_se(streq(l
[0], "PIEP"));
70 assert_se(streq(l
[1], "NANANANA=YES"));
71 assert_se(strv_length(l
) == 2);
74 static void test_strv_env_set(void) {
75 _cleanup_strv_free_
char **l
= NULL
, **r
= NULL
;
77 l
= strv_new("PIEP", "SCHLUMPF=SMURFF", "NANANANA=YES", NULL
);
80 r
= strv_env_set(l
, "WALDO=WALDO");
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);
90 static void test_strv_env_merge(void) {
91 _cleanup_strv_free_
char **a
= NULL
, **b
= NULL
, **r
= NULL
;
93 a
= strv_new("FOO=BAR", "WALDO=WALDO", "WALDO=", "PIEP", "SCHLUMPF=SMURF", NULL
);
96 b
= strv_new("FOO=KKK", "FOO=", "PIEP=", "SCHLUMPF=SMURFF", "NANANANA=YES", NULL
);
99 r
= strv_env_merge(2, a
, b
);
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);
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);
118 static void test_env_strv_get_n(void) {
119 const char *_env
[] = {
126 char **env
= (char**) _env
;
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"));
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"));
138 env
[3] = NULL
; /* kill our $PATH */
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
),
144 assert_se(streq(strv_env_get_n(env
, "PATH", 4, REPLACE_ENV_USE_ENVIRONMENT
),
148 static void test_replace_env(bool braceless
) {
149 const char *env
[] = {
154 _cleanup_free_
char *t
= NULL
, *s
= NULL
, *q
= NULL
, *r
= NULL
, *p
= NULL
;
155 unsigned flags
= REPLACE_ENV_ALLOW_BRACELESS
*braceless
;
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"));
160 s
= replace_env("BAR=$BAR=${BAR}", (char**) env
, flags
);
161 assert_se(streq(s
, braceless
? "BAR=waldo=waldo" : "BAR=$BAR=waldo"));
163 q
= replace_env("BARBAR=$BARBAR=${BARBAR}", (char**) env
, flags
);
164 assert_se(streq(q
, braceless
? "BARBAR==" : "BARBAR=$BARBAR="));
166 r
= replace_env("BAR=$BAR$BAR${BAR}${BAR}", (char**) env
, flags
);
167 assert_se(streq(r
, braceless
? "BAR=waldowaldowaldowaldo" : "BAR=$BAR$BARwaldowaldo"));
169 p
= replace_env("${BAR}$BAR$BAR", (char**) env
, flags
);
170 assert_se(streq(p
, braceless
? "waldowaldowaldo" : "waldo$BAR$BAR"));
173 static void test_replace_env2(bool extended
) {
174 const char *env
[] = {
179 _cleanup_free_
char *t
= NULL
, *s
= NULL
, *q
= NULL
, *r
= NULL
, *p
= NULL
, *x
= NULL
;
180 unsigned flags
= REPLACE_ENV_ALLOW_EXTENDED
*extended
;
182 t
= replace_env("FOO=${FOO:-${BAR}}", (char**) env
, flags
);
183 assert_se(streq(t
, extended
? "FOO=foo" : "FOO=${FOO:-bar}"));
185 s
= replace_env("BAR=${XXX:-${BAR}}", (char**) env
, flags
);
186 assert_se(streq(s
, extended
? "BAR=bar" : "BAR=${XXX:-bar}"));
188 q
= replace_env("XXX=${XXX:+${BAR}}", (char**) env
, flags
);
189 assert_se(streq(q
, extended
? "XXX=" : "XXX=${XXX:+bar}"));
191 r
= replace_env("FOO=${FOO:+${BAR}}", (char**) env
, flags
);
192 assert_se(streq(r
, extended
? "FOO=bar" : "FOO=${FOO:+bar}"));
194 p
= replace_env("FOO=${FOO:-${BAR}post}", (char**) env
, flags
);
195 assert_se(streq(p
, extended
? "FOO=foo" : "FOO=${FOO:-barpost}"));
197 x
= replace_env("XXX=${XXX:+${BAR}post}", (char**) env
, flags
);
198 assert_se(streq(x
, extended
? "XXX=" : "XXX=${XXX:+barpost}"));
201 static void test_replace_env_argv(void) {
202 const char *env
[] = {
207 const char *line
[] = {
227 _cleanup_strv_free_
char **r
= NULL
;
229 r
= replace_env_argv((char**) line
, (char**) env
);
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);
251 static void test_env_clean(void) {
252 _cleanup_strv_free_
char **e
;
254 e
= strv_new("FOOBAR=WALDO",
272 assert_se(!strv_env_is_valid(e
));
273 assert_se(strv_env_clean(e
) == e
);
274 assert_se(strv_env_is_valid(e
));
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
);
284 static void test_env_name_is_valid(void) {
285 assert_se(env_name_is_valid("test"));
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"));
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>\""));
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>\""));
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>\""));
320 static void test_deserialize_environment(void) {
321 _cleanup_strv_free_
char **env
= strv_new("A=1", NULL
);
323 assert_se(deserialize_environment(&env
, "env=B=2") >= 0);
324 assert_se(deserialize_environment(&env
, "env=FOO%%=a\\177b\\nc\\td e") >= 0);
326 assert_se(strv_equal(env
, STRV_MAKE("A=1", "B=2", "FOO%%=a\177b\nc\td e")));
328 assert_se(deserialize_environment(&env
, "env=foo\\") < 0);
329 assert_se(deserialize_environment(&env
, "env=bar\\_baz") < 0);
332 static void test_serialize_environment(void) {
333 char fn
[] = "/tmp/test-env-util.XXXXXXX";
335 _cleanup_fclose_
FILE *f
= NULL
;
337 _cleanup_strv_free_
char **env
= strv_new("A=1",
341 "FOO%%=a\177b\nc\td e",
343 _cleanup_strv_free_
char **env2
= NULL
;
345 fd
= mkostemp_safe(fn
);
348 assert_se(f
= fdopen(fd
, "r+"));
350 assert_se(serialize_environment(f
, env
) == 0);
351 assert_se(fflush_and_check(f
) == 0);
359 if (!fgets(line
, sizeof line
, f
))
365 r
= deserialize_environment(&env2
, l
);
370 assert_se(strv_equal(env
, env2
));
375 int main(int argc
, char *argv
[]) {
376 test_strv_env_delete();
378 test_strv_env_unset();
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();
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();