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