1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 
3 #include "escape.h"
4 #include "fd-util.h"
5 #include "fileio.h"
6 #include "fs-util.h"
7 #include "log.h"
8 #include "serialize.h"
9 #include "strv.h"
10 #include "tests.h"
11 #include "tmpfile-util.h"
12 
13 static char long_string[LONG_LINE_MAX+1];
14 
TEST(serialize_item)15 TEST(serialize_item) {
16         _cleanup_(unlink_tempfilep) char fn[] = "/tmp/test-serialize.XXXXXX";
17         _cleanup_fclose_ FILE *f = NULL;
18 
19         assert_se(fmkostemp_safe(fn, "r+", &f) == 0);
20         log_info("/* %s (%s) */", __func__, fn);
21 
22         assert_se(serialize_item(f, "a", NULL) == 0);
23         assert_se(serialize_item(f, "a", "bbb") == 1);
24         assert_se(serialize_item(f, "a", "bbb") == 1);
25         assert_se(serialize_item(f, "a", long_string) == -EINVAL);
26         assert_se(serialize_item(f, long_string, "a") == -EINVAL);
27         assert_se(serialize_item(f, long_string, long_string) == -EINVAL);
28 
29         rewind(f);
30 
31         _cleanup_free_ char *line1 = NULL, *line2 = NULL, *line3 = NULL;
32         assert_se(read_line(f, LONG_LINE_MAX, &line1) > 0);
33         assert_se(streq(line1, "a=bbb"));
34         assert_se(read_line(f, LONG_LINE_MAX, &line2) > 0);
35         assert_se(streq(line2, "a=bbb"));
36         assert_se(read_line(f, LONG_LINE_MAX, &line3) == 0);
37         assert_se(streq(line3, ""));
38 }
39 
TEST(serialize_item_escaped)40 TEST(serialize_item_escaped) {
41         _cleanup_(unlink_tempfilep) char fn[] = "/tmp/test-serialize.XXXXXX";
42         _cleanup_fclose_ FILE *f = NULL;
43 
44         assert_se(fmkostemp_safe(fn, "r+", &f) == 0);
45         log_info("/* %s (%s) */", __func__, fn);
46 
47         assert_se(serialize_item_escaped(f, "a", NULL) == 0);
48         assert_se(serialize_item_escaped(f, "a", "bbb") == 1);
49         assert_se(serialize_item_escaped(f, "a", "bbb") == 1);
50         assert_se(serialize_item_escaped(f, "a", long_string) == -EINVAL);
51         assert_se(serialize_item_escaped(f, long_string, "a") == -EINVAL);
52         assert_se(serialize_item_escaped(f, long_string, long_string) == -EINVAL);
53 
54         rewind(f);
55 
56         _cleanup_free_ char *line1 = NULL, *line2 = NULL, *line3 = NULL;
57         assert_se(read_line(f, LONG_LINE_MAX, &line1) > 0);
58         assert_se(streq(line1, "a=bbb"));
59         assert_se(read_line(f, LONG_LINE_MAX, &line2) > 0);
60         assert_se(streq(line2, "a=bbb"));
61         assert_se(read_line(f, LONG_LINE_MAX, &line3) == 0);
62         assert_se(streq(line3, ""));
63 }
64 
TEST(serialize_usec)65 TEST(serialize_usec) {
66         _cleanup_(unlink_tempfilep) char fn[] = "/tmp/test-serialize.XXXXXX";
67         _cleanup_fclose_ FILE *f = NULL;
68 
69         assert_se(fmkostemp_safe(fn, "r+", &f) == 0);
70         log_info("/* %s (%s) */", __func__, fn);
71 
72         assert_se(serialize_usec(f, "usec1", USEC_INFINITY) == 0);
73         assert_se(serialize_usec(f, "usec2", 0) == 1);
74         assert_se(serialize_usec(f, "usec3", USEC_INFINITY-1) == 1);
75 
76         rewind(f);
77 
78         _cleanup_free_ char *line1 = NULL, *line2 = NULL;
79         usec_t x;
80 
81         assert_se(read_line(f, LONG_LINE_MAX, &line1) > 0);
82         assert_se(streq(line1, "usec2=0"));
83         assert_se(deserialize_usec(line1 + 6, &x) == 0);
84         assert_se(x == 0);
85 
86         assert_se(read_line(f, LONG_LINE_MAX, &line2) > 0);
87         assert_se(startswith(line2, "usec3="));
88         assert_se(deserialize_usec(line2 + 6, &x) == 0);
89         assert_se(x == USEC_INFINITY-1);
90 }
91 
TEST(serialize_strv)92 TEST(serialize_strv) {
93         _cleanup_(unlink_tempfilep) char fn[] = "/tmp/test-serialize.XXXXXX";
94         _cleanup_fclose_ FILE *f = NULL;
95 
96         char **strv = STRV_MAKE("a", "b", "foo foo",
97                                 "nasty1 \"",
98                                 "\"nasty2 ",
99                                 "nasty3 '",
100                                 "\"nasty4 \"",
101                                 "nasty5\n",
102                                 "\nnasty5\nfoo=bar",
103                                 "\nnasty5\nfoo=bar");
104 
105         assert_se(fmkostemp_safe(fn, "r+", &f) == 0);
106         log_info("/* %s (%s) */", __func__, fn);
107 
108         assert_se(serialize_strv(f, "strv1", NULL) == 0);
109         assert_se(serialize_strv(f, "strv2", STRV_MAKE_EMPTY) == 0);
110         assert_se(serialize_strv(f, "strv3", strv) == 1);
111         assert_se(serialize_strv(f, "strv4", STRV_MAKE(long_string)) == -EINVAL);
112 
113         rewind(f);
114 
115         _cleanup_strv_free_ char **strv2 = NULL;
116         for (;;) {
117                 _cleanup_free_ char *line = NULL;
118                 int r;
119 
120                 r = read_line(f, LONG_LINE_MAX, &line);
121                 if (r == 0)
122                         break;
123                 assert_se(r > 0);
124 
125                 const char *t = startswith(line, "strv3=");
126                 assert_se(t);
127 
128                 char *un;
129                 assert_se(cunescape(t, 0, &un) >= 0);
130                 assert_se(strv_consume(&strv2, un) >= 0);
131         }
132 
133         assert_se(strv_equal(strv, strv2));
134 }
135 
TEST(deserialize_environment)136 TEST(deserialize_environment) {
137         _cleanup_strv_free_ char **env;
138 
139         assert_se(env = strv_new("A=1"));
140 
141         assert_se(deserialize_environment("B=2", &env) >= 0);
142         assert_se(deserialize_environment("FOO%%=a\\177b\\nc\\td e", &env) >= 0);
143 
144         assert_se(strv_equal(env, STRV_MAKE("A=1", "B=2", "FOO%%=a\177b\nc\td e")));
145 
146         assert_se(deserialize_environment("foo\\", &env) < 0);
147         assert_se(deserialize_environment("bar\\_baz", &env) < 0);
148 }
149 
TEST(serialize_environment)150 TEST(serialize_environment) {
151         _cleanup_strv_free_ char **env = NULL, **env2 = NULL;
152         _cleanup_(unlink_tempfilep) char fn[] = "/tmp/test-env-util.XXXXXXX";
153         _cleanup_fclose_ FILE *f = NULL;
154         int r;
155 
156         assert_se(fmkostemp_safe(fn, "r+", &f) == 0);
157         log_info("/* %s (%s) */", __func__, fn);
158 
159         assert_se(env = strv_new("A=1",
160                                  "B=2",
161                                  "C=ąęółń",
162                                  "D=D=a\\x0Ab",
163                                  "FOO%%=a\177b\nc\td e"));
164 
165         assert_se(serialize_strv(f, "env", env) == 1);
166         assert_se(fflush_and_check(f) == 0);
167 
168         rewind(f);
169 
170         for (;;) {
171                 _cleanup_free_ char *line = NULL;
172                 const char *l;
173 
174                 r = read_line(f, LONG_LINE_MAX, &line);
175                 assert_se(r >= 0);
176 
177                 if (r == 0)
178                         break;
179 
180                 l = strstrip(line);
181 
182                 assert_se(startswith(l, "env="));
183 
184                 r = deserialize_environment(l+4, &env2);
185                 assert_se(r >= 0);
186         }
187         assert_se(feof(f));
188 
189         assert_se(strv_equal(env, env2));
190 }
191 
intro(void)192 static int intro(void) {
193         memset(long_string, 'x', sizeof(long_string)-1);
194         char_array_0(long_string);
195         return EXIT_SUCCESS;
196 }
197 
198 DEFINE_TEST_MAIN_WITH_INTRO(LOG_INFO, intro);
199