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