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