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