LCOV - code coverage report
Current view: top level - test - test-fileio.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 492 501 98.2 %
Date: 2019-08-22 15:41:25 Functions: 24 24 100.0 %

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

Generated by: LCOV version 1.14