]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/test/test-fileio.c
sd-bus: Cite sd_bus_creds_unref in sd_bus_get_name_creds docs
[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
30b84c78 447 assert_se(read_one_line_file("/proc/version", &buf) >= 0);
dcd6361e 448 assert_se(buf2 = strjoin(buf, "\n"));
eb3da901 449
30b84c78 450 r = write_string_file("/proc/version", buf, 0);
4c701096 451 assert_se(IN_SET(r, -EACCES, -EIO));
30b84c78 452 r = write_string_file("/proc/version", buf2, 0);
4c701096 453 assert_se(IN_SET(r, -EACCES, -EIO));
eb3da901 454
30b84c78
ZJS
455 assert_se(write_string_file("/proc/version", buf, WRITE_STRING_FILE_VERIFY_ON_FAILURE) == 0);
456 assert_se(write_string_file("/proc/version", buf2, WRITE_STRING_FILE_VERIFY_ON_FAILURE) == 0);
eb3da901 457
30b84c78 458 r = write_string_file("/proc/version", buf, WRITE_STRING_FILE_VERIFY_ON_FAILURE|WRITE_STRING_FILE_AVOID_NEWLINE);
4c701096 459 assert_se(IN_SET(r, -EACCES, -EIO));
30b84c78 460 assert_se(write_string_file("/proc/version", buf2, WRITE_STRING_FILE_VERIFY_ON_FAILURE|WRITE_STRING_FILE_AVOID_NEWLINE) == 0);
eb3da901
LP
461}
462
e07995a3 463static void test_load_env_file_pairs(void) {
627d2bac
ZJS
464 _cleanup_(unlink_tempfilep) char fn[] = "/tmp/test-load_env_file_pairs-XXXXXX";
465 int fd, r;
e07995a3
RC
466 _cleanup_fclose_ FILE *f = NULL;
467 _cleanup_strv_free_ char **l = NULL;
468 char **k, **v;
469
646853bd 470 fd = mkostemp_safe(fn);
e07995a3
RC
471 assert_se(fd >= 0);
472
473 r = write_string_file(fn,
474 "NAME=\"Arch Linux\"\n"
475 "ID=arch\n"
476 "PRETTY_NAME=\"Arch Linux\"\n"
477 "ANSI_COLOR=\"0;36\"\n"
478 "HOME_URL=\"https://www.archlinux.org/\"\n"
479 "SUPPORT_URL=\"https://bbs.archlinux.org/\"\n"
4c1fc3e4
DM
480 "BUG_REPORT_URL=\"https://bugs.archlinux.org/\"\n",
481 WRITE_STRING_FILE_CREATE);
e07995a3
RC
482 assert_se(r == 0);
483
484 f = fdopen(fd, "r");
485 assert_se(f);
486
aa8fbc74 487 r = load_env_file_pairs(f, fn, &l);
e07995a3
RC
488 assert_se(r >= 0);
489
490 assert_se(strv_length(l) == 14);
491 STRV_FOREACH_PAIR(k, v, l) {
492 assert_se(STR_IN_SET(*k, "NAME", "ID", "PRETTY_NAME", "ANSI_COLOR", "HOME_URL", "SUPPORT_URL", "BUG_REPORT_URL"));
493 printf("%s=%s\n", *k, *v);
494 if (streq(*k, "NAME")) assert_se(streq(*v, "Arch Linux"));
495 if (streq(*k, "ID")) assert_se(streq(*v, "arch"));
496 if (streq(*k, "PRETTY_NAME")) assert_se(streq(*v, "Arch Linux"));
497 if (streq(*k, "ANSI_COLOR")) assert_se(streq(*v, "0;36"));
498 if (streq(*k, "HOME_URL")) assert_se(streq(*v, "https://www.archlinux.org/"));
499 if (streq(*k, "SUPPORT_URL")) assert_se(streq(*v, "https://bbs.archlinux.org/"));
500 if (streq(*k, "BUG_REPORT_URL")) assert_se(streq(*v, "https://bugs.archlinux.org/"));
501 }
e07995a3
RC
502}
503
897891f0
RC
504static void test_search_and_fopen(void) {
505 const char *dirs[] = {"/tmp/foo/bar", "/tmp", NULL};
627d2bac 506
897891f0 507 char name[] = "/tmp/test-search_and_fopen.XXXXXX";
627d2bac 508 int fd, r;
897891f0
RC
509 FILE *f;
510
646853bd 511 fd = mkostemp_safe(name);
897891f0
RC
512 assert_se(fd >= 0);
513 close(fd);
514
515 r = search_and_fopen(basename(name), "r", NULL, dirs, &f);
516 assert_se(r >= 0);
517 fclose(f);
518
519 r = search_and_fopen(name, "r", NULL, dirs, &f);
520 assert_se(r >= 0);
521 fclose(f);
522
523 r = search_and_fopen(basename(name), "r", "/", dirs, &f);
524 assert_se(r >= 0);
525 fclose(f);
526
527 r = search_and_fopen("/a/file/which/does/not/exist/i/guess", "r", NULL, dirs, &f);
528 assert_se(r < 0);
529 r = search_and_fopen("afilewhichdoesnotexistiguess", "r", NULL, dirs, &f);
530 assert_se(r < 0);
531
532 r = unlink(name);
533 assert_se(r == 0);
534
535 r = search_and_fopen(basename(name), "r", NULL, dirs, &f);
536 assert_se(r < 0);
537}
538
897891f0
RC
539static void test_search_and_fopen_nulstr(void) {
540 const char dirs[] = "/tmp/foo/bar\0/tmp\0";
627d2bac
ZJS
541
542 _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-search_and_fopen.XXXXXX";
543 int fd, r;
897891f0
RC
544 FILE *f;
545
646853bd 546 fd = mkostemp_safe(name);
897891f0
RC
547 assert_se(fd >= 0);
548 close(fd);
549
550 r = search_and_fopen_nulstr(basename(name), "r", NULL, dirs, &f);
551 assert_se(r >= 0);
552 fclose(f);
553
554 r = search_and_fopen_nulstr(name, "r", NULL, dirs, &f);
555 assert_se(r >= 0);
556 fclose(f);
557
558 r = search_and_fopen_nulstr("/a/file/which/does/not/exist/i/guess", "r", NULL, dirs, &f);
559 assert_se(r < 0);
560 r = search_and_fopen_nulstr("afilewhichdoesnotexistiguess", "r", NULL, dirs, &f);
561 assert_se(r < 0);
562
563 r = unlink(name);
564 assert_se(r == 0);
565
566 r = search_and_fopen_nulstr(basename(name), "r", NULL, dirs, &f);
567 assert_se(r < 0);
568}
569
570static void test_writing_tmpfile(void) {
627d2bac 571 _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-systemd_writing_tmpfile.XXXXXX";
897891f0
RC
572 _cleanup_free_ char *contents = NULL;
573 size_t size;
9a92e255 574 _cleanup_close_ int fd = -1;
897891f0 575 struct iovec iov[3];
627d2bac 576 int r;
897891f0 577
e6a7ec4b
LP
578 iov[0] = IOVEC_MAKE_STRING("abc\n");
579 iov[1] = IOVEC_MAKE_STRING(ALPHANUMERICAL "\n");
580 iov[2] = IOVEC_MAKE_STRING("");
897891f0 581
646853bd 582 fd = mkostemp_safe(name);
897891f0
RC
583 printf("tmpfile: %s", name);
584
585 r = writev(fd, iov, 3);
586 assert_se(r >= 0);
587
588 r = read_full_file(name, &contents, &size);
589 assert_se(r == 0);
590 printf("contents: %s", contents);
591 assert_se(streq(contents, "abc\n" ALPHANUMERICAL "\n"));
897891f0
RC
592}
593
594static void test_tempfn(void) {
595 char *ret = NULL, *p;
596
597 assert_se(tempfn_xxxxxx("/foo/bar/waldo", NULL, &ret) >= 0);
598 assert_se(streq_ptr(ret, "/foo/bar/.#waldoXXXXXX"));
599 free(ret);
600
601 assert_se(tempfn_xxxxxx("/foo/bar/waldo", "[miau]", &ret) >= 0);
602 assert_se(streq_ptr(ret, "/foo/bar/.#[miau]waldoXXXXXX"));
603 free(ret);
604
605 assert_se(tempfn_random("/foo/bar/waldo", NULL, &ret) >= 0);
606 assert_se(p = startswith(ret, "/foo/bar/.#waldo"));
607 assert_se(strlen(p) == 16);
608 assert_se(in_charset(p, "0123456789abcdef"));
609 free(ret);
610
611 assert_se(tempfn_random("/foo/bar/waldo", "[wuff]", &ret) >= 0);
612 assert_se(p = startswith(ret, "/foo/bar/.#[wuff]waldo"));
613 assert_se(strlen(p) == 16);
614 assert_se(in_charset(p, "0123456789abcdef"));
615 free(ret);
616
617 assert_se(tempfn_random_child("/foo/bar/waldo", NULL, &ret) >= 0);
618 assert_se(p = startswith(ret, "/foo/bar/waldo/.#"));
619 assert_se(strlen(p) == 16);
620 assert_se(in_charset(p, "0123456789abcdef"));
621 free(ret);
622
623 assert_se(tempfn_random_child("/foo/bar/waldo", "[kikiriki]", &ret) >= 0);
624 assert_se(p = startswith(ret, "/foo/bar/waldo/.#[kikiriki]"));
625 assert_se(strlen(p) == 16);
626 assert_se(in_charset(p, "0123456789abcdef"));
627 free(ret);
628}
629
7f9d1aed 630static const char chars[] =
cdce33f9 631 "Aąę„”\n루\377";
7f9d1aed 632
d3bdba38
ZJS
633#pragma GCC diagnostic push
634#pragma GCC diagnostic ignored "-Wtype-limits"
635
7f9d1aed
ZJS
636static void test_fgetc(void) {
637 _cleanup_fclose_ FILE *f = NULL;
638 char c;
639
673a1e6f 640 f = fmemopen_unlocked((void*) chars, sizeof(chars), "re");
7f9d1aed
ZJS
641 assert_se(f);
642
72fd79b3 643 for (size_t i = 0; i < sizeof(chars); i++) {
7f9d1aed
ZJS
644 assert_se(safe_fgetc(f, &c) == 1);
645 assert_se(c == chars[i]);
646
72fd79b3
LP
647 if (ungetc(c, f) == EOF) {
648 /* EOF is -1, and hence we can't push value 255 in this way – if char is signed */
649 assert_se(c == (char) EOF);
650 assert_se(CHAR_MIN == -128); /* verify that char is signed on this platform */
651 } else {
652 assert_se(safe_fgetc(f, &c) == 1);
653 assert_se(c == chars[i]);
654 }
7f9d1aed 655
cdce33f9 656 /* But it works when we push it properly cast */
7f9d1aed
ZJS
657 assert_se(ungetc((unsigned char) c, f) != EOF);
658 assert_se(safe_fgetc(f, &c) == 1);
659 assert_se(c == chars[i]);
660 }
661
662 assert_se(safe_fgetc(f, &c) == 0);
663}
664
d3bdba38
ZJS
665#pragma GCC diagnostic pop
666
2c9de139
ZJS
667static const char buffer[] =
668 "Some test data\n"
7f9d1aed 669 "루Non-ascii chars: ąę„”\n"
838894b0
LP
670 "terminators\r\n"
671 "and even more\n\r"
672 "now the same with a NUL\n\0"
673 "and more\r\0"
674 "and even more\r\n\0"
675 "and yet even more\n\r\0"
2c9de139
ZJS
676 "With newlines, and a NUL byte\0"
677 "\n"
678 "an empty line\n"
679 "an ignored line\n"
680 "and a very long line that is supposed to be truncated, because it is so long\n";
681
682static void test_read_line_one_file(FILE *f) {
4f9a66a3
LP
683 _cleanup_free_ char *line = NULL;
684
4f9a66a3
LP
685 assert_se(read_line(f, (size_t) -1, &line) == 15 && streq(line, "Some test data"));
686 line = mfree(line);
687
7f9d1aed 688 assert_se(read_line(f, (size_t) -1, &line) > 0 && streq(line, "루Non-ascii chars: ąę„”"));
838894b0
LP
689 line = mfree(line);
690
691 assert_se(read_line(f, (size_t) -1, &line) == 13 && streq(line, "terminators"));
692 line = mfree(line);
693
694 assert_se(read_line(f, (size_t) -1, &line) == 15 && streq(line, "and even more"));
695 line = mfree(line);
696
697 assert_se(read_line(f, (size_t) -1, &line) == 25 && streq(line, "now the same with a NUL"));
698 line = mfree(line);
699
700 assert_se(read_line(f, (size_t) -1, &line) == 10 && streq(line, "and more"));
701 line = mfree(line);
702
703 assert_se(read_line(f, (size_t) -1, &line) == 16 && streq(line, "and even more"));
704 line = mfree(line);
705
706 assert_se(read_line(f, (size_t) -1, &line) == 20 && streq(line, "and yet even more"));
707 line = mfree(line);
708
4f9a66a3
LP
709 assert_se(read_line(f, 1024, &line) == 30 && streq(line, "With newlines, and a NUL byte"));
710 line = mfree(line);
711
712 assert_se(read_line(f, 1024, &line) == 1 && streq(line, ""));
713 line = mfree(line);
714
715 assert_se(read_line(f, 1024, &line) == 14 && streq(line, "an empty line"));
716 line = mfree(line);
717
718 assert_se(read_line(f, (size_t) -1, NULL) == 16);
719
720 assert_se(read_line(f, 16, &line) == -ENOBUFS);
721 line = mfree(line);
722
723 /* read_line() stopped when it hit the limit, that means when we continue reading we'll read at the first
5238e957 724 * character after the previous limit. Let's make use of that to continue our test. */
838894b0 725 assert_se(read_line(f, 1024, &line) == 62 && streq(line, "line that is supposed to be truncated, because it is so long"));
4f9a66a3
LP
726 line = mfree(line);
727
728 assert_se(read_line(f, 1024, &line) == 0 && streq(line, ""));
729}
730
2c9de139
ZJS
731static void test_read_line(void) {
732 _cleanup_fclose_ FILE *f = NULL;
2c9de139 733
673a1e6f 734 f = fmemopen_unlocked((void*) buffer, sizeof(buffer), "re");
2c9de139
ZJS
735 assert_se(f);
736
737 test_read_line_one_file(f);
738}
739
740static void test_read_line2(void) {
627d2bac 741 _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-fileio.XXXXXX";
2c9de139
ZJS
742 int fd;
743 _cleanup_fclose_ FILE *f = NULL;
744
745 fd = mkostemp_safe(name);
746 assert_se(fd >= 0);
747 assert_se((size_t) write(fd, buffer, sizeof(buffer)) == sizeof(buffer));
748
749 assert_se(lseek(fd, 0, SEEK_SET) == 0);
750 assert_se(f = fdopen(fd, "r"));
751
752 test_read_line_one_file(f);
753}
754
755static void test_read_line3(void) {
756 _cleanup_fclose_ FILE *f = NULL;
757 _cleanup_free_ char *line = NULL;
758 int r;
759
30b84c78 760 f = fopen("/proc/uptime", "re");
2c9de139
ZJS
761 if (!f && IN_SET(errno, ENOENT, EPERM))
762 return;
763 assert_se(f);
764
765 r = read_line(f, LINE_MAX, &line);
b4555637
ZJS
766 assert_se(r >= 0);
767 if (r == 0)
768 assert_se(line && isempty(line));
769 else
770 assert_se((size_t) r == strlen(line) + 1);
2c9de139
ZJS
771 assert_se(read_line(f, LINE_MAX, NULL) == 0);
772}
773
6baac700
LP
774static void test_read_line4(void) {
775 static const struct {
776 size_t length;
777 const char *string;
778 } eof_endings[] = {
779 /* Each of these will be followed by EOF and should generate the one same single string */
780 { 3, "foo" },
781 { 4, "foo\n" },
782 { 4, "foo\r" },
783 { 4, "foo\0" },
784 { 5, "foo\n\0" },
785 { 5, "foo\r\0" },
786 { 5, "foo\r\n" },
787 { 5, "foo\n\r" },
788 { 6, "foo\r\n\0" },
789 { 6, "foo\n\r\0" },
790 };
791
792 size_t i;
793 int r;
794
795 for (i = 0; i < ELEMENTSOF(eof_endings); i++) {
796 _cleanup_fclose_ FILE *f = NULL;
797 _cleanup_free_ char *s = NULL;
798
673a1e6f 799 assert_se(f = fmemopen_unlocked((void*) eof_endings[i].string, eof_endings[i].length, "r"));
6baac700
LP
800
801 r = read_line(f, (size_t) -1, &s);
802 assert_se((size_t) r == eof_endings[i].length);
803 assert_se(streq_ptr(s, "foo"));
804
805 assert_se(read_line(f, (size_t) -1, NULL) == 0); /* Ensure we hit EOF */
806 }
807}
808
3946d576
LP
809static void test_read_nul_string(void) {
810 static const char test[] = "string nr. 1\0"
811 "string nr. 2\n\0"
517b7760 812 "\377empty string follows\0"
3946d576
LP
813 "\0"
814 "final string\n is empty\0"
815 "\0";
816
817 _cleanup_fclose_ FILE *f = NULL;
818 _cleanup_free_ char *s = NULL;
819
673a1e6f 820 assert_se(f = fmemopen_unlocked((void*) test, sizeof(test)-1, "r"));
3946d576
LP
821
822 assert_se(read_nul_string(f, LONG_LINE_MAX, &s) == 13 && streq_ptr(s, "string nr. 1"));
823 s = mfree(s);
824
825 assert_se(read_nul_string(f, LONG_LINE_MAX, &s) == 14 && streq_ptr(s, "string nr. 2\n"));
826 s = mfree(s);
827
517b7760 828 assert_se(read_nul_string(f, LONG_LINE_MAX, &s) == 22 && streq_ptr(s, "\377empty string follows"));
3946d576
LP
829 s = mfree(s);
830
831 assert_se(read_nul_string(f, LONG_LINE_MAX, &s) == 1 && streq_ptr(s, ""));
832 s = mfree(s);
833
834 assert_se(read_nul_string(f, LONG_LINE_MAX, &s) == 23 && streq_ptr(s, "final string\n is empty"));
835 s = mfree(s);
836
837 assert_se(read_nul_string(f, LONG_LINE_MAX, &s) == 1 && streq_ptr(s, ""));
838 s = mfree(s);
839
840 assert_se(read_nul_string(f, LONG_LINE_MAX, &s) == 0 && streq_ptr(s, ""));
841}
842
f73141d7 843int main(int argc, char *argv[]) {
6d7c4033 844 test_setup_logging(LOG_DEBUG);
1e5413f7 845
f73141d7 846 test_parse_env_file();
ac4c8d6d 847 test_parse_multiline_env_file();
37f3ffca 848 test_merge_env_file();
184d1904 849 test_merge_env_file_invalid();
68fee104 850 test_executable_is_script();
69ab8088 851 test_status_field();
1e5413f7 852 test_capeff();
0709b743
RC
853 test_write_string_stream();
854 test_write_string_file();
e07995a3 855 test_write_string_file_no_create();
eb3da901 856 test_write_string_file_verify();
e07995a3 857 test_load_env_file_pairs();
897891f0
RC
858 test_search_and_fopen();
859 test_search_and_fopen_nulstr();
860 test_writing_tmpfile();
861 test_tempfn();
7f9d1aed 862 test_fgetc();
4f9a66a3 863 test_read_line();
2c9de139
ZJS
864 test_read_line2();
865 test_read_line3();
6baac700 866 test_read_line4();
3946d576 867 test_read_nul_string();
1e5413f7 868
f73141d7
LP
869 return 0;
870}