]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/test/test-fileio.c
tree-wide: use -EBADF for fd initialization
[thirdparty/systemd.git] / src / test / test-fileio.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
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 11#include "env-util.h"
bca895c4 12#include "errno-util.h"
3ffd4af2
LP
13#include "fd-util.h"
14#include "fileio.h"
627d2bac 15#include "fs-util.h"
897891f0 16#include "io-util.h"
6bedfcbb 17#include "parse-util.h"
2708160c 18#include "path-util.h"
3ffd4af2 19#include "process-util.h"
d3dcf4e3 20#include "random-util.h"
b93d3f6b
LP
21#include "rm-rf.h"
22#include "socket-util.h"
07630cea 23#include "string-util.h"
3ffd4af2 24#include "strv.h"
6d7c4033 25#include "tests.h"
e4de7287 26#include "tmpfile-util.h"
f73141d7 27
4f7452a8 28TEST(parse_env_file) {
627d2bac
ZJS
29 _cleanup_(unlink_tempfilep) char
30 t[] = "/tmp/test-fileio-in-XXXXXX",
095b30cb 31 p[] = "/tmp/test-fileio-out-XXXXXX";
f73141d7 32 FILE *f;
ebc05a09 33 _cleanup_free_ char *one = NULL, *two = NULL, *three = NULL, *four = NULL, *five = NULL,
e4a8db1f
LT
34 *six = NULL, *seven = NULL, *eight = NULL, *nine = NULL, *ten = NULL,
35 *eleven = NULL, *twelve = NULL, *thirteen = NULL;
768100ef 36 _cleanup_strv_free_ char **a = NULL, **b = NULL;
768100ef 37 unsigned k;
d8351049 38 int r;
f73141d7 39
d8351049 40 assert_se(fmkostemp_safe(t, "w", &f) == 0);
f73141d7
LP
41 fputs("one=BAR \n"
42 "# comment\n"
43 " # comment \n"
98f59e59 44 " ; comment \n"
f73141d7
LP
45 " two = bar \n"
46 "invalid line\n"
98f59e59 47 "invalid line #comment\n"
f73141d7
LP
48 "three = \"333\n"
49 "xxxx\"\n"
50 "four = \'44\\\"44\'\n"
e4a8db1f 51 "five = \"55\\\"55\" \"FIVE\" cinco \n"
f73141d7
LP
52 "six = seis sechs\\\n"
53 " sis\n"
98f59e59
HH
54 "seven=\"sevenval\" #nocomment\n"
55 "eight=eightval #nocomment\n"
ebc05a09 56 "export nine=nineval\n"
99003e01
ZJS
57 "ten=ignored\n"
58 "ten=ignored\n"
e4a8db1f
LT
59 "ten=\n"
60 "eleven=\\value\n"
61 "twelve=\"\\value\"\n"
62 "thirteen='\\value'", f);
f73141d7
LP
63
64 fflush(f);
65 fclose(f);
66
aa8fbc74 67 r = load_env_file(NULL, t, &a);
ebc05a09
HH
68 assert_se(r >= 0);
69
70 STRV_FOREACH(i, a)
71 log_info("Got: <%s>", *i);
72
5fba7bbf
TA
73 assert_se(streq_ptr(a[0], "one=BAR"));
74 assert_se(streq_ptr(a[1], "two=bar"));
75 assert_se(streq_ptr(a[2], "three=333\nxxxx"));
e4a8db1f
LT
76 assert_se(streq_ptr(a[3], "four=44\\\"44"));
77 assert_se(streq_ptr(a[4], "five=55\"55FIVEcinco"));
5fba7bbf
TA
78 assert_se(streq_ptr(a[5], "six=seis sechs sis"));
79 assert_se(streq_ptr(a[6], "seven=sevenval#nocomment"));
80 assert_se(streq_ptr(a[7], "eight=eightval #nocomment"));
81 assert_se(streq_ptr(a[8], "export nine=nineval"));
82 assert_se(streq_ptr(a[9], "ten="));
e4a8db1f
LT
83 assert_se(streq_ptr(a[10], "eleven=value"));
84 assert_se(streq_ptr(a[11], "twelve=\\value"));
85 assert_se(streq_ptr(a[12], "thirteen=\\value"));
86 assert_se(a[13] == NULL);
ebc05a09 87
039f0e70 88 strv_env_clean(a);
ebc05a09 89
ebc05a09
HH
90 k = 0;
91 STRV_FOREACH(i, b) {
92 log_info("Got2: <%s>", *i);
93 assert_se(streq(*i, a[k++]));
94 }
95
f73141d7 96 r = parse_env_file(
aa8fbc74 97 NULL, t,
f73141d7
LP
98 "one", &one,
99 "two", &two,
100 "three", &three,
101 "four", &four,
102 "five", &five,
103 "six", &six,
104 "seven", &seven,
db537209 105 "eight", &eight,
ebc05a09 106 "export nine", &nine,
e4a8db1f
LT
107 "ten", &ten,
108 "eleven", &eleven,
109 "twelve", &twelve,
110 "thirteen", &thirteen);
99aad9a2 111 assert_se(r == 0);
f73141d7
LP
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
df8b14b5
LP
154static void test_one_shell_var(const char *file, const char *variable, const char *value) {
155 _cleanup_free_ char *cmd = NULL, *from_shell = NULL;
649bde89 156 _cleanup_pclose_ FILE *f = NULL;
df8b14b5
LP
157 size_t sz;
158
159 assert_se(cmd = strjoin(". ", file, " && /bin/echo -n \"$", variable, "\""));
160 assert_se(f = popen(cmd, "re"));
161 assert_se(read_full_stream(f, &from_shell, &sz) >= 0);
162 assert_se(sz == strlen(value));
163 assert_se(streq(from_shell, value));
164}
165
4f7452a8 166TEST(parse_multiline_env_file) {
627d2bac
ZJS
167 _cleanup_(unlink_tempfilep) char
168 t[] = "/tmp/test-fileio-in-XXXXXX",
ac4c8d6d 169 p[] = "/tmp/test-fileio-out-XXXXXX";
ac4c8d6d
ZJS
170 FILE *f;
171 _cleanup_strv_free_ char **a = NULL, **b = NULL;
d8351049 172 int r;
ac4c8d6d 173
d8351049 174 assert_se(fmkostemp_safe(t, "w", &f) == 0);
ac4c8d6d 175 fputs("one=BAR\\\n"
6fe31963
LP
176 "\\ \\ \\ \\ VAR\\\n"
177 "\\\tGAR\n"
ac4c8d6d
ZJS
178 "#comment\n"
179 "two=\"bar\\\n"
180 " var\\\n"
181 "\tgar\"\n"
182 "#comment\n"
183 "tri=\"bar \\\n"
184 " var \\\n"
185 "\tgar \"\n", f);
186
6fe31963 187 assert_se(fflush_and_check(f) >= 0);
ac4c8d6d
ZJS
188 fclose(f);
189
df8b14b5
LP
190 test_one_shell_var(t, "one", "BAR VAR\tGAR");
191 test_one_shell_var(t, "two", "bar var\tgar");
192 test_one_shell_var(t, "tri", "bar var \tgar ");
193
aa8fbc74 194 r = load_env_file(NULL, t, &a);
ac4c8d6d
ZJS
195 assert_se(r >= 0);
196
197 STRV_FOREACH(i, a)
198 log_info("Got: <%s>", *i);
199
5fba7bbf
TA
200 assert_se(streq_ptr(a[0], "one=BAR VAR\tGAR"));
201 assert_se(streq_ptr(a[1], "two=bar var\tgar"));
202 assert_se(streq_ptr(a[2], "tri=bar var \tgar "));
ac4c8d6d
ZJS
203 assert_se(a[3] == NULL);
204
d8351049
ZJS
205 {
206 _cleanup_close_ int fd = mkostemp_safe(p);
207 assert_se(fd >= 0);
208 }
209
ac4c8d6d
ZJS
210 r = write_env_file(p, a);
211 assert_se(r >= 0);
212
aa8fbc74 213 r = load_env_file(NULL, p, &b);
ac4c8d6d 214 assert_se(r >= 0);
ac4c8d6d
ZJS
215}
216
4f7452a8 217TEST(merge_env_file) {
627d2bac 218 _cleanup_(unlink_tempfilep) char t[] = "/tmp/test-fileio-XXXXXX";
9707d552 219 _cleanup_fclose_ FILE *f = NULL;
37f3ffca 220 _cleanup_strv_free_ char **a = NULL;
d8351049 221 int r;
37f3ffca 222
d8351049 223 assert_se(fmkostemp_safe(t, "w", &f) == 0);
37f3ffca
RS
224 log_info("/* %s (%s) */", __func__, t);
225
37f3ffca
RS
226 r = write_string_stream(f,
227 "one=1 \n"
228 "twelve=${one}2\n"
229 "twentyone=2${one}\n"
230 "one=2\n"
ccad1fd0
ZJS
231 "twentytwo=2${one}\n"
232 "xxx_minus_three=$xxx - 3\n"
233 "xxx=0x$one$one$one\n"
b82f58bf
RS
234 "yyy=${one:-fallback}\n"
235 "zzz=${one:+replacement}\n"
236 "zzzz=${foobar:-${nothing}}\n"
237 "zzzzz=${nothing:+${nothing}}\n"
b1837133 238 , WRITE_STRING_FILE_AVOID_NEWLINE);
f21b863e 239 assert_se(r >= 0);
37f3ffca
RS
240
241 r = merge_env_file(&a, NULL, t);
242 assert_se(r >= 0);
243 strv_sort(a);
244
245 STRV_FOREACH(i, a)
246 log_info("Got: <%s>", *i);
247
248 assert_se(streq(a[0], "one=2"));
249 assert_se(streq(a[1], "twelve=12"));
250 assert_se(streq(a[2], "twentyone=21"));
251 assert_se(streq(a[3], "twentytwo=22"));
ccad1fd0
ZJS
252 assert_se(streq(a[4], "xxx=0x222"));
253 assert_se(streq(a[5], "xxx_minus_three= - 3"));
b82f58bf
RS
254 assert_se(streq(a[6], "yyy=2"));
255 assert_se(streq(a[7], "zzz=replacement"));
256 assert_se(streq(a[8], "zzzz="));
257 assert_se(streq(a[9], "zzzzz="));
258 assert_se(a[10] == NULL);
37f3ffca
RS
259
260 r = merge_env_file(&a, NULL, t);
261 assert_se(r >= 0);
262 strv_sort(a);
263
264 STRV_FOREACH(i, a)
265 log_info("Got2: <%s>", *i);
266
267 assert_se(streq(a[0], "one=2"));
268 assert_se(streq(a[1], "twelve=12"));
269 assert_se(streq(a[2], "twentyone=21"));
270 assert_se(streq(a[3], "twentytwo=22"));
ccad1fd0
ZJS
271 assert_se(streq(a[4], "xxx=0x222"));
272 assert_se(streq(a[5], "xxx_minus_three=0x222 - 3"));
b82f58bf
RS
273 assert_se(streq(a[6], "yyy=2"));
274 assert_se(streq(a[7], "zzz=replacement"));
275 assert_se(streq(a[8], "zzzz="));
276 assert_se(streq(a[9], "zzzzz="));
277 assert_se(a[10] == NULL);
37f3ffca 278}
ac4c8d6d 279
4f7452a8 280TEST(merge_env_file_invalid) {
627d2bac 281 _cleanup_(unlink_tempfilep) char t[] = "/tmp/test-fileio-XXXXXX";
9707d552 282 _cleanup_fclose_ FILE *f = NULL;
184d1904 283 _cleanup_strv_free_ char **a = NULL;
d8351049 284 int r;
184d1904 285
d8351049 286 assert_se(fmkostemp_safe(t, "w", &f) == 0);
184d1904
ZJS
287 log_info("/* %s (%s) */", __func__, t);
288
184d1904
ZJS
289 r = write_string_stream(f,
290 "unset one \n"
291 "unset one= \n"
292 "unset one=1 \n"
293 "one \n"
294 "one = \n"
295 "one two =\n"
296 "\x20two=\n"
297 "#comment=comment\n"
298 ";comment2=comment2\n"
299 "#\n"
300 "\n\n" /* empty line */
b1837133 301 , WRITE_STRING_FILE_AVOID_NEWLINE);
f21b863e 302 assert_se(r >= 0);
184d1904
ZJS
303
304 r = merge_env_file(&a, NULL, t);
305 assert_se(r >= 0);
306
307 STRV_FOREACH(i, a)
308 log_info("Got: <%s>", *i);
309
310 assert_se(strv_isempty(a));
311}
312
4f7452a8 313TEST(executable_is_script) {
627d2bac 314 _cleanup_(unlink_tempfilep) char t[] = "/tmp/test-fileio-XXXXXX";
627d2bac 315 _cleanup_fclose_ FILE *f = NULL;
68fee104 316 char *command;
d8351049 317 int r;
68fee104 318
d8351049 319 assert_se(fmkostemp_safe(t, "w", &f) == 0);
68fee104
ZJS
320 fputs("#! /bin/script -a -b \ngoo goo", f);
321 fflush(f);
322
323 r = executable_is_script(t, &command);
324 assert_se(r > 0);
325 assert_se(streq(command, "/bin/script"));
326 free(command);
327
328 r = executable_is_script("/bin/sh", &command);
329 assert_se(r == 0);
330
331 r = executable_is_script("/usr/bin/yum", &command);
332 assert_se(r > 0 || r == -ENOENT);
333 if (r > 0) {
334 assert_se(startswith(command, "/"));
335 free(command);
336 }
68fee104
ZJS
337}
338
4f7452a8 339TEST(status_field) {
1e5413f7
ZJS
340 _cleanup_free_ char *t = NULL, *p = NULL, *s = NULL, *z = NULL;
341 unsigned long long total = 0, buffers = 0;
442e0083 342 int r;
69ab8088 343
c4cd1d4d 344 assert_se(get_proc_field("/proc/self/status", "Threads", WHITESPACE, &t) == 0);
69ab8088
ZJS
345 puts(t);
346 assert_se(streq(t, "1"));
347
c4cd1d4d 348 r = get_proc_field("/proc/meminfo", "MemTotal", WHITESPACE, &p);
1e5413f7 349 if (r != -ENOENT) {
bdf7026e 350 assert_se(r == 0);
1e5413f7
ZJS
351 puts(p);
352 assert_se(safe_atollu(p, &total) == 0);
353 }
69ab8088 354
c4cd1d4d 355 r = get_proc_field("/proc/meminfo", "Buffers", WHITESPACE, &s);
1e5413f7 356 if (r != -ENOENT) {
bdf7026e 357 assert_se(r == 0);
1e5413f7
ZJS
358 puts(s);
359 assert_se(safe_atollu(s, &buffers) == 0);
360 }
69ab8088 361
2b01a801 362 if (p)
bdf7026e 363 assert_se(buffers < total);
1e5413f7
ZJS
364
365 /* Seccomp should be a good test for field full of zeros. */
c4cd1d4d 366 r = get_proc_field("/proc/meminfo", "Seccomp", WHITESPACE, &z);
1e5413f7 367 if (r != -ENOENT) {
bdf7026e 368 assert_se(r == 0);
1e5413f7
ZJS
369 puts(z);
370 assert_se(safe_atollu(z, &buffers) == 0);
371 }
372}
373
4f7452a8 374TEST(capeff) {
d12ccbc3 375 for (int pid = 0; pid < 2; pid++) {
1e5413f7 376 _cleanup_free_ char *capeff = NULL;
d12ccbc3 377 int r, p;
1e5413f7
ZJS
378
379 r = get_process_capeff(0, &capeff);
380 log_info("capeff: '%s' (r=%d)", capeff, r);
381
4c701096 382 if (IN_SET(r, -ENOENT, -EPERM))
1e5413f7
ZJS
383 return;
384
bdf7026e
TA
385 assert_se(r == 0);
386 assert_se(*capeff);
1a7906ae 387 p = capeff[strspn(capeff, HEXDIGITS)];
bdf7026e 388 assert_se(!p || isspace(p));
1e5413f7 389 }
69ab8088
ZJS
390}
391
4f7452a8 392TEST(write_string_stream) {
627d2bac
ZJS
393 _cleanup_(unlink_tempfilep) char fn[] = "/tmp/test-write_string_stream-XXXXXX";
394 _cleanup_fclose_ FILE *f = NULL;
0709b743
RC
395 int fd;
396 char buf[64];
397
646853bd 398 fd = mkostemp_safe(fn);
0709b743
RC
399 assert_se(fd >= 0);
400
401 f = fdopen(fd, "r");
402 assert_se(f);
b1837133 403 assert_se(write_string_stream(f, "boohoo", 0) < 0);
36297390 404 f = safe_fclose(f);
0709b743 405
36297390 406 f = fopen(fn, "r+");
0709b743
RC
407 assert_se(f);
408
b1837133 409 assert_se(write_string_stream(f, "boohoo", 0) == 0);
0709b743
RC
410 rewind(f);
411
412 assert_se(fgets(buf, sizeof(buf), f));
413 assert_se(streq(buf, "boohoo\n"));
36297390 414 f = safe_fclose(f);
0709b743 415
36297390 416 f = fopen(fn, "w+");
40beecdb
DM
417 assert_se(f);
418
b1837133 419 assert_se(write_string_stream(f, "boohoo", WRITE_STRING_FILE_AVOID_NEWLINE) == 0);
40beecdb
DM
420 rewind(f);
421
422 assert_se(fgets(buf, sizeof(buf), f));
423 printf(">%s<", buf);
424 assert_se(streq(buf, "boohoo"));
0709b743
RC
425}
426
4f7452a8 427TEST(write_string_file) {
627d2bac 428 _cleanup_(unlink_tempfilep) char fn[] = "/tmp/test-write_string_file-XXXXXX";
76082570
RC
429 char buf[64] = {};
430 _cleanup_close_ int fd;
0709b743 431
646853bd 432 fd = mkostemp_safe(fn);
0709b743
RC
433 assert_se(fd >= 0);
434
4c1fc3e4 435 assert_se(write_string_file(fn, "boohoo", WRITE_STRING_FILE_CREATE) == 0);
0709b743 436
cca0efb0 437 assert_se(read(fd, buf, sizeof(buf)) == 7);
0709b743 438 assert_se(streq(buf, "boohoo\n"));
0709b743
RC
439}
440
4f7452a8 441TEST(write_string_file_no_create) {
627d2bac 442 _cleanup_(unlink_tempfilep) char fn[] = "/tmp/test-write_string_file_no_create-XXXXXX";
e07995a3 443 _cleanup_close_ int fd;
2aa07538 444 char buf[64] = {};
e07995a3 445
646853bd 446 fd = mkostemp_safe(fn);
e07995a3
RC
447 assert_se(fd >= 0);
448
4c1fc3e4
DM
449 assert_se(write_string_file("/a/file/which/does/not/exists/i/guess", "boohoo", 0) < 0);
450 assert_se(write_string_file(fn, "boohoo", 0) == 0);
e07995a3 451
2aa07538 452 assert_se(read(fd, buf, sizeof buf) == (ssize_t) strlen("boohoo\n"));
e07995a3 453 assert_se(streq(buf, "boohoo\n"));
e07995a3
RC
454}
455
4f7452a8 456TEST(write_string_file_verify) {
eb3da901
LP
457 _cleanup_free_ char *buf = NULL, *buf2 = NULL;
458 int r;
459
3c14dc61
TM
460 r = read_one_line_file("/proc/version", &buf);
461 if (ERRNO_IS_PRIVILEGE(r))
462 return;
463 assert_se(r >= 0);
dcd6361e 464 assert_se(buf2 = strjoin(buf, "\n"));
eb3da901 465
30b84c78 466 r = write_string_file("/proc/version", buf, 0);
4c701096 467 assert_se(IN_SET(r, -EACCES, -EIO));
30b84c78 468 r = write_string_file("/proc/version", buf2, 0);
4c701096 469 assert_se(IN_SET(r, -EACCES, -EIO));
eb3da901 470
30b84c78
ZJS
471 assert_se(write_string_file("/proc/version", buf, WRITE_STRING_FILE_VERIFY_ON_FAILURE) == 0);
472 assert_se(write_string_file("/proc/version", buf2, WRITE_STRING_FILE_VERIFY_ON_FAILURE) == 0);
eb3da901 473
30b84c78 474 r = write_string_file("/proc/version", buf, WRITE_STRING_FILE_VERIFY_ON_FAILURE|WRITE_STRING_FILE_AVOID_NEWLINE);
4c701096 475 assert_se(IN_SET(r, -EACCES, -EIO));
30b84c78 476 assert_se(write_string_file("/proc/version", buf2, WRITE_STRING_FILE_VERIFY_ON_FAILURE|WRITE_STRING_FILE_AVOID_NEWLINE) == 0);
eb3da901
LP
477}
478
4f7452a8 479TEST(load_env_file_pairs) {
627d2bac
ZJS
480 _cleanup_(unlink_tempfilep) char fn[] = "/tmp/test-load_env_file_pairs-XXXXXX";
481 int fd, r;
e07995a3
RC
482 _cleanup_fclose_ FILE *f = NULL;
483 _cleanup_strv_free_ char **l = NULL;
e07995a3 484
646853bd 485 fd = mkostemp_safe(fn);
e07995a3
RC
486 assert_se(fd >= 0);
487
488 r = write_string_file(fn,
489 "NAME=\"Arch Linux\"\n"
490 "ID=arch\n"
491 "PRETTY_NAME=\"Arch Linux\"\n"
492 "ANSI_COLOR=\"0;36\"\n"
493 "HOME_URL=\"https://www.archlinux.org/\"\n"
494 "SUPPORT_URL=\"https://bbs.archlinux.org/\"\n"
4c1fc3e4
DM
495 "BUG_REPORT_URL=\"https://bugs.archlinux.org/\"\n",
496 WRITE_STRING_FILE_CREATE);
e07995a3
RC
497 assert_se(r == 0);
498
499 f = fdopen(fd, "r");
500 assert_se(f);
501
aa8fbc74 502 r = load_env_file_pairs(f, fn, &l);
e07995a3
RC
503 assert_se(r >= 0);
504
505 assert_se(strv_length(l) == 14);
506 STRV_FOREACH_PAIR(k, v, l) {
507 assert_se(STR_IN_SET(*k, "NAME", "ID", "PRETTY_NAME", "ANSI_COLOR", "HOME_URL", "SUPPORT_URL", "BUG_REPORT_URL"));
508 printf("%s=%s\n", *k, *v);
509 if (streq(*k, "NAME")) assert_se(streq(*v, "Arch Linux"));
510 if (streq(*k, "ID")) assert_se(streq(*v, "arch"));
511 if (streq(*k, "PRETTY_NAME")) assert_se(streq(*v, "Arch Linux"));
512 if (streq(*k, "ANSI_COLOR")) assert_se(streq(*v, "0;36"));
513 if (streq(*k, "HOME_URL")) assert_se(streq(*v, "https://www.archlinux.org/"));
514 if (streq(*k, "SUPPORT_URL")) assert_se(streq(*v, "https://bbs.archlinux.org/"));
515 if (streq(*k, "BUG_REPORT_URL")) assert_se(streq(*v, "https://bugs.archlinux.org/"));
516 }
e07995a3
RC
517}
518
4f7452a8 519TEST(search_and_fopen) {
2708160c
LP
520 static const char* const dirs[] = {
521 "/tmp/foo/bar",
522 "/tmp",
523 NULL
524 };
897891f0 525 char name[] = "/tmp/test-search_and_fopen.XXXXXX";
2708160c
LP
526 _cleanup_fclose_ FILE *f = NULL;
527 _cleanup_free_ char *p = NULL;
254d1313 528 _cleanup_close_ int fd = -EBADF;
2708160c
LP
529 const char *e;
530 int r;
897891f0 531
646853bd 532 fd = mkostemp_safe(name);
897891f0 533 assert_se(fd >= 0);
2708160c 534 fd = safe_close(fd);
897891f0 535
2708160c 536 r = search_and_fopen(basename(name), "re", NULL, (const char**) dirs, &f, &p);
897891f0 537 assert_se(r >= 0);
2708160c
LP
538 assert_se(e = path_startswith(p, "/tmp/"));
539 assert_se(streq(basename(name), e));
540 f = safe_fclose(f);
541 p = mfree(p);
897891f0 542
2708160c 543 r = search_and_fopen(name, "re", NULL, (const char**) dirs, &f, &p);
897891f0 544 assert_se(r >= 0);
2708160c
LP
545 assert_se(path_equal(name, p));
546 f = safe_fclose(f);
547 p = mfree(p);
897891f0 548
2708160c 549 r = search_and_fopen(basename(name), "re", "/", (const char**) dirs, &f, &p);
897891f0 550 assert_se(r >= 0);
2708160c
LP
551 assert_se(e = path_startswith(p, "/tmp/"));
552 assert_se(streq(basename(name), e));
553 f = safe_fclose(f);
554 p = mfree(p);
897891f0 555
a3ee0916 556 r = search_and_fopen("/a/file/which/does/not/exist/i/guess", "re", NULL, (const char**) dirs, &f, &p);
2708160c 557 assert_se(r == -ENOENT);
a3ee0916 558 r = search_and_fopen("afilewhichdoesnotexistiguess", "re", NULL, (const char**) dirs, &f, &p);
2708160c 559 assert_se(r == -ENOENT);
897891f0
RC
560
561 r = unlink(name);
562 assert_se(r == 0);
563
a3ee0916 564 r = search_and_fopen(basename(name), "re", NULL, (const char**) dirs, &f, &p);
2708160c 565 assert_se(r == -ENOENT);
897891f0
RC
566}
567
4f7452a8 568TEST(search_and_fopen_nulstr) {
2708160c
LP
569 static const char dirs[] =
570 "/tmp/foo/bar\0"
571 "/tmp\0";
627d2bac
ZJS
572
573 _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-search_and_fopen.XXXXXX";
2708160c
LP
574 _cleanup_fclose_ FILE *f = NULL;
575 _cleanup_free_ char *p = NULL;
254d1313 576 _cleanup_close_ int fd = -EBADF;
2708160c
LP
577 const char *e;
578 int r;
897891f0 579
646853bd 580 fd = mkostemp_safe(name);
897891f0 581 assert_se(fd >= 0);
2708160c 582 fd = safe_close(fd);
897891f0 583
2708160c 584 r = search_and_fopen_nulstr(basename(name), "re", NULL, dirs, &f, &p);
897891f0 585 assert_se(r >= 0);
2708160c
LP
586 assert_se(e = path_startswith(p, "/tmp/"));
587 assert_se(streq(basename(name), e));
588 f = safe_fclose(f);
589 p = mfree(p);
897891f0 590
2708160c 591 r = search_and_fopen_nulstr(name, "re", NULL, dirs, &f, &p);
897891f0 592 assert_se(r >= 0);
2708160c
LP
593 assert_se(path_equal(name, p));
594 f = safe_fclose(f);
595 p = mfree(p);
897891f0 596
a3ee0916 597 r = search_and_fopen_nulstr("/a/file/which/does/not/exist/i/guess", "re", NULL, dirs, &f, &p);
2708160c 598 assert_se(r == -ENOENT);
a3ee0916 599 r = search_and_fopen_nulstr("afilewhichdoesnotexistiguess", "re", NULL, dirs, &f, &p);
2708160c 600 assert_se(r == -ENOENT);
897891f0
RC
601
602 r = unlink(name);
603 assert_se(r == 0);
604
a3ee0916 605 r = search_and_fopen_nulstr(basename(name), "re", NULL, dirs, &f, &p);
2708160c 606 assert_se(r == -ENOENT);
897891f0
RC
607}
608
4f7452a8 609TEST(writing_tmpfile) {
627d2bac 610 _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-systemd_writing_tmpfile.XXXXXX";
897891f0
RC
611 _cleanup_free_ char *contents = NULL;
612 size_t size;
254d1313 613 _cleanup_close_ int fd = -EBADF;
627d2bac 614 int r;
897891f0 615
d12ccbc3
ZJS
616 struct iovec iov[] = {
617 IOVEC_MAKE_STRING("abc\n"),
618 IOVEC_MAKE_STRING(ALPHANUMERICAL "\n"),
619 IOVEC_MAKE_STRING(""),
620 };
897891f0 621
646853bd 622 fd = mkostemp_safe(name);
897891f0
RC
623 printf("tmpfile: %s", name);
624
625 r = writev(fd, iov, 3);
626 assert_se(r >= 0);
627
628 r = read_full_file(name, &contents, &size);
629 assert_se(r == 0);
630 printf("contents: %s", contents);
631 assert_se(streq(contents, "abc\n" ALPHANUMERICAL "\n"));
897891f0
RC
632}
633
4f7452a8 634TEST(tempfn) {
897891f0
RC
635 char *ret = NULL, *p;
636
637 assert_se(tempfn_xxxxxx("/foo/bar/waldo", NULL, &ret) >= 0);
638 assert_se(streq_ptr(ret, "/foo/bar/.#waldoXXXXXX"));
639 free(ret);
640
641 assert_se(tempfn_xxxxxx("/foo/bar/waldo", "[miau]", &ret) >= 0);
642 assert_se(streq_ptr(ret, "/foo/bar/.#[miau]waldoXXXXXX"));
643 free(ret);
644
645 assert_se(tempfn_random("/foo/bar/waldo", NULL, &ret) >= 0);
646 assert_se(p = startswith(ret, "/foo/bar/.#waldo"));
647 assert_se(strlen(p) == 16);
648 assert_se(in_charset(p, "0123456789abcdef"));
649 free(ret);
650
651 assert_se(tempfn_random("/foo/bar/waldo", "[wuff]", &ret) >= 0);
652 assert_se(p = startswith(ret, "/foo/bar/.#[wuff]waldo"));
653 assert_se(strlen(p) == 16);
654 assert_se(in_charset(p, "0123456789abcdef"));
655 free(ret);
656
657 assert_se(tempfn_random_child("/foo/bar/waldo", NULL, &ret) >= 0);
658 assert_se(p = startswith(ret, "/foo/bar/waldo/.#"));
659 assert_se(strlen(p) == 16);
660 assert_se(in_charset(p, "0123456789abcdef"));
661 free(ret);
662
663 assert_se(tempfn_random_child("/foo/bar/waldo", "[kikiriki]", &ret) >= 0);
664 assert_se(p = startswith(ret, "/foo/bar/waldo/.#[kikiriki]"));
665 assert_se(strlen(p) == 16);
666 assert_se(in_charset(p, "0123456789abcdef"));
667 free(ret);
668}
669
7f9d1aed 670static const char chars[] =
cdce33f9 671 "Aąę„”\n루\377";
7f9d1aed 672
6028d766 673DISABLE_WARNING_TYPE_LIMITS;
d3bdba38 674
4f7452a8 675TEST(fgetc) {
7f9d1aed
ZJS
676 _cleanup_fclose_ FILE *f = NULL;
677 char c;
678
f3bd4b3d 679 assert_se(f = fmemopen_unlocked((void*) chars, sizeof(chars), "r"));
7f9d1aed 680
72fd79b3 681 for (size_t i = 0; i < sizeof(chars); i++) {
7f9d1aed
ZJS
682 assert_se(safe_fgetc(f, &c) == 1);
683 assert_se(c == chars[i]);
684
72fd79b3
LP
685 if (ungetc(c, f) == EOF) {
686 /* EOF is -1, and hence we can't push value 255 in this way – if char is signed */
687 assert_se(c == (char) EOF);
688 assert_se(CHAR_MIN == -128); /* verify that char is signed on this platform */
689 } else {
690 assert_se(safe_fgetc(f, &c) == 1);
691 assert_se(c == chars[i]);
692 }
7f9d1aed 693
cdce33f9 694 /* But it works when we push it properly cast */
7f9d1aed
ZJS
695 assert_se(ungetc((unsigned char) c, f) != EOF);
696 assert_se(safe_fgetc(f, &c) == 1);
697 assert_se(c == chars[i]);
698 }
699
700 assert_se(safe_fgetc(f, &c) == 0);
701}
702
6028d766 703REENABLE_WARNING;
d3bdba38 704
2c9de139
ZJS
705static const char buffer[] =
706 "Some test data\n"
7f9d1aed 707 "루Non-ascii chars: ąę„”\n"
838894b0
LP
708 "terminators\r\n"
709 "and even more\n\r"
710 "now the same with a NUL\n\0"
711 "and more\r\0"
712 "and even more\r\n\0"
713 "and yet even more\n\r\0"
2c9de139
ZJS
714 "With newlines, and a NUL byte\0"
715 "\n"
716 "an empty line\n"
717 "an ignored line\n"
718 "and a very long line that is supposed to be truncated, because it is so long\n";
719
720static void test_read_line_one_file(FILE *f) {
4f9a66a3
LP
721 _cleanup_free_ char *line = NULL;
722
f5fbe71d 723 assert_se(read_line(f, SIZE_MAX, &line) == 15 && streq(line, "Some test data"));
4f9a66a3
LP
724 line = mfree(line);
725
f5fbe71d 726 assert_se(read_line(f, SIZE_MAX, &line) > 0 && streq(line, "루Non-ascii chars: ąę„”"));
838894b0
LP
727 line = mfree(line);
728
f5fbe71d 729 assert_se(read_line(f, SIZE_MAX, &line) == 13 && streq(line, "terminators"));
838894b0
LP
730 line = mfree(line);
731
f5fbe71d 732 assert_se(read_line(f, SIZE_MAX, &line) == 15 && streq(line, "and even more"));
838894b0
LP
733 line = mfree(line);
734
f5fbe71d 735 assert_se(read_line(f, SIZE_MAX, &line) == 25 && streq(line, "now the same with a NUL"));
838894b0
LP
736 line = mfree(line);
737
f5fbe71d 738 assert_se(read_line(f, SIZE_MAX, &line) == 10 && streq(line, "and more"));
838894b0
LP
739 line = mfree(line);
740
f5fbe71d 741 assert_se(read_line(f, SIZE_MAX, &line) == 16 && streq(line, "and even more"));
838894b0
LP
742 line = mfree(line);
743
f5fbe71d 744 assert_se(read_line(f, SIZE_MAX, &line) == 20 && streq(line, "and yet even more"));
838894b0
LP
745 line = mfree(line);
746
4f9a66a3
LP
747 assert_se(read_line(f, 1024, &line) == 30 && streq(line, "With newlines, and a NUL byte"));
748 line = mfree(line);
749
750 assert_se(read_line(f, 1024, &line) == 1 && streq(line, ""));
751 line = mfree(line);
752
753 assert_se(read_line(f, 1024, &line) == 14 && streq(line, "an empty line"));
754 line = mfree(line);
755
f5fbe71d 756 assert_se(read_line(f, SIZE_MAX, NULL) == 16);
4f9a66a3
LP
757
758 assert_se(read_line(f, 16, &line) == -ENOBUFS);
759 line = mfree(line);
760
761 /* read_line() stopped when it hit the limit, that means when we continue reading we'll read at the first
5238e957 762 * character after the previous limit. Let's make use of that to continue our test. */
838894b0 763 assert_se(read_line(f, 1024, &line) == 62 && streq(line, "line that is supposed to be truncated, because it is so long"));
4f9a66a3
LP
764 line = mfree(line);
765
766 assert_se(read_line(f, 1024, &line) == 0 && streq(line, ""));
767}
768
4f7452a8 769TEST(read_line1) {
2c9de139 770 _cleanup_fclose_ FILE *f = NULL;
2c9de139 771
f3bd4b3d 772 assert_se(f = fmemopen_unlocked((void*) buffer, sizeof(buffer), "r"));
2c9de139
ZJS
773 test_read_line_one_file(f);
774}
775
4f7452a8 776TEST(read_line2) {
627d2bac 777 _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-fileio.XXXXXX";
2c9de139
ZJS
778 int fd;
779 _cleanup_fclose_ FILE *f = NULL;
780
781 fd = mkostemp_safe(name);
782 assert_se(fd >= 0);
783 assert_se((size_t) write(fd, buffer, sizeof(buffer)) == sizeof(buffer));
784
785 assert_se(lseek(fd, 0, SEEK_SET) == 0);
786 assert_se(f = fdopen(fd, "r"));
787
788 test_read_line_one_file(f);
789}
790
4f7452a8 791TEST(read_line3) {
2c9de139
ZJS
792 _cleanup_fclose_ FILE *f = NULL;
793 _cleanup_free_ char *line = NULL;
794 int r;
795
30b84c78 796 f = fopen("/proc/uptime", "re");
2c9de139
ZJS
797 if (!f && IN_SET(errno, ENOENT, EPERM))
798 return;
799 assert_se(f);
800
801 r = read_line(f, LINE_MAX, &line);
b4555637
ZJS
802 assert_se(r >= 0);
803 if (r == 0)
804 assert_se(line && isempty(line));
805 else
806 assert_se((size_t) r == strlen(line) + 1);
2c9de139
ZJS
807 assert_se(read_line(f, LINE_MAX, NULL) == 0);
808}
809
4f7452a8 810TEST(read_line4) {
6baac700
LP
811 static const struct {
812 size_t length;
813 const char *string;
814 } eof_endings[] = {
815 /* Each of these will be followed by EOF and should generate the one same single string */
816 { 3, "foo" },
817 { 4, "foo\n" },
818 { 4, "foo\r" },
819 { 4, "foo\0" },
820 { 5, "foo\n\0" },
821 { 5, "foo\r\0" },
822 { 5, "foo\r\n" },
823 { 5, "foo\n\r" },
824 { 6, "foo\r\n\0" },
825 { 6, "foo\n\r\0" },
826 };
827
6baac700
LP
828 int r;
829
d12ccbc3 830 for (size_t i = 0; i < ELEMENTSOF(eof_endings); i++) {
6baac700
LP
831 _cleanup_fclose_ FILE *f = NULL;
832 _cleanup_free_ char *s = NULL;
833
673a1e6f 834 assert_se(f = fmemopen_unlocked((void*) eof_endings[i].string, eof_endings[i].length, "r"));
6baac700 835
f5fbe71d 836 r = read_line(f, SIZE_MAX, &s);
6baac700
LP
837 assert_se((size_t) r == eof_endings[i].length);
838 assert_se(streq_ptr(s, "foo"));
839
f5fbe71d 840 assert_se(read_line(f, SIZE_MAX, NULL) == 0); /* Ensure we hit EOF */
6baac700
LP
841 }
842}
843
4f7452a8 844TEST(read_nul_string) {
3946d576
LP
845 static const char test[] = "string nr. 1\0"
846 "string nr. 2\n\0"
517b7760 847 "\377empty string follows\0"
3946d576
LP
848 "\0"
849 "final string\n is empty\0"
850 "\0";
851
852 _cleanup_fclose_ FILE *f = NULL;
853 _cleanup_free_ char *s = NULL;
854
673a1e6f 855 assert_se(f = fmemopen_unlocked((void*) test, sizeof(test)-1, "r"));
3946d576
LP
856
857 assert_se(read_nul_string(f, LONG_LINE_MAX, &s) == 13 && streq_ptr(s, "string nr. 1"));
858 s = mfree(s);
859
860 assert_se(read_nul_string(f, LONG_LINE_MAX, &s) == 14 && streq_ptr(s, "string nr. 2\n"));
861 s = mfree(s);
862
517b7760 863 assert_se(read_nul_string(f, LONG_LINE_MAX, &s) == 22 && streq_ptr(s, "\377empty string follows"));
3946d576
LP
864 s = mfree(s);
865
866 assert_se(read_nul_string(f, LONG_LINE_MAX, &s) == 1 && streq_ptr(s, ""));
867 s = mfree(s);
868
869 assert_se(read_nul_string(f, LONG_LINE_MAX, &s) == 23 && streq_ptr(s, "final string\n is empty"));
870 s = mfree(s);
871
872 assert_se(read_nul_string(f, LONG_LINE_MAX, &s) == 1 && streq_ptr(s, ""));
873 s = mfree(s);
874
875 assert_se(read_nul_string(f, LONG_LINE_MAX, &s) == 0 && streq_ptr(s, ""));
876}
877
4f7452a8 878TEST(read_full_file_socket) {
b93d3f6b
LP
879 _cleanup_(rm_rf_physical_and_freep) char *z = NULL;
880 _cleanup_close_ int listener = -1;
d3dcf4e3 881 _cleanup_free_ char *data = NULL, *clientname = NULL;
b93d3f6b 882 union sockaddr_union sa;
28ae8da9 883 const char *j, *jj;
b93d3f6b
LP
884 size_t size;
885 pid_t pid;
886 int r;
887
b93d3f6b
LP
888 listener = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
889 assert_se(listener >= 0);
890
891 assert_se(mkdtemp_malloc(NULL, &z) >= 0);
892 j = strjoina(z, "/socket");
893
894 assert_se(sockaddr_un_set_path(&sa.un, j) >= 0);
895
896 assert_se(bind(listener, &sa.sa, SOCKADDR_UN_LEN(sa.un)) >= 0);
897 assert_se(listen(listener, 1) >= 0);
898
28ae8da9
LP
899 /* Make sure the socket doesn't fit into a struct sockaddr_un, but we can still access it */
900 jj = strjoina(z, "/a_very_long_patha_very_long_patha_very_long_patha_very_long_patha_very_long_patha_very_long_patha_very_long_patha_very_long_path");
901 assert_se(strlen(jj) > sizeof_field(struct sockaddr_un, sun_path));
902 assert_se(rename(j, jj) >= 0);
903
d3dcf4e3
LP
904 /* Bind the *client* socket to some randomized name, to verify that this works correctly. */
905 assert_se(asprintf(&clientname, "@%" PRIx64 "/test-bindname", random_u64()) >= 0);
906
b93d3f6b
LP
907 r = safe_fork("(server)", FORK_DEATHSIG|FORK_LOG, &pid);
908 assert_se(r >= 0);
909 if (r == 0) {
d3dcf4e3
LP
910 union sockaddr_union peer = {};
911 socklen_t peerlen = sizeof(peer);
254d1313 912 _cleanup_close_ int rfd = -EBADF;
b93d3f6b
LP
913 /* child */
914
915 rfd = accept4(listener, NULL, 0, SOCK_CLOEXEC);
916 assert_se(rfd >= 0);
917
d3dcf4e3
LP
918 assert_se(getpeername(rfd, &peer.sa, &peerlen) >= 0);
919
920 assert_se(peer.un.sun_family == AF_UNIX);
921 assert_se(peerlen > offsetof(struct sockaddr_un, sun_path));
922 assert_se(peer.un.sun_path[0] == 0);
923 assert_se(streq(peer.un.sun_path + 1, clientname + 1));
924
b93d3f6b
LP
925#define TEST_STR "This is a test\nreally."
926
927 assert_se(write(rfd, TEST_STR, strlen(TEST_STR)) == strlen(TEST_STR));
928 _exit(EXIT_SUCCESS);
929 }
930
28ae8da9
LP
931 assert_se(read_full_file_full(AT_FDCWD, jj, UINT64_MAX, SIZE_MAX, 0, NULL, &data, &size) == -ENXIO);
932 assert_se(read_full_file_full(AT_FDCWD, jj, UINT64_MAX, SIZE_MAX, READ_FULL_FILE_CONNECT_SOCKET, clientname, &data, &size) >= 0);
b93d3f6b
LP
933 assert_se(size == strlen(TEST_STR));
934 assert_se(streq(data, TEST_STR));
935
936 assert_se(wait_for_terminate_and_check("(server)", pid, WAIT_LOG) >= 0);
937#undef TEST_STR
938}
939
4f7452a8 940TEST(read_full_file_offset_size) {
986311c2
LP
941 _cleanup_fclose_ FILE *f = NULL;
942 _cleanup_(unlink_and_freep) char *fn = NULL;
943 _cleanup_free_ char *rbuf = NULL;
944 size_t rbuf_size;
945 uint8_t buf[4711];
946
947 random_bytes(buf, sizeof(buf));
948
949 assert_se(tempfn_random_child(NULL, NULL, &fn) >= 0);
950 assert_se(f = fopen(fn, "we"));
951 assert_se(fwrite(buf, 1, sizeof(buf), f) == sizeof(buf));
952 assert_se(fflush_and_check(f) >= 0);
953
954 assert_se(read_full_file_full(AT_FDCWD, fn, UINT64_MAX, SIZE_MAX, 0, NULL, &rbuf, &rbuf_size) >= 0);
955 assert_se(rbuf_size == sizeof(buf));
956 assert_se(memcmp(buf, rbuf, rbuf_size) == 0);
957 rbuf = mfree(rbuf);
958
959 assert_se(read_full_file_full(AT_FDCWD, fn, UINT64_MAX, 128, 0, NULL, &rbuf, &rbuf_size) >= 0);
960 assert_se(rbuf_size == 128);
961 assert_se(memcmp(buf, rbuf, rbuf_size) == 0);
962 rbuf = mfree(rbuf);
963
7b0da71d
LP
964 assert_se(read_full_file_full(AT_FDCWD, fn, UINT64_MAX, 128, READ_FULL_FILE_FAIL_WHEN_LARGER, NULL, &rbuf, &rbuf_size) == -E2BIG);
965 assert_se(read_full_file_full(AT_FDCWD, fn, UINT64_MAX, sizeof(buf)-1, READ_FULL_FILE_FAIL_WHEN_LARGER, NULL, &rbuf, &rbuf_size) == -E2BIG);
966 assert_se(read_full_file_full(AT_FDCWD, fn, UINT64_MAX, sizeof(buf), READ_FULL_FILE_FAIL_WHEN_LARGER, NULL, &rbuf, &rbuf_size) >= 0);
967 assert_se(rbuf_size == sizeof(buf));
968 assert_se(memcmp(buf, rbuf, rbuf_size) == 0);
969 rbuf = mfree(rbuf);
970
971 assert_se(read_full_file_full(AT_FDCWD, fn, 47, 128, READ_FULL_FILE_FAIL_WHEN_LARGER, NULL, &rbuf, &rbuf_size) == -E2BIG);
972 assert_se(read_full_file_full(AT_FDCWD, fn, 47, sizeof(buf)-47-1, READ_FULL_FILE_FAIL_WHEN_LARGER, NULL, &rbuf, &rbuf_size) == -E2BIG);
973 assert_se(read_full_file_full(AT_FDCWD, fn, 47, sizeof(buf)-47, READ_FULL_FILE_FAIL_WHEN_LARGER, NULL, &rbuf, &rbuf_size) >= 0);
974 assert_se(rbuf_size == sizeof(buf)-47);
975 assert_se(memcmp(buf+47, rbuf, rbuf_size) == 0);
976 rbuf = mfree(rbuf);
977
978 assert_se(read_full_file_full(AT_FDCWD, fn, UINT64_MAX, sizeof(buf)+1, READ_FULL_FILE_FAIL_WHEN_LARGER, NULL, &rbuf, &rbuf_size) >= 0);
979 assert_se(rbuf_size == sizeof(buf));
980 assert_se(memcmp(buf, rbuf, rbuf_size) == 0);
981 rbuf = mfree(rbuf);
982
986311c2
LP
983 assert_se(read_full_file_full(AT_FDCWD, fn, 1234, SIZE_MAX, 0, NULL, &rbuf, &rbuf_size) >= 0);
984 assert_se(rbuf_size == sizeof(buf) - 1234);
985 assert_se(memcmp(buf + 1234, rbuf, rbuf_size) == 0);
986 rbuf = mfree(rbuf);
987
988 assert_se(read_full_file_full(AT_FDCWD, fn, 2345, 777, 0, NULL, &rbuf, &rbuf_size) >= 0);
989 assert_se(rbuf_size == 777);
990 assert_se(memcmp(buf + 2345, rbuf, rbuf_size) == 0);
991 rbuf = mfree(rbuf);
992
993 assert_se(read_full_file_full(AT_FDCWD, fn, 4700, 20, 0, NULL, &rbuf, &rbuf_size) >= 0);
994 assert_se(rbuf_size == 11);
995 assert_se(memcmp(buf + 4700, rbuf, rbuf_size) == 0);
996 rbuf = mfree(rbuf);
997
998 assert_se(read_full_file_full(AT_FDCWD, fn, 10000, 99, 0, NULL, &rbuf, &rbuf_size) >= 0);
999 assert_se(rbuf_size == 0);
1000 rbuf = mfree(rbuf);
1001}
1002
4f7452a8 1003static void test_read_virtual_file_one(size_t max_size) {
bca895c4
ZJS
1004 int r;
1005
d12ccbc3
ZJS
1006 log_info("/* %s (max_size=%zu) */", __func__, max_size);
1007
bca895c4
ZJS
1008 FOREACH_STRING(filename,
1009 "/proc/1/cmdline",
1010 "/etc/nsswitch.conf",
f3b75122
LP
1011 "/sys/kernel/uevent_seqnum",
1012 "/proc/kcore",
1013 "/proc/kallsyms",
1014 "/proc/self/exe",
1015 "/proc/self/pagemap") {
bca895c4
ZJS
1016
1017 _cleanup_free_ char *buf = NULL;
1018 size_t size = 0;
1019
ad0e687c 1020 r = read_virtual_file(filename, max_size, &buf, &size);
8461d6da
LP
1021 if (r < 0) {
1022 log_info_errno(r, "read_virtual_file(\"%s\", %zu): %m", filename, max_size);
f3b75122
LP
1023 assert_se(ERRNO_IS_PRIVILEGE(r) || /* /proc/kcore is not accessible to unpriv */
1024 IN_SET(r,
1025 -ENOENT, /* Some of the files might be absent */
1026 -EINVAL, /* too small reads from /proc/self/pagemap trigger EINVAL */
1027 -EFBIG)); /* /proc/kcore and /proc/self/pagemap should be too large */
8461d6da
LP
1028 } else
1029 log_info("read_virtual_file(\"%s\", %zu): %s (%zu bytes)", filename, max_size, r ? "non-truncated" : "truncated", size);
bca895c4
ZJS
1030 }
1031}
1032
4f7452a8
JJ
1033TEST(test_read_virtual_file) {
1034 test_read_virtual_file_one(0);
1035 test_read_virtual_file_one(1);
1036 test_read_virtual_file_one(2);
1037 test_read_virtual_file_one(20);
1038 test_read_virtual_file_one(4096);
1039 test_read_virtual_file_one(4097);
1040 test_read_virtual_file_one(SIZE_MAX);
f73141d7 1041}
4f7452a8
JJ
1042
1043DEFINE_TEST_MAIN(LOG_DEBUG);