]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/test/test-fileio.c
Merge pull request #8106 from dqminh/route-expires-kernel
[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 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 f = safe_fclose(f);
420
421 f = fopen(fn, "r+");
422 assert_se(f);
423
424 assert_se(write_string_stream(f, "boohoo", 0) == 0);
425 rewind(f);
426
427 assert_se(fgets(buf, sizeof(buf), f));
428 assert_se(streq(buf, "boohoo\n"));
429 f = safe_fclose(f);
430
431 f = fopen(fn, "w+");
432 assert_se(f);
433
434 assert_se(write_string_stream(f, "boohoo", WRITE_STRING_FILE_AVOID_NEWLINE) == 0);
435 rewind(f);
436
437 assert_se(fgets(buf, sizeof(buf), f));
438 printf(">%s<", buf);
439 assert_se(streq(buf, "boohoo"));
440 f = safe_fclose(f);
441
442 unlink(fn);
443 }
444
445 static void test_write_string_file(void) {
446 char fn[] = "/tmp/test-write_string_file-XXXXXX";
447 char buf[64] = {};
448 _cleanup_close_ int fd;
449
450 fd = mkostemp_safe(fn);
451 assert_se(fd >= 0);
452
453 assert_se(write_string_file(fn, "boohoo", WRITE_STRING_FILE_CREATE) == 0);
454
455 assert_se(read(fd, buf, sizeof(buf)) == 7);
456 assert_se(streq(buf, "boohoo\n"));
457
458 unlink(fn);
459 }
460
461 static void test_write_string_file_no_create(void) {
462 char fn[] = "/tmp/test-write_string_file_no_create-XXXXXX";
463 _cleanup_close_ int fd;
464 char buf[64] = {0};
465
466 fd = mkostemp_safe(fn);
467 assert_se(fd >= 0);
468
469 assert_se(write_string_file("/a/file/which/does/not/exists/i/guess", "boohoo", 0) < 0);
470 assert_se(write_string_file(fn, "boohoo", 0) == 0);
471
472 assert_se(read(fd, buf, sizeof(buf)) == STRLEN("boohoo\n"));
473 assert_se(streq(buf, "boohoo\n"));
474
475 unlink(fn);
476 }
477
478 static void test_write_string_file_verify(void) {
479 _cleanup_free_ char *buf = NULL, *buf2 = NULL;
480 int r;
481
482 assert_se(read_one_line_file("/proc/cmdline", &buf) >= 0);
483 assert_se((buf2 = strjoin(buf, "\n")));
484
485 r = write_string_file("/proc/cmdline", buf, 0);
486 assert_se(IN_SET(r, -EACCES, -EIO));
487 r = write_string_file("/proc/cmdline", buf2, 0);
488 assert_se(IN_SET(r, -EACCES, -EIO));
489
490 assert_se(write_string_file("/proc/cmdline", buf, WRITE_STRING_FILE_VERIFY_ON_FAILURE) == 0);
491 assert_se(write_string_file("/proc/cmdline", buf2, WRITE_STRING_FILE_VERIFY_ON_FAILURE) == 0);
492
493 r = write_string_file("/proc/cmdline", buf, WRITE_STRING_FILE_VERIFY_ON_FAILURE|WRITE_STRING_FILE_AVOID_NEWLINE);
494 assert_se(IN_SET(r, -EACCES, -EIO));
495 assert_se(write_string_file("/proc/cmdline", buf2, WRITE_STRING_FILE_VERIFY_ON_FAILURE|WRITE_STRING_FILE_AVOID_NEWLINE) == 0);
496 }
497
498 static void test_load_env_file_pairs(void) {
499 char fn[] = "/tmp/test-load_env_file_pairs-XXXXXX";
500 int fd;
501 int r;
502 _cleanup_fclose_ FILE *f = NULL;
503 _cleanup_strv_free_ char **l = NULL;
504 char **k, **v;
505
506 fd = mkostemp_safe(fn);
507 assert_se(fd >= 0);
508
509 r = write_string_file(fn,
510 "NAME=\"Arch Linux\"\n"
511 "ID=arch\n"
512 "PRETTY_NAME=\"Arch Linux\"\n"
513 "ANSI_COLOR=\"0;36\"\n"
514 "HOME_URL=\"https://www.archlinux.org/\"\n"
515 "SUPPORT_URL=\"https://bbs.archlinux.org/\"\n"
516 "BUG_REPORT_URL=\"https://bugs.archlinux.org/\"\n",
517 WRITE_STRING_FILE_CREATE);
518 assert_se(r == 0);
519
520 f = fdopen(fd, "r");
521 assert_se(f);
522
523 r = load_env_file_pairs(f, fn, NULL, &l);
524 assert_se(r >= 0);
525
526 assert_se(strv_length(l) == 14);
527 STRV_FOREACH_PAIR(k, v, l) {
528 assert_se(STR_IN_SET(*k, "NAME", "ID", "PRETTY_NAME", "ANSI_COLOR", "HOME_URL", "SUPPORT_URL", "BUG_REPORT_URL"));
529 printf("%s=%s\n", *k, *v);
530 if (streq(*k, "NAME")) assert_se(streq(*v, "Arch Linux"));
531 if (streq(*k, "ID")) assert_se(streq(*v, "arch"));
532 if (streq(*k, "PRETTY_NAME")) assert_se(streq(*v, "Arch Linux"));
533 if (streq(*k, "ANSI_COLOR")) assert_se(streq(*v, "0;36"));
534 if (streq(*k, "HOME_URL")) assert_se(streq(*v, "https://www.archlinux.org/"));
535 if (streq(*k, "SUPPORT_URL")) assert_se(streq(*v, "https://bbs.archlinux.org/"));
536 if (streq(*k, "BUG_REPORT_URL")) assert_se(streq(*v, "https://bugs.archlinux.org/"));
537 }
538
539 unlink(fn);
540 }
541
542 static void test_search_and_fopen(void) {
543 const char *dirs[] = {"/tmp/foo/bar", "/tmp", NULL};
544 char name[] = "/tmp/test-search_and_fopen.XXXXXX";
545 int fd = -1;
546 int r;
547 FILE *f;
548
549 fd = mkostemp_safe(name);
550 assert_se(fd >= 0);
551 close(fd);
552
553 r = search_and_fopen(basename(name), "r", NULL, dirs, &f);
554 assert_se(r >= 0);
555 fclose(f);
556
557 r = search_and_fopen(name, "r", NULL, dirs, &f);
558 assert_se(r >= 0);
559 fclose(f);
560
561 r = search_and_fopen(basename(name), "r", "/", dirs, &f);
562 assert_se(r >= 0);
563 fclose(f);
564
565 r = search_and_fopen("/a/file/which/does/not/exist/i/guess", "r", NULL, dirs, &f);
566 assert_se(r < 0);
567 r = search_and_fopen("afilewhichdoesnotexistiguess", "r", NULL, dirs, &f);
568 assert_se(r < 0);
569
570 r = unlink(name);
571 assert_se(r == 0);
572
573 r = search_and_fopen(basename(name), "r", NULL, dirs, &f);
574 assert_se(r < 0);
575 }
576
577
578 static void test_search_and_fopen_nulstr(void) {
579 const char dirs[] = "/tmp/foo/bar\0/tmp\0";
580 char name[] = "/tmp/test-search_and_fopen.XXXXXX";
581 int fd = -1;
582 int r;
583 FILE *f;
584
585 fd = mkostemp_safe(name);
586 assert_se(fd >= 0);
587 close(fd);
588
589 r = search_and_fopen_nulstr(basename(name), "r", NULL, dirs, &f);
590 assert_se(r >= 0);
591 fclose(f);
592
593 r = search_and_fopen_nulstr(name, "r", NULL, dirs, &f);
594 assert_se(r >= 0);
595 fclose(f);
596
597 r = search_and_fopen_nulstr("/a/file/which/does/not/exist/i/guess", "r", NULL, dirs, &f);
598 assert_se(r < 0);
599 r = search_and_fopen_nulstr("afilewhichdoesnotexistiguess", "r", NULL, dirs, &f);
600 assert_se(r < 0);
601
602 r = unlink(name);
603 assert_se(r == 0);
604
605 r = search_and_fopen_nulstr(basename(name), "r", NULL, dirs, &f);
606 assert_se(r < 0);
607 }
608
609 static void test_writing_tmpfile(void) {
610 char name[] = "/tmp/test-systemd_writing_tmpfile.XXXXXX";
611 _cleanup_free_ char *contents = NULL;
612 size_t size;
613 int r;
614 _cleanup_close_ int fd = -1;
615 struct iovec iov[3];
616
617 iov[0] = IOVEC_MAKE_STRING("abc\n");
618 iov[1] = IOVEC_MAKE_STRING(ALPHANUMERICAL "\n");
619 iov[2] = IOVEC_MAKE_STRING("");
620
621 fd = mkostemp_safe(name);
622 printf("tmpfile: %s", name);
623
624 r = writev(fd, iov, 3);
625 assert_se(r >= 0);
626
627 r = read_full_file(name, &contents, &size);
628 assert_se(r == 0);
629 printf("contents: %s", contents);
630 assert_se(streq(contents, "abc\n" ALPHANUMERICAL "\n"));
631
632 unlink(name);
633 }
634
635 static void test_tempfn(void) {
636 char *ret = NULL, *p;
637
638 assert_se(tempfn_xxxxxx("/foo/bar/waldo", NULL, &ret) >= 0);
639 assert_se(streq_ptr(ret, "/foo/bar/.#waldoXXXXXX"));
640 free(ret);
641
642 assert_se(tempfn_xxxxxx("/foo/bar/waldo", "[miau]", &ret) >= 0);
643 assert_se(streq_ptr(ret, "/foo/bar/.#[miau]waldoXXXXXX"));
644 free(ret);
645
646 assert_se(tempfn_random("/foo/bar/waldo", NULL, &ret) >= 0);
647 assert_se(p = startswith(ret, "/foo/bar/.#waldo"));
648 assert_se(strlen(p) == 16);
649 assert_se(in_charset(p, "0123456789abcdef"));
650 free(ret);
651
652 assert_se(tempfn_random("/foo/bar/waldo", "[wuff]", &ret) >= 0);
653 assert_se(p = startswith(ret, "/foo/bar/.#[wuff]waldo"));
654 assert_se(strlen(p) == 16);
655 assert_se(in_charset(p, "0123456789abcdef"));
656 free(ret);
657
658 assert_se(tempfn_random_child("/foo/bar/waldo", NULL, &ret) >= 0);
659 assert_se(p = startswith(ret, "/foo/bar/waldo/.#"));
660 assert_se(strlen(p) == 16);
661 assert_se(in_charset(p, "0123456789abcdef"));
662 free(ret);
663
664 assert_se(tempfn_random_child("/foo/bar/waldo", "[kikiriki]", &ret) >= 0);
665 assert_se(p = startswith(ret, "/foo/bar/waldo/.#[kikiriki]"));
666 assert_se(strlen(p) == 16);
667 assert_se(in_charset(p, "0123456789abcdef"));
668 free(ret);
669 }
670
671 static const char buffer[] =
672 "Some test data\n"
673 "With newlines, and a NUL byte\0"
674 "\n"
675 "an empty line\n"
676 "an ignored line\n"
677 "and a very long line that is supposed to be truncated, because it is so long\n";
678
679 static void test_read_line_one_file(FILE *f) {
680 _cleanup_free_ char *line = NULL;
681
682 assert_se(read_line(f, (size_t) -1, &line) == 15 && streq(line, "Some test data"));
683 line = mfree(line);
684
685 assert_se(read_line(f, 1024, &line) == 30 && streq(line, "With newlines, and a NUL byte"));
686 line = mfree(line);
687
688 assert_se(read_line(f, 1024, &line) == 1 && streq(line, ""));
689 line = mfree(line);
690
691 assert_se(read_line(f, 1024, &line) == 14 && streq(line, "an empty line"));
692 line = mfree(line);
693
694 assert_se(read_line(f, (size_t) -1, NULL) == 16);
695
696 assert_se(read_line(f, 16, &line) == -ENOBUFS);
697 line = mfree(line);
698
699 /* read_line() stopped when it hit the limit, that means when we continue reading we'll read at the first
700 * character after the previous limit. Let's make use of tha to continue our test. */
701 assert_se(read_line(f, 1024, &line) == 61 && streq(line, "line that is supposed to be truncated, because it is so long"));
702 line = mfree(line);
703
704 assert_se(read_line(f, 1024, &line) == 1 && streq(line, ""));
705 line = mfree(line);
706
707 assert_se(read_line(f, 1024, &line) == 0 && streq(line, ""));
708 }
709
710 static void test_read_line(void) {
711 _cleanup_fclose_ FILE *f = NULL;
712
713 f = fmemopen((void*) buffer, sizeof(buffer), "re");
714 assert_se(f);
715
716 test_read_line_one_file(f);
717 }
718
719 static void test_read_line2(void) {
720 char name[] = "/tmp/test-fileio.XXXXXX";
721 int fd;
722 _cleanup_fclose_ FILE *f = NULL;
723
724 fd = mkostemp_safe(name);
725 assert_se(fd >= 0);
726 assert_se((size_t) write(fd, buffer, sizeof(buffer)) == sizeof(buffer));
727
728 assert_se(lseek(fd, 0, SEEK_SET) == 0);
729 assert_se(f = fdopen(fd, "r"));
730
731 test_read_line_one_file(f);
732 }
733
734 static void test_read_line3(void) {
735 _cleanup_fclose_ FILE *f = NULL;
736 _cleanup_free_ char *line = NULL;
737 int r;
738
739 f = fopen("/proc/cmdline", "re");
740 if (!f && IN_SET(errno, ENOENT, EPERM))
741 return;
742 assert_se(f);
743
744 r = read_line(f, LINE_MAX, &line);
745 assert_se((size_t) r == strlen(line) + 1);
746 assert_se(read_line(f, LINE_MAX, NULL) == 0);
747 }
748
749 int main(int argc, char *argv[]) {
750 log_set_max_level(LOG_DEBUG);
751 log_parse_environment();
752 log_open();
753
754 test_parse_env_file();
755 test_parse_multiline_env_file();
756 test_merge_env_file();
757 test_merge_env_file_invalid();
758 test_executable_is_script();
759 test_status_field();
760 test_capeff();
761 test_write_string_stream();
762 test_write_string_file();
763 test_write_string_file_no_create();
764 test_write_string_file_verify();
765 test_load_env_file_pairs();
766 test_search_and_fopen();
767 test_search_and_fopen_nulstr();
768 test_writing_tmpfile();
769 test_tempfn();
770 test_read_line();
771 test_read_line2();
772 test_read_line3();
773
774 return 0;
775 }