1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 
3 #include "env-file.h"
4 #include "fd-util.h"
5 #include "fileio.h"
6 #include "fs-util.h"
7 #include "macro.h"
8 #include "strv.h"
9 #include "tests.h"
10 #include "tmpfile-util.h"
11 
12 /* In case of repeating keys, later entries win. */
13 
14 #define env_file_1                              \
15         "a=a\n"                                 \
16         "a=b\n"                                 \
17         "a=b\n"                                 \
18         "a=a\n"                                 \
19         "b=b\\\n"                               \
20         "c\n"                                   \
21         "d= d\\\n"                              \
22         "e  \\\n"                               \
23         "f  \n"                                 \
24         "g=g\\ \n"                              \
25         "h= ąęół\\ śćńźżµ \n"                   \
26         "i=i\\"
27 
28 #define env_file_2                              \
29         "a=a\\\n"
30 
31 #define env_file_3 \
32         "#SPAMD_ARGS=\"-d --socketpath=/var/lib/bulwark/spamd \\\n" \
33         "#--nouser-config                                     \\\n" \
34         "normal=line                                          \\\n" \
35         ";normal=ignored                                      \\\n" \
36         "normal_ignored                                       \\\n" \
37         "normal ignored                                       \\\n"
38 
39 #define env_file_4                              \
40         "# Generated\n"                         \
41         "\n"                                    \
42         "HWMON_MODULES=\"coretemp f71882fg\"\n" \
43         "\n"                                    \
44         "# For compatibility reasons\n"         \
45         "\n"                                    \
46         "MODULE_0=coretemp\n"                   \
47         "MODULE_1=f71882fg"
48 
49 #define env_file_5                              \
50         "a=\n"                                  \
51         "b="
52 
53 #define env_file_6                              \
54         "a=\\ \\n \\t \\x \\y \\' \n"           \
55         "b= \\$'                  \n"           \
56         "c= ' \\n\\t\\$\\`\\\\\n"               \
57         "'   \n"                                \
58         "d= \" \\n\\t\\$\\`\\\\\n"              \
59         "\"   \n"
60 
61 
TEST(load_env_file_1)62 TEST(load_env_file_1) {
63         _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-load-env-file.XXXXXX";
64         assert_se(write_tmpfile(name, env_file_1) == 0);
65 
66         _cleanup_strv_free_ char **data = NULL;
67         assert_se(load_env_file(NULL, name, &data) == 0);
68         assert_se(streq(data[0], "a=a"));
69         assert_se(streq(data[1], "b=bc"));
70         assert_se(streq(data[2], "d=de  f"));
71         assert_se(streq(data[3], "g=g "));
72         assert_se(streq(data[4], "h=ąęół śćńźżµ"));
73         assert_se(streq(data[5], "i=i"));
74         assert_se(data[6] == NULL);
75 }
76 
TEST(load_env_file_2)77 TEST(load_env_file_2) {
78         _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-load-env-file.XXXXXX";
79         assert_se(write_tmpfile(name, env_file_2) == 0);
80 
81         _cleanup_strv_free_ char **data = NULL;
82         assert_se(load_env_file(NULL, name, &data) == 0);
83         assert_se(streq(data[0], "a=a"));
84         assert_se(data[1] == NULL);
85 }
86 
TEST(load_env_file_3)87 TEST(load_env_file_3) {
88         _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-load-env-file.XXXXXX";
89         assert_se(write_tmpfile(name, env_file_3) == 0);
90 
91         _cleanup_strv_free_ char **data = NULL;
92         assert_se(load_env_file(NULL, name, &data) == 0);
93         assert_se(data == NULL);
94 }
95 
TEST(load_env_file_4)96 TEST(load_env_file_4) {
97         _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-load-env-file.XXXXXX";
98         assert_se(write_tmpfile(name, env_file_4) == 0);
99 
100         _cleanup_strv_free_ char **data = NULL;
101         assert_se(load_env_file(NULL, name, &data) == 0);
102         assert_se(streq(data[0], "HWMON_MODULES=coretemp f71882fg"));
103         assert_se(streq(data[1], "MODULE_0=coretemp"));
104         assert_se(streq(data[2], "MODULE_1=f71882fg"));
105         assert_se(data[3] == NULL);
106 }
107 
TEST(load_env_file_5)108 TEST(load_env_file_5) {
109         _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-load-env-file.XXXXXX";
110         assert_se(write_tmpfile(name, env_file_5) == 0);
111 
112         _cleanup_strv_free_ char **data = NULL;
113         assert_se(load_env_file(NULL, name, &data) == 0);
114         assert_se(streq(data[0], "a="));
115         assert_se(streq(data[1], "b="));
116         assert_se(data[2] == NULL);
117 }
118 
TEST(load_env_file_6)119 TEST(load_env_file_6) {
120         _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-load-env-file.XXXXXX";
121         assert_se(write_tmpfile(name, env_file_6) == 0);
122 
123         _cleanup_strv_free_ char **data = NULL;
124         assert_se(load_env_file(NULL, name, &data) == 0);
125         assert_se(streq(data[0], "a= n t x y '"));
126         assert_se(streq(data[1], "b=$'"));
127         assert_se(streq(data[2], "c= \\n\\t\\$\\`\\\\\n"));
128         assert_se(streq(data[3], "d= \\n\\t$`\\\n"));
129         assert_se(data[4] == NULL);
130 }
131 
TEST(write_and_load_env_file)132 TEST(write_and_load_env_file) {
133         /* Make sure that our writer, parser and the shell agree on what our env var files mean */
134 
135         FOREACH_STRING(v,
136                        "obbardc-laptop",
137                        "obbardc\\-laptop",
138                        "obbardc-lap\\top",
139                        "obbardc-lap\\top",
140                        "obbardc-lap\\\\top",
141                        "double\"quote",
142                        "single\'quote",
143                        "dollar$dollar",
144                        "newline\nnewline") {
145                 _cleanup_(unlink_and_freep) char *p = NULL;
146                 _cleanup_strv_free_ char **l = NULL;
147                 _cleanup_free_ char *j = NULL, *w = NULL, *cmd = NULL, *from_shell = NULL;
148                 _cleanup_pclose_ FILE *f = NULL;
149                 size_t sz;
150 
151                 assert_se(tempfn_random_child(NULL, NULL, &p) >= 0);
152 
153                 assert_se(j = strjoin("TEST=", v));
154                 assert_se(write_env_file(p, STRV_MAKE(j)) >= 0);
155 
156                 assert_se(cmd = strjoin(". ", p, " && /bin/echo -n \"$TEST\""));
157                 assert_se(f = popen(cmd, "re"));
158                 assert_se(read_full_stream(f, &from_shell, &sz) >= 0);
159                 assert_se(sz == strlen(v));
160                 assert_se(streq(from_shell, v));
161 
162                 assert_se(load_env_file(NULL, p, &l) >= 0);
163                 assert_se(strv_equal(l, STRV_MAKE(j)));
164 
165                 assert_se(parse_env_file(NULL, p, "TEST", &w) >= 0);
166                 assert_se(streq_ptr(w, v));
167         }
168 }
169 
170 DEFINE_TEST_MAIN(LOG_INFO);
171