Branch data Line data Source code
1 : : /* SPDX-License-Identifier: LGPL-2.1+ */
2 : :
3 : : #include <fcntl.h>
4 : : #include <stdio.h>
5 : : #include <unistd.h>
6 : :
7 : : #include "alloc-util.h"
8 : : #include "ctype.h"
9 : : #include "env-file.h"
10 : : #include "env-util.h"
11 : : #include "fd-util.h"
12 : : #include "fileio.h"
13 : : #include "fs-util.h"
14 : : #include "io-util.h"
15 : : #include "parse-util.h"
16 : : #include "process-util.h"
17 : : #include "string-util.h"
18 : : #include "strv.h"
19 : : #include "tests.h"
20 : : #include "tmpfile-util.h"
21 : : #include "util.h"
22 : :
23 : 4 : static void test_parse_env_file(void) {
24 : : _cleanup_(unlink_tempfilep) char
25 : 4 : t[] = "/tmp/test-fileio-in-XXXXXX",
26 : 4 : p[] = "/tmp/test-fileio-out-XXXXXX";
27 : : FILE *f;
28 : 4 : _cleanup_free_ char *one = NULL, *two = NULL, *three = NULL, *four = NULL, *five = NULL,
29 : 4 : *six = NULL, *seven = NULL, *eight = NULL, *nine = NULL, *ten = NULL,
30 : 4 : *eleven = NULL, *twelve = NULL, *thirteen = NULL;
31 : 4 : _cleanup_strv_free_ char **a = NULL, **b = NULL;
32 : : char **i;
33 : : unsigned k;
34 : : int r;
35 : :
36 [ - + ]: 4 : assert_se(fmkostemp_safe(t, "w", &f) == 0);
37 : 4 : fputs("one=BAR \n"
38 : : "# comment\n"
39 : : " # comment \n"
40 : : " ; comment \n"
41 : : " two = bar \n"
42 : : "invalid line\n"
43 : : "invalid line #comment\n"
44 : : "three = \"333\n"
45 : : "xxxx\"\n"
46 : : "four = \'44\\\"44\'\n"
47 : : "five = \"55\\\"55\" \"FIVE\" cinco \n"
48 : : "six = seis sechs\\\n"
49 : : " sis\n"
50 : : "seven=\"sevenval\" #nocomment\n"
51 : : "eight=eightval #nocomment\n"
52 : : "export nine=nineval\n"
53 : : "ten=ignored\n"
54 : : "ten=ignored\n"
55 : : "ten=\n"
56 : : "eleven=\\value\n"
57 : : "twelve=\"\\value\"\n"
58 : : "thirteen='\\value'", f);
59 : :
60 : 4 : fflush(f);
61 : 4 : fclose(f);
62 : :
63 : 4 : r = load_env_file(NULL, t, &a);
64 [ - + ]: 4 : assert_se(r >= 0);
65 : :
66 [ + - + + ]: 56 : STRV_FOREACH(i, a)
67 [ + - ]: 52 : log_info("Got: <%s>", *i);
68 : :
69 [ - + ]: 4 : assert_se(streq_ptr(a[0], "one=BAR"));
70 [ - + ]: 4 : assert_se(streq_ptr(a[1], "two=bar"));
71 [ - + ]: 4 : assert_se(streq_ptr(a[2], "three=333\nxxxx"));
72 [ - + ]: 4 : assert_se(streq_ptr(a[3], "four=44\\\"44"));
73 [ - + ]: 4 : assert_se(streq_ptr(a[4], "five=55\"55FIVEcinco"));
74 [ - + ]: 4 : assert_se(streq_ptr(a[5], "six=seis sechs sis"));
75 [ - + ]: 4 : assert_se(streq_ptr(a[6], "seven=sevenval#nocomment"));
76 [ - + ]: 4 : assert_se(streq_ptr(a[7], "eight=eightval #nocomment"));
77 [ - + ]: 4 : assert_se(streq_ptr(a[8], "export nine=nineval"));
78 [ - + ]: 4 : assert_se(streq_ptr(a[9], "ten="));
79 [ - + ]: 4 : assert_se(streq_ptr(a[10], "eleven=value"));
80 [ - + ]: 4 : assert_se(streq_ptr(a[11], "twelve=\\value"));
81 [ - + ]: 4 : assert_se(streq_ptr(a[12], "thirteen=\\value"));
82 [ - + ]: 4 : assert_se(a[13] == NULL);
83 : :
84 : 4 : strv_env_clean(a);
85 : :
86 : 4 : k = 0;
87 [ - + # # ]: 4 : STRV_FOREACH(i, b) {
88 [ # # ]: 0 : log_info("Got2: <%s>", *i);
89 [ # # ]: 0 : assert_se(streq(*i, a[k++]));
90 : : }
91 : :
92 : 4 : r = parse_env_file(
93 : : NULL, t,
94 : : "one", &one,
95 : : "two", &two,
96 : : "three", &three,
97 : : "four", &four,
98 : : "five", &five,
99 : : "six", &six,
100 : : "seven", &seven,
101 : : "eight", &eight,
102 : : "export nine", &nine,
103 : : "ten", &ten,
104 : : "eleven", &eleven,
105 : : "twelve", &twelve,
106 : : "thirteen", &thirteen);
107 : :
108 [ - + ]: 4 : assert_se(r >= 0);
109 : :
110 [ + - ]: 4 : log_info("one=[%s]", strna(one));
111 [ + - ]: 4 : log_info("two=[%s]", strna(two));
112 [ + - ]: 4 : log_info("three=[%s]", strna(three));
113 [ + - ]: 4 : log_info("four=[%s]", strna(four));
114 [ + - ]: 4 : log_info("five=[%s]", strna(five));
115 [ + - ]: 4 : log_info("six=[%s]", strna(six));
116 [ + - ]: 4 : log_info("seven=[%s]", strna(seven));
117 [ + - ]: 4 : log_info("eight=[%s]", strna(eight));
118 [ + - ]: 4 : log_info("export nine=[%s]", strna(nine));
119 [ + - ]: 4 : log_info("ten=[%s]", strna(nine));
120 [ + - ]: 4 : log_info("eleven=[%s]", strna(eleven));
121 [ + - ]: 4 : log_info("twelve=[%s]", strna(twelve));
122 [ + - ]: 4 : log_info("thirteen=[%s]", strna(thirteen));
123 : :
124 [ - + ]: 4 : assert_se(streq(one, "BAR"));
125 [ - + ]: 4 : assert_se(streq(two, "bar"));
126 [ - + ]: 4 : assert_se(streq(three, "333\nxxxx"));
127 [ - + ]: 4 : assert_se(streq(four, "44\\\"44"));
128 [ - + ]: 4 : assert_se(streq(five, "55\"55FIVEcinco"));
129 [ - + ]: 4 : assert_se(streq(six, "seis sechs sis"));
130 [ - + ]: 4 : assert_se(streq(seven, "sevenval#nocomment"));
131 [ - + ]: 4 : assert_se(streq(eight, "eightval #nocomment"));
132 [ - + ]: 4 : assert_se(streq(nine, "nineval"));
133 [ - + ]: 4 : assert_se(ten == NULL);
134 [ - + ]: 4 : assert_se(streq(eleven, "value"));
135 [ - + ]: 4 : assert_se(streq(twelve, "\\value"));
136 [ - + ]: 4 : assert_se(streq(thirteen, "\\value"));
137 : :
138 : : {
139 : : /* prepare a temporary file to write the environment to */
140 : 8 : _cleanup_close_ int fd = mkostemp_safe(p);
141 [ - + ]: 4 : assert_se(fd >= 0);
142 : : }
143 : :
144 : 4 : r = write_env_file(p, a);
145 [ - + ]: 4 : assert_se(r >= 0);
146 : :
147 : 4 : r = load_env_file(NULL, p, &b);
148 [ - + ]: 4 : assert_se(r >= 0);
149 : 4 : }
150 : :
151 : 4 : static void test_parse_multiline_env_file(void) {
152 : : _cleanup_(unlink_tempfilep) char
153 : 4 : t[] = "/tmp/test-fileio-in-XXXXXX",
154 : 4 : p[] = "/tmp/test-fileio-out-XXXXXX";
155 : : FILE *f;
156 : 4 : _cleanup_strv_free_ char **a = NULL, **b = NULL;
157 : : char **i;
158 : : int r;
159 : :
160 [ - + ]: 4 : assert_se(fmkostemp_safe(t, "w", &f) == 0);
161 : 4 : fputs("one=BAR\\\n"
162 : : " VAR\\\n"
163 : : "\tGAR\n"
164 : : "#comment\n"
165 : : "two=\"bar\\\n"
166 : : " var\\\n"
167 : : "\tgar\"\n"
168 : : "#comment\n"
169 : : "tri=\"bar \\\n"
170 : : " var \\\n"
171 : : "\tgar \"\n", f);
172 : :
173 : 4 : fflush(f);
174 : 4 : fclose(f);
175 : :
176 : 4 : r = load_env_file(NULL, t, &a);
177 [ - + ]: 4 : assert_se(r >= 0);
178 : :
179 [ + - + + ]: 16 : STRV_FOREACH(i, a)
180 [ + - ]: 12 : log_info("Got: <%s>", *i);
181 : :
182 [ - + ]: 4 : assert_se(streq_ptr(a[0], "one=BAR VAR\tGAR"));
183 [ - + ]: 4 : assert_se(streq_ptr(a[1], "two=bar var\tgar"));
184 [ - + ]: 4 : assert_se(streq_ptr(a[2], "tri=bar var \tgar "));
185 [ - + ]: 4 : assert_se(a[3] == NULL);
186 : :
187 : : {
188 : 8 : _cleanup_close_ int fd = mkostemp_safe(p);
189 [ - + ]: 4 : assert_se(fd >= 0);
190 : : }
191 : :
192 : 4 : r = write_env_file(p, a);
193 [ - + ]: 4 : assert_se(r >= 0);
194 : :
195 : 4 : r = load_env_file(NULL, p, &b);
196 [ - + ]: 4 : assert_se(r >= 0);
197 : 4 : }
198 : :
199 : 4 : static void test_merge_env_file(void) {
200 : 4 : _cleanup_(unlink_tempfilep) char t[] = "/tmp/test-fileio-XXXXXX";
201 : 4 : _cleanup_fclose_ FILE *f = NULL;
202 : 4 : _cleanup_strv_free_ char **a = NULL;
203 : : char **i;
204 : : int r;
205 : :
206 [ - + ]: 4 : assert_se(fmkostemp_safe(t, "w", &f) == 0);
207 [ + - ]: 4 : log_info("/* %s (%s) */", __func__, t);
208 : :
209 : 4 : r = write_string_stream(f,
210 : : "one=1 \n"
211 : : "twelve=${one}2\n"
212 : : "twentyone=2${one}\n"
213 : : "one=2\n"
214 : : "twentytwo=2${one}\n"
215 : : "xxx_minus_three=$xxx - 3\n"
216 : : "xxx=0x$one$one$one\n"
217 : : "yyy=${one:-fallback}\n"
218 : : "zzz=${one:+replacement}\n"
219 : : "zzzz=${foobar:-${nothing}}\n"
220 : : "zzzzz=${nothing:+${nothing}}\n"
221 : : , WRITE_STRING_FILE_AVOID_NEWLINE);
222 [ - + ]: 4 : assert(r >= 0);
223 : :
224 : 4 : r = merge_env_file(&a, NULL, t);
225 [ - + ]: 4 : assert_se(r >= 0);
226 : 4 : strv_sort(a);
227 : :
228 [ + - + + ]: 44 : STRV_FOREACH(i, a)
229 [ + - ]: 40 : log_info("Got: <%s>", *i);
230 : :
231 [ - + ]: 4 : assert_se(streq(a[0], "one=2"));
232 [ - + ]: 4 : assert_se(streq(a[1], "twelve=12"));
233 [ - + ]: 4 : assert_se(streq(a[2], "twentyone=21"));
234 [ - + ]: 4 : assert_se(streq(a[3], "twentytwo=22"));
235 [ - + ]: 4 : assert_se(streq(a[4], "xxx=0x222"));
236 [ - + ]: 4 : assert_se(streq(a[5], "xxx_minus_three= - 3"));
237 [ - + ]: 4 : assert_se(streq(a[6], "yyy=2"));
238 [ - + ]: 4 : assert_se(streq(a[7], "zzz=replacement"));
239 [ - + ]: 4 : assert_se(streq(a[8], "zzzz="));
240 [ - + ]: 4 : assert_se(streq(a[9], "zzzzz="));
241 [ - + ]: 4 : assert_se(a[10] == NULL);
242 : :
243 : 4 : r = merge_env_file(&a, NULL, t);
244 [ - + ]: 4 : assert_se(r >= 0);
245 : 4 : strv_sort(a);
246 : :
247 [ + - + + ]: 44 : STRV_FOREACH(i, a)
248 [ + - ]: 40 : log_info("Got2: <%s>", *i);
249 : :
250 [ - + ]: 4 : assert_se(streq(a[0], "one=2"));
251 [ - + ]: 4 : assert_se(streq(a[1], "twelve=12"));
252 [ - + ]: 4 : assert_se(streq(a[2], "twentyone=21"));
253 [ - + ]: 4 : assert_se(streq(a[3], "twentytwo=22"));
254 [ - + ]: 4 : assert_se(streq(a[4], "xxx=0x222"));
255 [ - + ]: 4 : assert_se(streq(a[5], "xxx_minus_three=0x222 - 3"));
256 [ - + ]: 4 : assert_se(streq(a[6], "yyy=2"));
257 [ - + ]: 4 : assert_se(streq(a[7], "zzz=replacement"));
258 [ - + ]: 4 : assert_se(streq(a[8], "zzzz="));
259 [ - + ]: 4 : assert_se(streq(a[9], "zzzzz="));
260 [ - + ]: 4 : assert_se(a[10] == NULL);
261 : 4 : }
262 : :
263 : 4 : static void test_merge_env_file_invalid(void) {
264 : 4 : _cleanup_(unlink_tempfilep) char t[] = "/tmp/test-fileio-XXXXXX";
265 : 4 : _cleanup_fclose_ FILE *f = NULL;
266 : 4 : _cleanup_strv_free_ char **a = NULL;
267 : : char **i;
268 : : int r;
269 : :
270 [ - + ]: 4 : assert_se(fmkostemp_safe(t, "w", &f) == 0);
271 [ + - ]: 4 : log_info("/* %s (%s) */", __func__, t);
272 : :
273 : 4 : r = write_string_stream(f,
274 : : "unset one \n"
275 : : "unset one= \n"
276 : : "unset one=1 \n"
277 : : "one \n"
278 : : "one = \n"
279 : : "one two =\n"
280 : : "\x20two=\n"
281 : : "#comment=comment\n"
282 : : ";comment2=comment2\n"
283 : : "#\n"
284 : : "\n\n" /* empty line */
285 : : , WRITE_STRING_FILE_AVOID_NEWLINE);
286 [ - + ]: 4 : assert(r >= 0);
287 : :
288 : 4 : r = merge_env_file(&a, NULL, t);
289 [ - + ]: 4 : assert_se(r >= 0);
290 : :
291 [ - + # # ]: 4 : STRV_FOREACH(i, a)
292 [ # # ]: 0 : log_info("Got: <%s>", *i);
293 : :
294 [ - + ]: 4 : assert_se(strv_isempty(a));
295 : 4 : }
296 : :
297 : 4 : static void test_executable_is_script(void) {
298 : 4 : _cleanup_(unlink_tempfilep) char t[] = "/tmp/test-fileio-XXXXXX";
299 : 4 : _cleanup_fclose_ FILE *f = NULL;
300 : : char *command;
301 : : int r;
302 : :
303 [ - + ]: 4 : assert_se(fmkostemp_safe(t, "w", &f) == 0);
304 : 4 : fputs("#! /bin/script -a -b \ngoo goo", f);
305 : 4 : fflush(f);
306 : :
307 : 4 : r = executable_is_script(t, &command);
308 [ - + ]: 4 : assert_se(r > 0);
309 [ - + ]: 4 : assert_se(streq(command, "/bin/script"));
310 : 4 : free(command);
311 : :
312 : 4 : r = executable_is_script("/bin/sh", &command);
313 [ - + ]: 4 : assert_se(r == 0);
314 : :
315 : 4 : r = executable_is_script("/usr/bin/yum", &command);
316 [ - + # # ]: 4 : assert_se(r > 0 || r == -ENOENT);
317 [ + - ]: 4 : if (r > 0) {
318 [ - + ]: 4 : assert_se(startswith(command, "/"));
319 : 4 : free(command);
320 : : }
321 : 4 : }
322 : :
323 : 4 : static void test_status_field(void) {
324 : 4 : _cleanup_free_ char *t = NULL, *p = NULL, *s = NULL, *z = NULL;
325 : 4 : unsigned long long total = 0, buffers = 0;
326 : : int r;
327 : :
328 [ - + ]: 4 : assert_se(get_proc_field("/proc/self/status", "Threads", WHITESPACE, &t) == 0);
329 : 4 : puts(t);
330 [ - + ]: 4 : assert_se(streq(t, "1"));
331 : :
332 : 4 : r = get_proc_field("/proc/meminfo", "MemTotal", WHITESPACE, &p);
333 [ + - ]: 4 : if (r != -ENOENT) {
334 [ - + ]: 4 : assert_se(r == 0);
335 : 4 : puts(p);
336 [ - + ]: 4 : assert_se(safe_atollu(p, &total) == 0);
337 : : }
338 : :
339 : 4 : r = get_proc_field("/proc/meminfo", "Buffers", WHITESPACE, &s);
340 [ + - ]: 4 : if (r != -ENOENT) {
341 [ - + ]: 4 : assert_se(r == 0);
342 : 4 : puts(s);
343 [ - + ]: 4 : assert_se(safe_atollu(s, &buffers) == 0);
344 : : }
345 : :
346 [ + - ]: 4 : if (p)
347 [ - + ]: 4 : assert_se(buffers < total);
348 : :
349 : : /* Seccomp should be a good test for field full of zeros. */
350 : 4 : r = get_proc_field("/proc/meminfo", "Seccomp", WHITESPACE, &z);
351 [ - + ]: 4 : if (r != -ENOENT) {
352 [ # # ]: 0 : assert_se(r == 0);
353 : 0 : puts(z);
354 [ # # ]: 0 : assert_se(safe_atollu(z, &buffers) == 0);
355 : : }
356 : 4 : }
357 : :
358 : 4 : static void test_capeff(void) {
359 : : int pid, p;
360 : :
361 [ + + ]: 12 : for (pid = 0; pid < 2; pid++) {
362 [ + - ]: 8 : _cleanup_free_ char *capeff = NULL;
363 : : int r;
364 : :
365 : 8 : r = get_process_capeff(0, &capeff);
366 [ + - ]: 8 : log_info("capeff: '%s' (r=%d)", capeff, r);
367 : :
368 [ - + - + ]: 8 : if (IN_SET(r, -ENOENT, -EPERM))
369 : 0 : return;
370 : :
371 [ - + ]: 8 : assert_se(r == 0);
372 [ - + ]: 8 : assert_se(*capeff);
373 : 8 : p = capeff[strspn(capeff, HEXDIGITS)];
374 [ - + # # ]: 8 : assert_se(!p || isspace(p));
375 : : }
376 : : }
377 : :
378 : 4 : static void test_write_string_stream(void) {
379 : 4 : _cleanup_(unlink_tempfilep) char fn[] = "/tmp/test-write_string_stream-XXXXXX";
380 : 4 : _cleanup_fclose_ FILE *f = NULL;
381 : : int fd;
382 : : char buf[64];
383 : :
384 : 4 : fd = mkostemp_safe(fn);
385 [ - + ]: 4 : assert_se(fd >= 0);
386 : :
387 : 4 : f = fdopen(fd, "r");
388 [ - + ]: 4 : assert_se(f);
389 [ - + ]: 4 : assert_se(write_string_stream(f, "boohoo", 0) < 0);
390 : 4 : f = safe_fclose(f);
391 : :
392 : 4 : f = fopen(fn, "r+");
393 [ - + ]: 4 : assert_se(f);
394 : :
395 [ - + ]: 4 : assert_se(write_string_stream(f, "boohoo", 0) == 0);
396 : 4 : rewind(f);
397 : :
398 [ - + ]: 4 : assert_se(fgets(buf, sizeof(buf), f));
399 [ - + ]: 4 : assert_se(streq(buf, "boohoo\n"));
400 : 4 : f = safe_fclose(f);
401 : :
402 : 4 : f = fopen(fn, "w+");
403 [ - + ]: 4 : assert_se(f);
404 : :
405 [ - + ]: 4 : assert_se(write_string_stream(f, "boohoo", WRITE_STRING_FILE_AVOID_NEWLINE) == 0);
406 : 4 : rewind(f);
407 : :
408 [ - + ]: 4 : assert_se(fgets(buf, sizeof(buf), f));
409 : 4 : printf(">%s<", buf);
410 [ - + ]: 4 : assert_se(streq(buf, "boohoo"));
411 : 4 : }
412 : :
413 : 4 : static void test_write_string_file(void) {
414 : 4 : _cleanup_(unlink_tempfilep) char fn[] = "/tmp/test-write_string_file-XXXXXX";
415 : 4 : char buf[64] = {};
416 : 4 : _cleanup_close_ int fd;
417 : :
418 : 4 : fd = mkostemp_safe(fn);
419 [ - + ]: 4 : assert_se(fd >= 0);
420 : :
421 [ - + ]: 4 : assert_se(write_string_file(fn, "boohoo", WRITE_STRING_FILE_CREATE) == 0);
422 : :
423 [ - + ]: 4 : assert_se(read(fd, buf, sizeof(buf)) == 7);
424 [ - + ]: 4 : assert_se(streq(buf, "boohoo\n"));
425 : 4 : }
426 : :
427 : 4 : static void test_write_string_file_no_create(void) {
428 : 4 : _cleanup_(unlink_tempfilep) char fn[] = "/tmp/test-write_string_file_no_create-XXXXXX";
429 : 4 : _cleanup_close_ int fd;
430 : 4 : char buf[64] = {};
431 : :
432 : 4 : fd = mkostemp_safe(fn);
433 [ - + ]: 4 : assert_se(fd >= 0);
434 : :
435 [ - + ]: 4 : assert_se(write_string_file("/a/file/which/does/not/exists/i/guess", "boohoo", 0) < 0);
436 [ - + ]: 4 : assert_se(write_string_file(fn, "boohoo", 0) == 0);
437 : :
438 [ - + ]: 4 : assert_se(read(fd, buf, sizeof buf) == (ssize_t) strlen("boohoo\n"));
439 [ - + ]: 4 : assert_se(streq(buf, "boohoo\n"));
440 : 4 : }
441 : :
442 : 4 : static void test_write_string_file_verify(void) {
443 : 4 : _cleanup_free_ char *buf = NULL, *buf2 = NULL;
444 : : int r;
445 : :
446 [ - + ]: 4 : assert_se(read_one_line_file("/proc/cmdline", &buf) >= 0);
447 [ - + ]: 4 : assert_se(buf2 = strjoin(buf, "\n"));
448 : :
449 : 4 : r = write_string_file("/proc/cmdline", buf, 0);
450 [ + - - + ]: 4 : assert_se(IN_SET(r, -EACCES, -EIO));
451 : 4 : r = write_string_file("/proc/cmdline", buf2, 0);
452 [ + - - + ]: 4 : assert_se(IN_SET(r, -EACCES, -EIO));
453 : :
454 [ - + ]: 4 : assert_se(write_string_file("/proc/cmdline", buf, WRITE_STRING_FILE_VERIFY_ON_FAILURE) == 0);
455 [ - + ]: 4 : assert_se(write_string_file("/proc/cmdline", buf2, WRITE_STRING_FILE_VERIFY_ON_FAILURE) == 0);
456 : :
457 : 4 : r = write_string_file("/proc/cmdline", buf, WRITE_STRING_FILE_VERIFY_ON_FAILURE|WRITE_STRING_FILE_AVOID_NEWLINE);
458 [ + - - + ]: 4 : assert_se(IN_SET(r, -EACCES, -EIO));
459 [ - + ]: 4 : assert_se(write_string_file("/proc/cmdline", buf2, WRITE_STRING_FILE_VERIFY_ON_FAILURE|WRITE_STRING_FILE_AVOID_NEWLINE) == 0);
460 : 4 : }
461 : :
462 : 4 : static void test_load_env_file_pairs(void) {
463 : 4 : _cleanup_(unlink_tempfilep) char fn[] = "/tmp/test-load_env_file_pairs-XXXXXX";
464 : : int fd, r;
465 : 4 : _cleanup_fclose_ FILE *f = NULL;
466 : 4 : _cleanup_strv_free_ char **l = NULL;
467 : : char **k, **v;
468 : :
469 : 4 : fd = mkostemp_safe(fn);
470 [ - + ]: 4 : assert_se(fd >= 0);
471 : :
472 : 4 : r = write_string_file(fn,
473 : : "NAME=\"Arch Linux\"\n"
474 : : "ID=arch\n"
475 : : "PRETTY_NAME=\"Arch Linux\"\n"
476 : : "ANSI_COLOR=\"0;36\"\n"
477 : : "HOME_URL=\"https://www.archlinux.org/\"\n"
478 : : "SUPPORT_URL=\"https://bbs.archlinux.org/\"\n"
479 : : "BUG_REPORT_URL=\"https://bugs.archlinux.org/\"\n",
480 : : WRITE_STRING_FILE_CREATE);
481 [ - + ]: 4 : assert_se(r == 0);
482 : :
483 : 4 : f = fdopen(fd, "r");
484 [ - + ]: 4 : assert_se(f);
485 : :
486 : 4 : r = load_env_file_pairs(f, fn, &l);
487 [ - + ]: 4 : assert_se(r >= 0);
488 : :
489 [ - + ]: 4 : assert_se(strv_length(l) == 14);
490 [ + - + + : 32 : STRV_FOREACH_PAIR(k, v, l) {
+ - ]
491 [ - + ]: 28 : assert_se(STR_IN_SET(*k, "NAME", "ID", "PRETTY_NAME", "ANSI_COLOR", "HOME_URL", "SUPPORT_URL", "BUG_REPORT_URL"));
492 : 28 : printf("%s=%s\n", *k, *v);
493 [ + + - + ]: 28 : if (streq(*k, "NAME")) assert_se(streq(*v, "Arch Linux"));
494 [ + + - + ]: 28 : if (streq(*k, "ID")) assert_se(streq(*v, "arch"));
495 [ + + - + ]: 28 : if (streq(*k, "PRETTY_NAME")) assert_se(streq(*v, "Arch Linux"));
496 [ + + - + ]: 28 : if (streq(*k, "ANSI_COLOR")) assert_se(streq(*v, "0;36"));
497 [ + + - + ]: 28 : if (streq(*k, "HOME_URL")) assert_se(streq(*v, "https://www.archlinux.org/"));
498 [ + + - + ]: 28 : if (streq(*k, "SUPPORT_URL")) assert_se(streq(*v, "https://bbs.archlinux.org/"));
499 [ + + - + ]: 28 : if (streq(*k, "BUG_REPORT_URL")) assert_se(streq(*v, "https://bugs.archlinux.org/"));
500 : : }
501 : 4 : }
502 : :
503 : 4 : static void test_search_and_fopen(void) {
504 : 4 : const char *dirs[] = {"/tmp/foo/bar", "/tmp", NULL};
505 : :
506 : 4 : char name[] = "/tmp/test-search_and_fopen.XXXXXX";
507 : : int fd, r;
508 : : FILE *f;
509 : :
510 : 4 : fd = mkostemp_safe(name);
511 [ - + ]: 4 : assert_se(fd >= 0);
512 : 4 : close(fd);
513 : :
514 : 4 : r = search_and_fopen(basename(name), "r", NULL, dirs, &f);
515 [ - + ]: 4 : assert_se(r >= 0);
516 : 4 : fclose(f);
517 : :
518 : 4 : r = search_and_fopen(name, "r", NULL, dirs, &f);
519 [ - + ]: 4 : assert_se(r >= 0);
520 : 4 : fclose(f);
521 : :
522 : 4 : r = search_and_fopen(basename(name), "r", "/", dirs, &f);
523 [ - + ]: 4 : assert_se(r >= 0);
524 : 4 : fclose(f);
525 : :
526 : 4 : r = search_and_fopen("/a/file/which/does/not/exist/i/guess", "r", NULL, dirs, &f);
527 [ - + ]: 4 : assert_se(r < 0);
528 : 4 : r = search_and_fopen("afilewhichdoesnotexistiguess", "r", NULL, dirs, &f);
529 [ - + ]: 4 : assert_se(r < 0);
530 : :
531 : 4 : r = unlink(name);
532 [ - + ]: 4 : assert_se(r == 0);
533 : :
534 : 4 : r = search_and_fopen(basename(name), "r", NULL, dirs, &f);
535 [ - + ]: 4 : assert_se(r < 0);
536 : 4 : }
537 : :
538 : 4 : static void test_search_and_fopen_nulstr(void) {
539 : 4 : const char dirs[] = "/tmp/foo/bar\0/tmp\0";
540 : :
541 : 4 : _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-search_and_fopen.XXXXXX";
542 : : int fd, r;
543 : : FILE *f;
544 : :
545 : 4 : fd = mkostemp_safe(name);
546 [ - + ]: 4 : assert_se(fd >= 0);
547 : 4 : close(fd);
548 : :
549 : 4 : r = search_and_fopen_nulstr(basename(name), "r", NULL, dirs, &f);
550 [ - + ]: 4 : assert_se(r >= 0);
551 : 4 : fclose(f);
552 : :
553 : 4 : r = search_and_fopen_nulstr(name, "r", NULL, dirs, &f);
554 [ - + ]: 4 : assert_se(r >= 0);
555 : 4 : fclose(f);
556 : :
557 : 4 : r = search_and_fopen_nulstr("/a/file/which/does/not/exist/i/guess", "r", NULL, dirs, &f);
558 [ - + ]: 4 : assert_se(r < 0);
559 : 4 : r = search_and_fopen_nulstr("afilewhichdoesnotexistiguess", "r", NULL, dirs, &f);
560 [ - + ]: 4 : assert_se(r < 0);
561 : :
562 : 4 : r = unlink(name);
563 [ - + ]: 4 : assert_se(r == 0);
564 : :
565 : 4 : r = search_and_fopen_nulstr(basename(name), "r", NULL, dirs, &f);
566 [ - + ]: 4 : assert_se(r < 0);
567 : 4 : }
568 : :
569 : 4 : static void test_writing_tmpfile(void) {
570 : 4 : _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-systemd_writing_tmpfile.XXXXXX";
571 : 4 : _cleanup_free_ char *contents = NULL;
572 : : size_t size;
573 : 4 : _cleanup_close_ int fd = -1;
574 : : struct iovec iov[3];
575 : : int r;
576 : :
577 : 4 : iov[0] = IOVEC_MAKE_STRING("abc\n");
578 : 4 : iov[1] = IOVEC_MAKE_STRING(ALPHANUMERICAL "\n");
579 : 4 : iov[2] = IOVEC_MAKE_STRING("");
580 : :
581 : 4 : fd = mkostemp_safe(name);
582 : 4 : printf("tmpfile: %s", name);
583 : :
584 : 4 : r = writev(fd, iov, 3);
585 [ - + ]: 4 : assert_se(r >= 0);
586 : :
587 : 4 : r = read_full_file(name, &contents, &size);
588 [ - + ]: 4 : assert_se(r == 0);
589 : 4 : printf("contents: %s", contents);
590 [ - + ]: 4 : assert_se(streq(contents, "abc\n" ALPHANUMERICAL "\n"));
591 : 4 : }
592 : :
593 : 4 : static void test_tempfn(void) {
594 : 4 : char *ret = NULL, *p;
595 : :
596 [ - + ]: 4 : assert_se(tempfn_xxxxxx("/foo/bar/waldo", NULL, &ret) >= 0);
597 [ - + ]: 4 : assert_se(streq_ptr(ret, "/foo/bar/.#waldoXXXXXX"));
598 : 4 : free(ret);
599 : :
600 [ - + ]: 4 : assert_se(tempfn_xxxxxx("/foo/bar/waldo", "[miau]", &ret) >= 0);
601 [ - + ]: 4 : assert_se(streq_ptr(ret, "/foo/bar/.#[miau]waldoXXXXXX"));
602 : 4 : free(ret);
603 : :
604 [ - + ]: 4 : assert_se(tempfn_random("/foo/bar/waldo", NULL, &ret) >= 0);
605 [ - + ]: 4 : assert_se(p = startswith(ret, "/foo/bar/.#waldo"));
606 [ - + ]: 4 : assert_se(strlen(p) == 16);
607 [ - + ]: 4 : assert_se(in_charset(p, "0123456789abcdef"));
608 : 4 : free(ret);
609 : :
610 [ - + ]: 4 : assert_se(tempfn_random("/foo/bar/waldo", "[wuff]", &ret) >= 0);
611 [ - + ]: 4 : assert_se(p = startswith(ret, "/foo/bar/.#[wuff]waldo"));
612 [ - + ]: 4 : assert_se(strlen(p) == 16);
613 [ - + ]: 4 : assert_se(in_charset(p, "0123456789abcdef"));
614 : 4 : free(ret);
615 : :
616 [ - + ]: 4 : assert_se(tempfn_random_child("/foo/bar/waldo", NULL, &ret) >= 0);
617 [ - + ]: 4 : assert_se(p = startswith(ret, "/foo/bar/waldo/.#"));
618 [ - + ]: 4 : assert_se(strlen(p) == 16);
619 [ - + ]: 4 : assert_se(in_charset(p, "0123456789abcdef"));
620 : 4 : free(ret);
621 : :
622 [ - + ]: 4 : assert_se(tempfn_random_child("/foo/bar/waldo", "[kikiriki]", &ret) >= 0);
623 [ - + ]: 4 : assert_se(p = startswith(ret, "/foo/bar/waldo/.#[kikiriki]"));
624 [ - + ]: 4 : assert_se(strlen(p) == 16);
625 [ - + ]: 4 : assert_se(in_charset(p, "0123456789abcdef"));
626 : 4 : free(ret);
627 : 4 : }
628 : :
629 : : static const char chars[] =
630 : : "Aąę„”\n루\377";
631 : :
632 : : #pragma GCC diagnostic push
633 : : #pragma GCC diagnostic ignored "-Wtype-limits"
634 : :
635 : 4 : static void test_fgetc(void) {
636 : 4 : _cleanup_fclose_ FILE *f = NULL;
637 : : char c;
638 : :
639 : 4 : f = fmemopen_unlocked((void*) chars, sizeof(chars), "re");
640 [ - + ]: 4 : assert_se(f);
641 : :
642 [ + + ]: 72 : for (unsigned i = 0; i < sizeof(chars); i++) {
643 [ - + ]: 68 : assert_se(safe_fgetc(f, &c) == 1);
644 [ - + ]: 68 : assert_se(c == chars[i]);
645 : :
646 : : /* EOF is -1, and hence we can't push value 255 in this way if char is signed */
647 [ + + - + ]: 68 : assert_se(ungetc(c, f) != EOF || c == EOF);
648 [ + + - + ]: 68 : assert_se(c == EOF || safe_fgetc(f, &c) == 1);
649 [ - + ]: 68 : assert_se(c == chars[i]);
650 : :
651 : : /* But it works when we push it properly cast */
652 [ - + ]: 68 : assert_se(ungetc((unsigned char) c, f) != EOF);
653 [ - + ]: 68 : assert_se(safe_fgetc(f, &c) == 1);
654 [ - + ]: 68 : assert_se(c == chars[i]);
655 : : }
656 : :
657 [ - + ]: 4 : assert_se(safe_fgetc(f, &c) == 0);
658 : 4 : }
659 : :
660 : : #pragma GCC diagnostic pop
661 : :
662 : : static const char buffer[] =
663 : : "Some test data\n"
664 : : "루Non-ascii chars: ąę„”\n"
665 : : "terminators\r\n"
666 : : "and even more\n\r"
667 : : "now the same with a NUL\n\0"
668 : : "and more\r\0"
669 : : "and even more\r\n\0"
670 : : "and yet even more\n\r\0"
671 : : "With newlines, and a NUL byte\0"
672 : : "\n"
673 : : "an empty line\n"
674 : : "an ignored line\n"
675 : : "and a very long line that is supposed to be truncated, because it is so long\n";
676 : :
677 : 8 : static void test_read_line_one_file(FILE *f) {
678 : 8 : _cleanup_free_ char *line = NULL;
679 : :
680 [ + - - + ]: 8 : assert_se(read_line(f, (size_t) -1, &line) == 15 && streq(line, "Some test data"));
681 : 8 : line = mfree(line);
682 : :
683 [ + - - + ]: 8 : assert_se(read_line(f, (size_t) -1, &line) > 0 && streq(line, "루Non-ascii chars: ąę„”"));
684 : 8 : line = mfree(line);
685 : :
686 [ + - - + ]: 8 : assert_se(read_line(f, (size_t) -1, &line) == 13 && streq(line, "terminators"));
687 : 8 : line = mfree(line);
688 : :
689 [ + - - + ]: 8 : assert_se(read_line(f, (size_t) -1, &line) == 15 && streq(line, "and even more"));
690 : 8 : line = mfree(line);
691 : :
692 [ + - - + ]: 8 : assert_se(read_line(f, (size_t) -1, &line) == 25 && streq(line, "now the same with a NUL"));
693 : 8 : line = mfree(line);
694 : :
695 [ + - - + ]: 8 : assert_se(read_line(f, (size_t) -1, &line) == 10 && streq(line, "and more"));
696 : 8 : line = mfree(line);
697 : :
698 [ + - - + ]: 8 : assert_se(read_line(f, (size_t) -1, &line) == 16 && streq(line, "and even more"));
699 : 8 : line = mfree(line);
700 : :
701 [ + - - + ]: 8 : assert_se(read_line(f, (size_t) -1, &line) == 20 && streq(line, "and yet even more"));
702 : 8 : line = mfree(line);
703 : :
704 [ + - - + ]: 8 : assert_se(read_line(f, 1024, &line) == 30 && streq(line, "With newlines, and a NUL byte"));
705 : 8 : line = mfree(line);
706 : :
707 [ + - - + ]: 8 : assert_se(read_line(f, 1024, &line) == 1 && streq(line, ""));
708 : 8 : line = mfree(line);
709 : :
710 [ + - - + ]: 8 : assert_se(read_line(f, 1024, &line) == 14 && streq(line, "an empty line"));
711 : 8 : line = mfree(line);
712 : :
713 [ - + ]: 8 : assert_se(read_line(f, (size_t) -1, NULL) == 16);
714 : :
715 [ - + ]: 8 : assert_se(read_line(f, 16, &line) == -ENOBUFS);
716 : 8 : line = mfree(line);
717 : :
718 : : /* read_line() stopped when it hit the limit, that means when we continue reading we'll read at the first
719 : : * character after the previous limit. Let's make use of that to continue our test. */
720 [ + - - + ]: 8 : assert_se(read_line(f, 1024, &line) == 62 && streq(line, "line that is supposed to be truncated, because it is so long"));
721 : 8 : line = mfree(line);
722 : :
723 [ + - - + ]: 8 : assert_se(read_line(f, 1024, &line) == 0 && streq(line, ""));
724 : 8 : }
725 : :
726 : 4 : static void test_read_line(void) {
727 : 4 : _cleanup_fclose_ FILE *f = NULL;
728 : :
729 : 4 : f = fmemopen_unlocked((void*) buffer, sizeof(buffer), "re");
730 [ - + ]: 4 : assert_se(f);
731 : :
732 : 4 : test_read_line_one_file(f);
733 : 4 : }
734 : :
735 : 4 : static void test_read_line2(void) {
736 : 4 : _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-fileio.XXXXXX";
737 : : int fd;
738 : 4 : _cleanup_fclose_ FILE *f = NULL;
739 : :
740 : 4 : fd = mkostemp_safe(name);
741 [ - + ]: 4 : assert_se(fd >= 0);
742 [ - + ]: 4 : assert_se((size_t) write(fd, buffer, sizeof(buffer)) == sizeof(buffer));
743 : :
744 [ - + ]: 4 : assert_se(lseek(fd, 0, SEEK_SET) == 0);
745 [ - + ]: 4 : assert_se(f = fdopen(fd, "r"));
746 : :
747 : 4 : test_read_line_one_file(f);
748 : 4 : }
749 : :
750 : 4 : static void test_read_line3(void) {
751 [ + - ]: 4 : _cleanup_fclose_ FILE *f = NULL;
752 [ + - ]: 4 : _cleanup_free_ char *line = NULL;
753 : : int r;
754 : :
755 : 4 : f = fopen("/proc/cmdline", "re");
756 [ - + # # : 4 : if (!f && IN_SET(errno, ENOENT, EPERM))
# # ]
757 : 0 : return;
758 [ - + ]: 4 : assert_se(f);
759 : :
760 : 4 : r = read_line(f, LINE_MAX, &line);
761 [ - + ]: 4 : assert_se(r >= 0);
762 [ - + ]: 4 : if (r == 0)
763 [ # # # # ]: 0 : assert_se(line && isempty(line));
764 : : else
765 [ - + ]: 4 : assert_se((size_t) r == strlen(line) + 1);
766 [ - + ]: 4 : assert_se(read_line(f, LINE_MAX, NULL) == 0);
767 : : }
768 : :
769 : 4 : static void test_read_line4(void) {
770 : : static const struct {
771 : : size_t length;
772 : : const char *string;
773 : : } eof_endings[] = {
774 : : /* Each of these will be followed by EOF and should generate the one same single string */
775 : : { 3, "foo" },
776 : : { 4, "foo\n" },
777 : : { 4, "foo\r" },
778 : : { 4, "foo\0" },
779 : : { 5, "foo\n\0" },
780 : : { 5, "foo\r\0" },
781 : : { 5, "foo\r\n" },
782 : : { 5, "foo\n\r" },
783 : : { 6, "foo\r\n\0" },
784 : : { 6, "foo\n\r\0" },
785 : : };
786 : :
787 : : size_t i;
788 : : int r;
789 : :
790 [ + + ]: 44 : for (i = 0; i < ELEMENTSOF(eof_endings); i++) {
791 : 40 : _cleanup_fclose_ FILE *f = NULL;
792 : 40 : _cleanup_free_ char *s = NULL;
793 : :
794 [ - + ]: 40 : assert_se(f = fmemopen_unlocked((void*) eof_endings[i].string, eof_endings[i].length, "r"));
795 : :
796 : 40 : r = read_line(f, (size_t) -1, &s);
797 [ - + ]: 40 : assert_se((size_t) r == eof_endings[i].length);
798 [ - + ]: 40 : assert_se(streq_ptr(s, "foo"));
799 : :
800 [ - + ]: 40 : assert_se(read_line(f, (size_t) -1, NULL) == 0); /* Ensure we hit EOF */
801 : : }
802 : 4 : }
803 : :
804 : 4 : static void test_read_nul_string(void) {
805 : : static const char test[] = "string nr. 1\0"
806 : : "string nr. 2\n\0"
807 : : "\377empty string follows\0"
808 : : "\0"
809 : : "final string\n is empty\0"
810 : : "\0";
811 : :
812 : 4 : _cleanup_fclose_ FILE *f = NULL;
813 : 4 : _cleanup_free_ char *s = NULL;
814 : :
815 [ - + ]: 4 : assert_se(f = fmemopen_unlocked((void*) test, sizeof(test)-1, "r"));
816 : :
817 [ + - - + ]: 4 : assert_se(read_nul_string(f, LONG_LINE_MAX, &s) == 13 && streq_ptr(s, "string nr. 1"));
818 : 4 : s = mfree(s);
819 : :
820 [ + - - + ]: 4 : assert_se(read_nul_string(f, LONG_LINE_MAX, &s) == 14 && streq_ptr(s, "string nr. 2\n"));
821 : 4 : s = mfree(s);
822 : :
823 [ + - - + ]: 4 : assert_se(read_nul_string(f, LONG_LINE_MAX, &s) == 22 && streq_ptr(s, "\377empty string follows"));
824 : 4 : s = mfree(s);
825 : :
826 [ + - - + ]: 4 : assert_se(read_nul_string(f, LONG_LINE_MAX, &s) == 1 && streq_ptr(s, ""));
827 : 4 : s = mfree(s);
828 : :
829 [ + - - + ]: 4 : assert_se(read_nul_string(f, LONG_LINE_MAX, &s) == 23 && streq_ptr(s, "final string\n is empty"));
830 : 4 : s = mfree(s);
831 : :
832 [ + - - + ]: 4 : assert_se(read_nul_string(f, LONG_LINE_MAX, &s) == 1 && streq_ptr(s, ""));
833 : 4 : s = mfree(s);
834 : :
835 [ + - - + ]: 4 : assert_se(read_nul_string(f, LONG_LINE_MAX, &s) == 0 && streq_ptr(s, ""));
836 : 4 : }
837 : :
838 : 4 : int main(int argc, char *argv[]) {
839 : 4 : test_setup_logging(LOG_DEBUG);
840 : :
841 : 4 : test_parse_env_file();
842 : 4 : test_parse_multiline_env_file();
843 : 4 : test_merge_env_file();
844 : 4 : test_merge_env_file_invalid();
845 : 4 : test_executable_is_script();
846 : 4 : test_status_field();
847 : 4 : test_capeff();
848 : 4 : test_write_string_stream();
849 : 4 : test_write_string_file();
850 : 4 : test_write_string_file_no_create();
851 : 4 : test_write_string_file_verify();
852 : 4 : test_load_env_file_pairs();
853 : 4 : test_search_and_fopen();
854 : 4 : test_search_and_fopen_nulstr();
855 : 4 : test_writing_tmpfile();
856 : 4 : test_tempfn();
857 : 4 : test_fgetc();
858 : 4 : test_read_line();
859 : 4 : test_read_line2();
860 : 4 : test_read_line3();
861 : 4 : test_read_line4();
862 : 4 : test_read_nul_string();
863 : :
864 : 4 : return 0;
865 : : }
|