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