LCOV - code coverage report
Current view: top level - basic - fileio.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 309 463 66.7 %
Date: 2019-08-23 13:36:53 Functions: 21 28 75.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 208 388 53.6 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: LGPL-2.1+ */
       2                 :            : 
       3                 :            : #include <ctype.h>
       4                 :            : #include <errno.h>
       5                 :            : #include <fcntl.h>
       6                 :            : #include <limits.h>
       7                 :            : #include <stdarg.h>
       8                 :            : #include <stdint.h>
       9                 :            : #include <stdio_ext.h>
      10                 :            : #include <stdlib.h>
      11                 :            : #include <string.h>
      12                 :            : #include <sys/stat.h>
      13                 :            : #include <sys/types.h>
      14                 :            : #include <unistd.h>
      15                 :            : 
      16                 :            : #include "alloc-util.h"
      17                 :            : #include "fd-util.h"
      18                 :            : #include "fileio.h"
      19                 :            : #include "fs-util.h"
      20                 :            : #include "hexdecoct.h"
      21                 :            : #include "log.h"
      22                 :            : #include "macro.h"
      23                 :            : #include "missing.h"
      24                 :            : #include "mkdir.h"
      25                 :            : #include "parse-util.h"
      26                 :            : #include "path-util.h"
      27                 :            : #include "stdio-util.h"
      28                 :            : #include "string-util.h"
      29                 :            : #include "tmpfile-util.h"
      30                 :            : 
      31                 :            : #define READ_FULL_BYTES_MAX (4U*1024U*1024U)
      32                 :            : 
      33                 :      81854 : int fopen_unlocked(const char *path, const char *options, FILE **ret) {
      34         [ -  + ]:      81854 :         assert(ret);
      35                 :            : 
      36                 :      81854 :         FILE *f = fopen(path, options);
      37         [ +  + ]:      81854 :         if (!f)
      38                 :      29556 :                 return -errno;
      39                 :            : 
      40                 :      52298 :         (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
      41                 :            : 
      42                 :      52298 :         *ret = f;
      43                 :      52298 :         return 0;
      44                 :            : }
      45                 :            : 
      46                 :         24 : int fdopen_unlocked(int fd, const char *options, FILE **ret) {
      47         [ -  + ]:         24 :         assert(ret);
      48                 :            : 
      49                 :         24 :         FILE *f = fdopen(fd, options);
      50         [ -  + ]:         24 :         if (!f)
      51                 :          0 :                 return -errno;
      52                 :            : 
      53                 :         24 :         (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
      54                 :            : 
      55                 :         24 :         *ret = f;
      56                 :         24 :         return 0;
      57                 :            : }
      58                 :            : 
      59                 :       2184 : FILE* open_memstream_unlocked(char **ptr, size_t *sizeloc) {
      60                 :       2184 :         FILE *f = open_memstream(ptr, sizeloc);
      61         [ -  + ]:       2184 :         if (!f)
      62                 :          0 :                 return NULL;
      63                 :            : 
      64                 :       2184 :         (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
      65                 :            : 
      66                 :       2184 :         return f;
      67                 :            : }
      68                 :            : 
      69                 :         56 : FILE* fmemopen_unlocked(void *buf, size_t size, const char *mode) {
      70                 :         56 :         FILE *f = fmemopen(buf, size, mode);
      71         [ -  + ]:         56 :         if (!f)
      72                 :          0 :                 return NULL;
      73                 :            : 
      74                 :         56 :         (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
      75                 :            : 
      76                 :         56 :         return f;
      77                 :            : }
      78                 :            : 
      79                 :        472 : int write_string_stream_ts(
      80                 :            :                 FILE *f,
      81                 :            :                 const char *line,
      82                 :            :                 WriteStringFileFlags flags,
      83                 :            :                 struct timespec *ts) {
      84                 :            : 
      85                 :            :         bool needs_nl;
      86                 :            :         int r;
      87                 :            : 
      88         [ -  + ]:        472 :         assert(f);
      89         [ -  + ]:        472 :         assert(line);
      90                 :            : 
      91         [ -  + ]:        472 :         if (ferror(f))
      92                 :          0 :                 return -EIO;
      93                 :            : 
      94   [ +  +  +  + ]:        472 :         needs_nl = !(flags & WRITE_STRING_FILE_AVOID_NEWLINE) && !endswith(line, "\n");
      95                 :            : 
      96   [ +  +  -  + ]:        472 :         if (needs_nl && (flags & WRITE_STRING_FILE_DISABLE_BUFFER)) {
      97                 :            :                 /* If STDIO buffering was disabled, then let's append the newline character to the string itself, so
      98                 :            :                  * that the write goes out in one go, instead of two */
      99                 :            : 
     100   [ #  #  #  #  :          0 :                 line = strjoina(line, "\n");
          #  #  #  #  #  
                #  #  # ]
     101                 :          0 :                 needs_nl = false;
     102                 :            :         }
     103                 :            : 
     104         [ +  + ]:        472 :         if (fputs(line, f) == EOF)
     105                 :          4 :                 return -errno;
     106                 :            : 
     107         [ +  + ]:        468 :         if (needs_nl)
     108         [ -  + ]:        248 :                 if (fputc('\n', f) == EOF)
     109                 :          0 :                         return -errno;
     110                 :            : 
     111         [ -  + ]:        468 :         if (flags & WRITE_STRING_FILE_SYNC)
     112                 :          0 :                 r = fflush_sync_and_check(f);
     113                 :            :         else
     114                 :        468 :                 r = fflush_and_check(f);
     115         [ -  + ]:        468 :         if (r < 0)
     116                 :          0 :                 return r;
     117                 :            : 
     118         [ -  + ]:        468 :         if (ts) {
     119                 :          0 :                 struct timespec twice[2] = {*ts, *ts};
     120                 :            : 
     121         [ #  # ]:          0 :                 if (futimens(fileno(f), twice) < 0)
     122                 :          0 :                         return -errno;
     123                 :            :         }
     124                 :            : 
     125                 :        468 :         return 0;
     126                 :            : }
     127                 :            : 
     128                 :          0 : static int write_string_file_atomic(
     129                 :            :                 const char *fn,
     130                 :            :                 const char *line,
     131                 :            :                 WriteStringFileFlags flags,
     132                 :            :                 struct timespec *ts) {
     133                 :            : 
     134                 :          0 :         _cleanup_fclose_ FILE *f = NULL;
     135                 :          0 :         _cleanup_free_ char *p = NULL;
     136                 :            :         int r;
     137                 :            : 
     138         [ #  # ]:          0 :         assert(fn);
     139         [ #  # ]:          0 :         assert(line);
     140                 :            : 
     141                 :          0 :         r = fopen_temporary(fn, &f, &p);
     142         [ #  # ]:          0 :         if (r < 0)
     143                 :          0 :                 return r;
     144                 :            : 
     145                 :          0 :         (void) fchmod_umask(fileno(f), 0644);
     146                 :            : 
     147                 :          0 :         r = write_string_stream_ts(f, line, flags, ts);
     148         [ #  # ]:          0 :         if (r < 0)
     149                 :          0 :                 goto fail;
     150                 :            : 
     151         [ #  # ]:          0 :         if (rename(p, fn) < 0) {
     152                 :          0 :                 r = -errno;
     153                 :          0 :                 goto fail;
     154                 :            :         }
     155                 :            : 
     156                 :          0 :         return 0;
     157                 :            : 
     158                 :          0 : fail:
     159                 :          0 :         (void) unlink(p);
     160                 :          0 :         return r;
     161                 :            : }
     162                 :            : 
     163                 :        424 : int write_string_file_ts(
     164                 :            :                 const char *fn,
     165                 :            :                 const char *line,
     166                 :            :                 WriteStringFileFlags flags,
     167                 :            :                 struct timespec *ts) {
     168                 :            : 
     169                 :        424 :         _cleanup_fclose_ FILE *f = NULL;
     170                 :            :         int q, r;
     171                 :            : 
     172         [ -  + ]:        424 :         assert(fn);
     173         [ -  + ]:        424 :         assert(line);
     174                 :            : 
     175                 :            :         /* We don't know how to verify whether the file contents was already on-disk. */
     176   [ +  +  -  + ]:        424 :         assert(!((flags & WRITE_STRING_FILE_VERIFY_ON_FAILURE) && (flags & WRITE_STRING_FILE_SYNC)));
     177                 :            : 
     178         [ -  + ]:        424 :         if (flags & WRITE_STRING_FILE_MKDIR_0755) {
     179                 :          0 :                 r = mkdir_parents(fn, 0755);
     180         [ #  # ]:          0 :                 if (r < 0)
     181                 :          0 :                         return r;
     182                 :            :         }
     183                 :            : 
     184         [ -  + ]:        424 :         if (flags & WRITE_STRING_FILE_ATOMIC) {
     185         [ #  # ]:          0 :                 assert(flags & WRITE_STRING_FILE_CREATE);
     186                 :            : 
     187                 :          0 :                 r = write_string_file_atomic(fn, line, flags, ts);
     188         [ #  # ]:          0 :                 if (r < 0)
     189                 :          0 :                         goto fail;
     190                 :            : 
     191                 :          0 :                 return r;
     192                 :            :         } else
     193         [ -  + ]:        424 :                 assert(!ts);
     194                 :            : 
     195         [ +  + ]:        424 :         if (flags & WRITE_STRING_FILE_CREATE) {
     196                 :        356 :                 r = fopen_unlocked(fn, "we", &f);
     197         [ -  + ]:        356 :                 if (r < 0)
     198                 :          0 :                         goto fail;
     199                 :            :         } else {
     200                 :            :                 int fd;
     201                 :            : 
     202                 :            :                 /* We manually build our own version of fopen(..., "we") that
     203                 :            :                  * works without O_CREAT */
     204                 :         68 :                 fd = open(fn, O_WRONLY|O_CLOEXEC|O_NOCTTY | ((flags & WRITE_STRING_FILE_NOFOLLOW) ? O_NOFOLLOW : 0));
     205         [ +  + ]:         68 :                 if (fd < 0) {
     206                 :         64 :                         r = -errno;
     207                 :         64 :                         goto fail;
     208                 :            :                 }
     209                 :            : 
     210                 :          4 :                 r = fdopen_unlocked(fd, "w", &f);
     211         [ -  + ]:          4 :                 if (r < 0) {
     212                 :          0 :                         safe_close(fd);
     213                 :          0 :                         goto fail;
     214                 :            :                 }
     215                 :            :         }
     216                 :            : 
     217         [ -  + ]:        360 :         if (flags & WRITE_STRING_FILE_DISABLE_BUFFER)
     218                 :          0 :                 setvbuf(f, NULL, _IONBF, 0);
     219                 :            : 
     220                 :        360 :         r = write_string_stream_ts(f, line, flags, ts);
     221         [ -  + ]:        360 :         if (r < 0)
     222                 :          0 :                 goto fail;
     223                 :            : 
     224                 :        360 :         return 0;
     225                 :            : 
     226                 :         64 : fail:
     227         [ +  + ]:         64 :         if (!(flags & WRITE_STRING_FILE_VERIFY_ON_FAILURE))
     228                 :         48 :                 return r;
     229                 :            : 
     230                 :         16 :         f = safe_fclose(f);
     231                 :            : 
     232                 :            :         /* OK, the operation failed, but let's see if the right
     233                 :            :          * contents in place already. If so, eat up the error. */
     234                 :            : 
     235                 :         16 :         q = verify_file(fn, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE));
     236         [ +  + ]:         16 :         if (q <= 0)
     237                 :          4 :                 return r;
     238                 :            : 
     239                 :         12 :         return 0;
     240                 :            : }
     241                 :            : 
     242                 :          0 : int write_string_filef(
     243                 :            :                 const char *fn,
     244                 :            :                 WriteStringFileFlags flags,
     245                 :            :                 const char *format, ...) {
     246                 :            : 
     247                 :          0 :         _cleanup_free_ char *p = NULL;
     248                 :            :         va_list ap;
     249                 :            :         int r;
     250                 :            : 
     251                 :          0 :         va_start(ap, format);
     252                 :          0 :         r = vasprintf(&p, format, ap);
     253                 :          0 :         va_end(ap);
     254                 :            : 
     255         [ #  # ]:          0 :         if (r < 0)
     256                 :          0 :                 return -ENOMEM;
     257                 :            : 
     258                 :          0 :         return write_string_file(fn, p, flags);
     259                 :            : }
     260                 :            : 
     261                 :       9756 : int read_one_line_file(const char *fn, char **line) {
     262                 :       9756 :         _cleanup_fclose_ FILE *f = NULL;
     263                 :            :         int r;
     264                 :            : 
     265         [ -  + ]:       9756 :         assert(fn);
     266         [ -  + ]:       9756 :         assert(line);
     267                 :            : 
     268                 :       9756 :         r = fopen_unlocked(fn, "re", &f);
     269         [ +  + ]:       9756 :         if (r < 0)
     270                 :       1658 :                 return r;
     271                 :            : 
     272                 :       8098 :         return read_line(f, LONG_LINE_MAX, line);
     273                 :            : }
     274                 :            : 
     275                 :         16 : int verify_file(const char *fn, const char *blob, bool accept_extra_nl) {
     276                 :         16 :         _cleanup_fclose_ FILE *f = NULL;
     277                 :         16 :         _cleanup_free_ char *buf = NULL;
     278                 :            :         size_t l, k;
     279                 :            :         int r;
     280                 :            : 
     281         [ -  + ]:         16 :         assert(fn);
     282         [ -  + ]:         16 :         assert(blob);
     283                 :            : 
     284                 :         16 :         l = strlen(blob);
     285                 :            : 
     286   [ +  +  +  + ]:         16 :         if (accept_extra_nl && endswith(blob, "\n"))
     287                 :          4 :                 accept_extra_nl = false;
     288                 :            : 
     289                 :         16 :         buf = malloc(l + accept_extra_nl + 1);
     290         [ -  + ]:         16 :         if (!buf)
     291                 :          0 :                 return -ENOMEM;
     292                 :            : 
     293                 :         16 :         r = fopen_unlocked(fn, "re", &f);
     294         [ -  + ]:         16 :         if (r < 0)
     295                 :          0 :                 return r;
     296                 :            : 
     297                 :            :         /* We try to read one byte more than we need, so that we know whether we hit eof */
     298                 :         16 :         errno = 0;
     299                 :         16 :         k = fread(buf, 1, l + accept_extra_nl + 1, f);
     300         [ -  + ]:         16 :         if (ferror(f))
     301                 :          0 :                 return errno_or_else(EIO);
     302                 :            : 
     303   [ +  +  +  + ]:         16 :         if (k != l && k != l + accept_extra_nl)
     304                 :          4 :                 return 0;
     305         [ -  + ]:         12 :         if (memcmp(buf, blob, l) != 0)
     306                 :          0 :                 return 0;
     307   [ +  +  -  + ]:         12 :         if (k > l && buf[l] != '\n')
     308                 :          0 :                 return 0;
     309                 :            : 
     310                 :         12 :         return 1;
     311                 :            : }
     312                 :            : 
     313                 :      32772 : int read_full_stream_full(
     314                 :            :                 FILE *f,
     315                 :            :                 const char *filename,
     316                 :            :                 ReadFullFileFlags flags,
     317                 :            :                 char **ret_contents,
     318                 :            :                 size_t *ret_size) {
     319                 :            : 
     320                 :      32772 :         _cleanup_free_ char *buf = NULL;
     321                 :            :         struct stat st;
     322                 :            :         size_t n, n_next, l;
     323                 :            :         int fd, r;
     324                 :            : 
     325         [ -  + ]:      32772 :         assert(f);
     326         [ -  + ]:      32772 :         assert(ret_contents);
     327         [ -  + ]:      32772 :         assert(!FLAGS_SET(flags, READ_FULL_FILE_UNBASE64 | READ_FULL_FILE_UNHEX));
     328   [ -  +  #  # ]:      32772 :         assert(!(flags & (READ_FULL_FILE_UNBASE64 | READ_FULL_FILE_UNHEX)) || ret_size);
     329                 :            : 
     330                 :      32772 :         n_next = LINE_MAX; /* Start size */
     331                 :            : 
     332                 :      32772 :         fd = fileno(f);
     333         [ +  + ]:      32772 :         if (fd >= 0) { /* If the FILE* object is backed by an fd (as opposed to memory or such, see fmemopen(), let's
     334                 :            :                         * optimize our buffering) */
     335                 :            : 
     336         [ -  + ]:      32768 :                 if (fstat(fd, &st) < 0)
     337                 :          0 :                         return -errno;
     338                 :            : 
     339         [ +  - ]:      32768 :                 if (S_ISREG(st.st_mode)) {
     340                 :            : 
     341                 :            :                         /* Safety check */
     342         [ -  + ]:      32768 :                         if (st.st_size > READ_FULL_BYTES_MAX)
     343                 :          0 :                                 return -E2BIG;
     344                 :            : 
     345                 :            :                         /* Start with the right file size, but be prepared for files from /proc which generally report a file
     346                 :            :                          * size of 0. Note that we increase the size to read here by one, so that the first read attempt
     347                 :            :                          * already makes us notice the EOF. */
     348         [ +  + ]:      32768 :                         if (st.st_size > 0)
     349                 :      30648 :                                 n_next = st.st_size + 1;
     350                 :            : 
     351         [ -  + ]:      32768 :                         if (flags & READ_FULL_FILE_SECURE)
     352                 :          0 :                                 (void) warn_file_is_world_accessible(filename, &st, NULL, 0);
     353                 :            :                 }
     354                 :            :         }
     355                 :            : 
     356                 :      32772 :         n = l = 0;
     357                 :          0 :         for (;;) {
     358                 :            :                 char *t;
     359                 :            :                 size_t k;
     360                 :            : 
     361         [ -  + ]:      32772 :                 if (flags & READ_FULL_FILE_SECURE) {
     362                 :          0 :                         t = malloc(n_next + 1);
     363         [ #  # ]:          0 :                         if (!t) {
     364                 :          0 :                                 r = -ENOMEM;
     365                 :          0 :                                 goto finalize;
     366                 :            :                         }
     367                 :          0 :                         memcpy_safe(t, buf, n);
     368                 :          0 :                         explicit_bzero_safe(buf, n);
     369                 :          0 :                         buf = mfree(buf);
     370                 :            :                 } else {
     371                 :      32772 :                         t = realloc(buf, n_next + 1);
     372         [ -  + ]:      32772 :                         if (!t)
     373                 :          0 :                                 return -ENOMEM;
     374                 :            :                 }
     375                 :            : 
     376                 :      32772 :                 buf = t;
     377                 :      32772 :                 n = n_next;
     378                 :            : 
     379                 :      32772 :                 errno = 0;
     380                 :      32772 :                 k = fread(buf + l, 1, n - l, f);
     381         [ +  + ]:      32772 :                 if (k > 0)
     382                 :      23808 :                         l += k;
     383                 :            : 
     384         [ +  + ]:      32772 :                 if (ferror(f)) {
     385                 :         16 :                         r = errno_or_else(EIO);
     386                 :         16 :                         goto finalize;
     387                 :            :                 }
     388                 :            : 
     389         [ +  - ]:      32756 :                 if (feof(f))
     390                 :      32756 :                         break;
     391                 :            : 
     392                 :            :                 /* We aren't expecting fread() to return a short read outside
     393                 :            :                  * of (error && eof), assert buffer is full and enlarge buffer.
     394                 :            :                  */
     395         [ #  # ]:          0 :                 assert(l == n);
     396                 :            : 
     397                 :            :                 /* Safety check */
     398         [ #  # ]:          0 :                 if (n >= READ_FULL_BYTES_MAX) {
     399                 :          0 :                         r = -E2BIG;
     400                 :          0 :                         goto finalize;
     401                 :            :                 }
     402                 :            : 
     403                 :          0 :                 n_next = MIN(n * 2, READ_FULL_BYTES_MAX);
     404                 :            :         }
     405                 :            : 
     406         [ -  + ]:      32756 :         if (flags & (READ_FULL_FILE_UNBASE64 | READ_FULL_FILE_UNHEX)) {
     407                 :          0 :                 buf[l++] = 0;
     408         [ #  # ]:          0 :                 if (flags & READ_FULL_FILE_UNBASE64)
     409                 :          0 :                         r = unbase64mem_full(buf, l, flags & READ_FULL_FILE_SECURE, (void **) ret_contents, ret_size);
     410                 :            :                 else
     411                 :          0 :                         r = unhexmem_full(buf, l, flags & READ_FULL_FILE_SECURE, (void **) ret_contents, ret_size);
     412                 :          0 :                 goto finalize;
     413                 :            :         }
     414                 :            : 
     415         [ +  + ]:      32756 :         if (!ret_size) {
     416                 :            :                 /* Safety check: if the caller doesn't want to know the size of what we just read it will rely on the
     417                 :            :                  * trailing NUL byte. But if there's an embedded NUL byte, then we should refuse operation as otherwise
     418                 :            :                  * there'd be ambiguity about what we just read. */
     419                 :            : 
     420         [ -  + ]:        368 :                 if (memchr(buf, 0, l)) {
     421                 :          0 :                         r = -EBADMSG;
     422                 :          0 :                         goto finalize;
     423                 :            :                 }
     424                 :            :         }
     425                 :            : 
     426                 :      32756 :         buf[l] = 0;
     427                 :      32756 :         *ret_contents = TAKE_PTR(buf);
     428                 :            : 
     429         [ +  + ]:      32756 :         if (ret_size)
     430                 :      32388 :                 *ret_size = l;
     431                 :            : 
     432                 :      32756 :         return 0;
     433                 :            : 
     434                 :         16 : finalize:
     435         [ -  + ]:         16 :         if (flags & READ_FULL_FILE_SECURE)
     436                 :          0 :                 explicit_bzero_safe(buf, n);
     437                 :            : 
     438                 :         16 :         return r;
     439                 :            : }
     440                 :            : 
     441                 :      59068 : int read_full_file_full(const char *filename, ReadFullFileFlags flags, char **contents, size_t *size) {
     442                 :      59068 :         _cleanup_fclose_ FILE *f = NULL;
     443                 :            :         int r;
     444                 :            : 
     445         [ -  + ]:      59068 :         assert(filename);
     446         [ -  + ]:      59068 :         assert(contents);
     447                 :            : 
     448                 :      59068 :         r = fopen_unlocked(filename, "re", &f);
     449         [ +  + ]:      59068 :         if (r < 0)
     450                 :      26320 :                 return r;
     451                 :            : 
     452                 :      32748 :         return read_full_stream_full(f, filename, flags, contents, size);
     453                 :            : }
     454                 :            : 
     455                 :         12 : int executable_is_script(const char *path, char **interpreter) {
     456                 :         12 :         _cleanup_free_ char *line = NULL;
     457                 :            :         size_t len;
     458                 :            :         char *ans;
     459                 :            :         int r;
     460                 :            : 
     461         [ -  + ]:         12 :         assert(path);
     462                 :            : 
     463                 :         12 :         r = read_one_line_file(path, &line);
     464         [ -  + ]:         12 :         if (r == -ENOBUFS) /* First line overly long? if so, then it's not a script */
     465                 :          0 :                 return 0;
     466         [ -  + ]:         12 :         if (r < 0)
     467                 :          0 :                 return r;
     468                 :            : 
     469         [ +  + ]:         12 :         if (!startswith(line, "#!"))
     470                 :          4 :                 return 0;
     471                 :            : 
     472                 :          8 :         ans = strstrip(line + 2);
     473                 :          8 :         len = strcspn(ans, " \t");
     474                 :            : 
     475         [ -  + ]:          8 :         if (len == 0)
     476                 :          0 :                 return 0;
     477                 :            : 
     478                 :          8 :         ans = strndup(ans, len);
     479         [ -  + ]:          8 :         if (!ans)
     480                 :          0 :                 return -ENOMEM;
     481                 :            : 
     482                 :          8 :         *interpreter = ans;
     483                 :          8 :         return 1;
     484                 :            : }
     485                 :            : 
     486                 :            : /**
     487                 :            :  * Retrieve one field from a file like /proc/self/status.  pattern
     488                 :            :  * should not include whitespace or the delimiter (':'). pattern matches only
     489                 :            :  * the beginning of a line. Whitespace before ':' is skipped. Whitespace and
     490                 :            :  * zeros after the ':' will be skipped. field must be freed afterwards.
     491                 :            :  * terminator specifies the terminating characters of the field value (not
     492                 :            :  * included in the value).
     493                 :            :  */
     494                 :         24 : int get_proc_field(const char *filename, const char *pattern, const char *terminator, char **field) {
     495                 :         24 :         _cleanup_free_ char *status = NULL;
     496                 :            :         char *t, *f;
     497                 :            :         size_t len;
     498                 :            :         int r;
     499                 :            : 
     500         [ -  + ]:         24 :         assert(terminator);
     501         [ -  + ]:         24 :         assert(filename);
     502         [ -  + ]:         24 :         assert(pattern);
     503         [ -  + ]:         24 :         assert(field);
     504                 :            : 
     505                 :         24 :         r = read_full_file(filename, &status, NULL);
     506         [ -  + ]:         24 :         if (r < 0)
     507                 :          0 :                 return r;
     508                 :            : 
     509                 :         24 :         t = status;
     510                 :            : 
     511                 :            :         do {
     512                 :            :                 bool pattern_ok;
     513                 :            : 
     514                 :            :                 do {
     515                 :         24 :                         t = strstr(t, pattern);
     516         [ +  + ]:         24 :                         if (!t)
     517                 :          4 :                                 return -ENOENT;
     518                 :            : 
     519                 :            :                         /* Check that pattern occurs in beginning of line. */
     520   [ +  +  +  - ]:         20 :                         pattern_ok = (t == status || t[-1] == '\n');
     521                 :            : 
     522                 :         20 :                         t += strlen(pattern);
     523                 :            : 
     524         [ -  + ]:         20 :                 } while (!pattern_ok);
     525                 :            : 
     526                 :         20 :                 t += strspn(t, " \t");
     527         [ -  + ]:         20 :                 if (!*t)
     528                 :          0 :                         return -ENOENT;
     529                 :            : 
     530         [ -  + ]:         20 :         } while (*t != ':');
     531                 :            : 
     532                 :         20 :         t++;
     533                 :            : 
     534         [ +  - ]:         20 :         if (*t) {
     535                 :         20 :                 t += strspn(t, " \t");
     536                 :            : 
     537                 :            :                 /* Also skip zeros, because when this is used for
     538                 :            :                  * capabilities, we don't want the zeros. This way the
     539                 :            :                  * same capability set always maps to the same string,
     540                 :            :                  * irrespective of the total capability set size. For
     541                 :            :                  * other numbers it shouldn't matter. */
     542                 :         20 :                 t += strspn(t, "0");
     543                 :            :                 /* Back off one char if there's nothing but whitespace
     544                 :            :                    and zeros */
     545   [ +  -  +  + ]:         20 :                 if (!*t || isspace(*t))
     546                 :          8 :                         t--;
     547                 :            :         }
     548                 :            : 
     549                 :         20 :         len = strcspn(t, terminator);
     550                 :            : 
     551                 :         20 :         f = strndup(t, len);
     552         [ -  + ]:         20 :         if (!f)
     553                 :          0 :                 return -ENOMEM;
     554                 :            : 
     555                 :         20 :         *field = f;
     556                 :         20 :         return 0;
     557                 :            : }
     558                 :            : 
     559                 :          0 : DIR *xopendirat(int fd, const char *name, int flags) {
     560                 :            :         int nfd;
     561                 :            :         DIR *d;
     562                 :            : 
     563         [ #  # ]:          0 :         assert(!(flags & O_CREAT));
     564                 :            : 
     565                 :          0 :         nfd = openat(fd, name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|flags, 0);
     566         [ #  # ]:          0 :         if (nfd < 0)
     567                 :          0 :                 return NULL;
     568                 :            : 
     569                 :          0 :         d = fdopendir(nfd);
     570         [ #  # ]:          0 :         if (!d) {
     571                 :          0 :                 safe_close(nfd);
     572                 :          0 :                 return NULL;
     573                 :            :         }
     574                 :            : 
     575                 :          0 :         return d;
     576                 :            : }
     577                 :            : 
     578                 :         28 : static int search_and_fopen_internal(const char *path, const char *mode, const char *root, char **search, FILE **_f) {
     579                 :            :         char **i;
     580                 :            : 
     581         [ -  + ]:         28 :         assert(path);
     582         [ -  + ]:         28 :         assert(mode);
     583         [ -  + ]:         28 :         assert(_f);
     584                 :            : 
     585         [ -  + ]:         28 :         if (!path_strv_resolve_uniq(search, root))
     586                 :          0 :                 return -ENOMEM;
     587                 :            : 
     588   [ +  -  +  + ]:         72 :         STRV_FOREACH(i, search) {
     589         [ +  + ]:         56 :                 _cleanup_free_ char *p = NULL;
     590                 :            :                 FILE *f;
     591                 :            : 
     592                 :         56 :                 p = path_join(root, *i, path);
     593         [ -  + ]:         56 :                 if (!p)
     594                 :          0 :                         return -ENOMEM;
     595                 :            : 
     596                 :         56 :                 f = fopen(p, mode);
     597         [ +  + ]:         56 :                 if (f) {
     598                 :         12 :                         *_f = f;
     599                 :         12 :                         return 0;
     600                 :            :                 }
     601                 :            : 
     602         [ -  + ]:         44 :                 if (errno != ENOENT)
     603                 :          0 :                         return -errno;
     604                 :            :         }
     605                 :            : 
     606                 :         16 :         return -ENOENT;
     607                 :            : }
     608                 :            : 
     609                 :         24 : int search_and_fopen(const char *path, const char *mode, const char *root, const char **search, FILE **_f) {
     610                 :         24 :         _cleanup_strv_free_ char **copy = NULL;
     611                 :            : 
     612         [ -  + ]:         24 :         assert(path);
     613         [ -  + ]:         24 :         assert(mode);
     614         [ -  + ]:         24 :         assert(_f);
     615                 :            : 
     616         [ +  + ]:         24 :         if (path_is_absolute(path)) {
     617                 :            :                 FILE *f;
     618                 :            : 
     619                 :          8 :                 f = fopen(path, mode);
     620         [ +  + ]:          8 :                 if (f) {
     621                 :          4 :                         *_f = f;
     622                 :          4 :                         return 0;
     623                 :            :                 }
     624                 :            : 
     625                 :          4 :                 return -errno;
     626                 :            :         }
     627                 :            : 
     628                 :         16 :         copy = strv_copy((char**) search);
     629         [ -  + ]:         16 :         if (!copy)
     630                 :          0 :                 return -ENOMEM;
     631                 :            : 
     632                 :         16 :         return search_and_fopen_internal(path, mode, root, copy, _f);
     633                 :            : }
     634                 :            : 
     635                 :         20 : int search_and_fopen_nulstr(const char *path, const char *mode, const char *root, const char *search, FILE **_f) {
     636                 :         20 :         _cleanup_strv_free_ char **s = NULL;
     637                 :            : 
     638         [ +  + ]:         20 :         if (path_is_absolute(path)) {
     639                 :            :                 FILE *f;
     640                 :            : 
     641                 :          8 :                 f = fopen(path, mode);
     642         [ +  + ]:          8 :                 if (f) {
     643                 :          4 :                         *_f = f;
     644                 :          4 :                         return 0;
     645                 :            :                 }
     646                 :            : 
     647                 :          4 :                 return -errno;
     648                 :            :         }
     649                 :            : 
     650                 :         12 :         s = strv_split_nulstr(search);
     651         [ -  + ]:         12 :         if (!s)
     652                 :          0 :                 return -ENOMEM;
     653                 :            : 
     654                 :         12 :         return search_and_fopen_internal(path, mode, root, s, _f);
     655                 :            : }
     656                 :            : 
     657                 :       2784 : int fflush_and_check(FILE *f) {
     658         [ -  + ]:       2784 :         assert(f);
     659                 :            : 
     660                 :       2784 :         errno = 0;
     661                 :       2784 :         fflush(f);
     662                 :            : 
     663         [ -  + ]:       2784 :         if (ferror(f))
     664                 :          0 :                 return errno_or_else(EIO);
     665                 :            : 
     666                 :       2784 :         return 0;
     667                 :            : }
     668                 :            : 
     669                 :          0 : int fflush_sync_and_check(FILE *f) {
     670                 :            :         int r;
     671                 :            : 
     672         [ #  # ]:          0 :         assert(f);
     673                 :            : 
     674                 :          0 :         r = fflush_and_check(f);
     675         [ #  # ]:          0 :         if (r < 0)
     676                 :          0 :                 return r;
     677                 :            : 
     678         [ #  # ]:          0 :         if (fsync(fileno(f)) < 0)
     679                 :          0 :                 return -errno;
     680                 :            : 
     681                 :          0 :         r = fsync_directory_of_file(fileno(f));
     682         [ #  # ]:          0 :         if (r < 0)
     683                 :          0 :                 return r;
     684                 :            : 
     685                 :          0 :         return 0;
     686                 :            : }
     687                 :            : 
     688                 :          0 : int write_timestamp_file_atomic(const char *fn, usec_t n) {
     689                 :            :         char ln[DECIMAL_STR_MAX(n)+2];
     690                 :            : 
     691                 :            :         /* Creates a "timestamp" file, that contains nothing but a
     692                 :            :          * usec_t timestamp, formatted in ASCII. */
     693                 :            : 
     694   [ #  #  #  # ]:          0 :         if (n <= 0 || n >= USEC_INFINITY)
     695                 :          0 :                 return -ERANGE;
     696                 :            : 
     697         [ #  # ]:          0 :         xsprintf(ln, USEC_FMT "\n", n);
     698                 :            : 
     699                 :          0 :         return write_string_file(fn, ln, WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC);
     700                 :            : }
     701                 :            : 
     702                 :          0 : int read_timestamp_file(const char *fn, usec_t *ret) {
     703                 :          0 :         _cleanup_free_ char *ln = NULL;
     704                 :            :         uint64_t t;
     705                 :            :         int r;
     706                 :            : 
     707                 :          0 :         r = read_one_line_file(fn, &ln);
     708         [ #  # ]:          0 :         if (r < 0)
     709                 :          0 :                 return r;
     710                 :            : 
     711                 :          0 :         r = safe_atou64(ln, &t);
     712         [ #  # ]:          0 :         if (r < 0)
     713                 :          0 :                 return r;
     714                 :            : 
     715   [ #  #  #  # ]:          0 :         if (t <= 0 || t >= (uint64_t) USEC_INFINITY)
     716                 :          0 :                 return -ERANGE;
     717                 :            : 
     718                 :          0 :         *ret = (usec_t) t;
     719                 :          0 :         return 0;
     720                 :            : }
     721                 :            : 
     722                 :         44 : int fputs_with_space(FILE *f, const char *s, const char *separator, bool *space) {
     723                 :            :         int r;
     724                 :            : 
     725         [ -  + ]:         44 :         assert(s);
     726                 :            : 
     727                 :            :         /* Outputs the specified string with fputs(), but optionally prefixes it with a separator. The *space parameter
     728                 :            :          * when specified shall initially point to a boolean variable initialized to false. It is set to true after the
     729                 :            :          * first invocation. This call is supposed to be use in loops, where a separator shall be inserted between each
     730                 :            :          * element, but not before the first one. */
     731                 :            : 
     732         [ -  + ]:         44 :         if (!f)
     733                 :          0 :                 f = stdout;
     734                 :            : 
     735         [ +  - ]:         44 :         if (space) {
     736         [ +  - ]:         44 :                 if (!separator)
     737                 :         44 :                         separator = " ";
     738                 :            : 
     739         [ +  + ]:         44 :                 if (*space) {
     740                 :         32 :                         r = fputs(separator, f);
     741         [ -  + ]:         32 :                         if (r < 0)
     742                 :          0 :                                 return r;
     743                 :            :                 }
     744                 :            : 
     745                 :         44 :                 *space = true;
     746                 :            :         }
     747                 :            : 
     748                 :         44 :         return fputs(s, f);
     749                 :            : }
     750                 :            : 
     751                 :            : /* A bitmask of the EOL markers we know */
     752                 :            : typedef enum EndOfLineMarker {
     753                 :            :         EOL_NONE     = 0,
     754                 :            :         EOL_ZERO     = 1 << 0,  /* \0 (aka NUL) */
     755                 :            :         EOL_TEN      = 1 << 1,  /* \n (aka NL, aka LF)  */
     756                 :            :         EOL_THIRTEEN = 1 << 2,  /* \r (aka CR)  */
     757                 :            : } EndOfLineMarker;
     758                 :            : 
     759                 :   42666611 : static EndOfLineMarker categorize_eol(char c, ReadLineFlags flags) {
     760                 :            : 
     761   [ +  +  +  + ]:   42666611 :         if (!IN_SET(flags, READ_LINE_ONLY_NUL)) {
     762         [ +  + ]:   42666295 :                 if (c == '\n')
     763                 :    1644870 :                         return EOL_TEN;
     764         [ +  + ]:   41021425 :                 if (c == '\r')
     765                 :         64 :                         return EOL_THIRTEEN;
     766                 :            :         }
     767                 :            : 
     768         [ +  + ]:   41021677 :         if (c == '\0')
     769                 :        116 :                 return EOL_ZERO;
     770                 :            : 
     771                 :   41021561 :         return EOL_NONE;
     772                 :            : }
     773                 :            : 
     774         [ +  - ]:    1286610 : DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, funlockfile);
     775                 :            : 
     776                 :    1286610 : int read_line_full(FILE *f, size_t limit, ReadLineFlags flags, char **ret) {
     777                 :    1286610 :         size_t n = 0, allocated = 0, count = 0;
     778                 :    1286610 :         _cleanup_free_ char *buffer = NULL;
     779                 :    1286610 :         int r, tty = -1;
     780                 :            : 
     781         [ -  + ]:    1286610 :         assert(f);
     782                 :            : 
     783                 :            :         /* Something like a bounded version of getline().
     784                 :            :          *
     785                 :            :          * Considers EOF, \n, \r and \0 end of line delimiters (or combinations of these), and does not include these
     786                 :            :          * delimiters in the string returned. Specifically, recognizes the following combinations of markers as line
     787                 :            :          * endings:
     788                 :            :          *
     789                 :            :          *     • \n        (UNIX)
     790                 :            :          *     • \r        (old MacOS)
     791                 :            :          *     • \0        (C strings)
     792                 :            :          *     • \n\0
     793                 :            :          *     • \r\0
     794                 :            :          *     • \r\n      (Windows)
     795                 :            :          *     • \n\r
     796                 :            :          *     • \r\n\0
     797                 :            :          *     • \n\r\0
     798                 :            :          *
     799                 :            :          * Returns the number of bytes read from the files (i.e. including delimiters — this hence usually differs from
     800                 :            :          * the number of characters in the returned string). When EOF is hit, 0 is returned.
     801                 :            :          *
     802                 :            :          * The input parameter limit is the maximum numbers of characters in the returned string, i.e. excluding
     803                 :            :          * delimiters. If the limit is hit we fail and return -ENOBUFS.
     804                 :            :          *
     805                 :            :          * If a line shall be skipped ret may be initialized as NULL. */
     806                 :            : 
     807         [ +  + ]:    1286610 :         if (ret) {
     808         [ -  + ]:    1286478 :                 if (!GREEDY_REALLOC(buffer, allocated, 1))
     809                 :          0 :                         return -ENOMEM;
     810                 :            :         }
     811                 :            : 
     812                 :            :         {
     813         [ +  + ]:    1286610 :                 _unused_ _cleanup_(funlockfilep) FILE *flocked = f;
     814                 :    1286610 :                 EndOfLineMarker previous_eol = EOL_NONE;
     815                 :    1286610 :                 flockfile(f);
     816                 :            : 
     817                 :   41405929 :                 for (;;) {
     818                 :            :                         EndOfLineMarker eol;
     819                 :            :                         char c;
     820                 :            : 
     821         [ +  + ]:   42692539 :                         if (n >= limit)
     822                 :         12 :                                 return -ENOBUFS;
     823                 :            : 
     824         [ -  + ]:   42692527 :                         if (count >= INT_MAX) /* We couldn't return the counter anymore as "int", hence refuse this */
     825                 :          0 :                                 return -ENOBUFS;
     826                 :            : 
     827                 :   42692527 :                         r = safe_fgetc(f, &c);
     828         [ -  + ]:   42692527 :                         if (r < 0)
     829                 :          0 :                                 return r;
     830         [ +  + ]:   42692527 :                         if (r == 0) /* EOF is definitely EOL */
     831                 :    1286598 :                                 break;
     832                 :            : 
     833                 :   42666611 :                         eol = categorize_eol(c, flags);
     834                 :            : 
     835   [ +  +  +  + ]:   42666611 :                         if (FLAGS_SET(previous_eol, EOL_ZERO) ||
     836   [ +  +  +  + ]:   42666547 :                             (eol == EOL_NONE && previous_eol != EOL_NONE) ||
     837         [ +  + ]:    1645030 :                             (eol != EOL_NONE && (previous_eol & eol) != 0)) {
     838                 :            :                                 /* Previous char was a NUL? This is not an EOL, but the previous char was? This type of
     839                 :            :                                  * EOL marker has been seen right before?  In either of these three cases we are
     840                 :            :                                  * done. But first, let's put this character back in the queue. (Note that we have to
     841                 :            :                                  * cast this to (unsigned char) here as ungetc() expects a positive 'int', and if we
     842                 :            :                                  * are on an architecture where 'char' equals 'signed char' we need to ensure we don't
     843                 :            :                                  * pass a negative value here. That said, to complicate things further ungetc() is
     844                 :            :                                  * actually happy with most negative characters and implicitly casts them back to
     845                 :            :                                  * positive ones as needed, except for \xff (aka -1, aka EOF), which it refuses. What a
     846                 :            :                                  * godawful API!) */
     847         [ -  + ]:    1260682 :                                 assert_se(ungetc((unsigned char) c, f) != EOF);
     848                 :    1260682 :                                 break;
     849                 :            :                         }
     850                 :            : 
     851                 :   41405929 :                         count++;
     852                 :            : 
     853         [ +  + ]:   41405929 :                         if (eol != EOL_NONE) {
     854                 :            :                                 /* If we are on a tty, we can't wait for more input. But we expect only
     855                 :            :                                  * \n as the single EOL marker, so there is no need to wait. We check
     856                 :            :                                  * this condition last to avoid isatty() check if not necessary. */
     857                 :            : 
     858         [ +  + ]:    1282162 :                                 if (tty < 0)
     859                 :    1282058 :                                         tty = isatty(fileno(f));
     860         [ -  + ]:    1282162 :                                 if (tty > 0)
     861                 :          0 :                                         break;
     862                 :            :                         }
     863                 :            : 
     864         [ +  + ]:   41405929 :                         if (eol != EOL_NONE) {
     865                 :    1282162 :                                 previous_eol |= eol;
     866                 :    1282162 :                                 continue;
     867                 :            :                         }
     868                 :            : 
     869         [ +  + ]:   40123767 :                         if (ret) {
     870         [ -  + ]:   40123327 :                                 if (!GREEDY_REALLOC(buffer, allocated, n + 2))
     871                 :          0 :                                         return -ENOMEM;
     872                 :            : 
     873                 :   40123327 :                                 buffer[n] = c;
     874                 :            :                         }
     875                 :            : 
     876                 :   40123767 :                         n++;
     877                 :            :                 }
     878                 :            :         }
     879                 :            : 
     880         [ +  + ]:    1286598 :         if (ret) {
     881                 :    1286466 :                 buffer[n] = 0;
     882                 :            : 
     883                 :    1286466 :                 *ret = TAKE_PTR(buffer);
     884                 :            :         }
     885                 :            : 
     886                 :    1286598 :         return (int) count;
     887                 :            : }
     888                 :            : 
     889                 :   42721709 : int safe_fgetc(FILE *f, char *ret) {
     890                 :            :         int k;
     891                 :            : 
     892         [ -  + ]:   42721709 :         assert(f);
     893                 :            : 
     894                 :            :         /* A safer version of plain fgetc(): let's propagate the error that happened while reading as such, and
     895                 :            :          * separate the EOF condition from the byte read, to avoid those confusion signed/unsigned issues fgetc()
     896                 :            :          * has. */
     897                 :            : 
     898                 :   42721709 :         errno = 0;
     899                 :   42721709 :         k = fgetc(f);
     900         [ +  + ]:   42721709 :         if (k == EOF) {
     901         [ -  + ]:      25924 :                 if (ferror(f))
     902                 :          0 :                         return errno_or_else(EIO);
     903                 :            : 
     904         [ +  - ]:      25924 :                 if (ret)
     905                 :      25924 :                         *ret = 0;
     906                 :            : 
     907                 :      25924 :                 return 0;
     908                 :            :         }
     909                 :            : 
     910         [ +  - ]:   42695785 :         if (ret)
     911                 :   42695785 :                 *ret = k;
     912                 :            : 
     913                 :   42695785 :         return 1;
     914                 :            : }
     915                 :            : 
     916                 :          0 : int warn_file_is_world_accessible(const char *filename, struct stat *st, const char *unit, unsigned line) {
     917                 :            :         struct stat _st;
     918                 :            : 
     919         [ #  # ]:          0 :         if (!filename)
     920                 :          0 :                 return 0;
     921                 :            : 
     922         [ #  # ]:          0 :         if (!st) {
     923         [ #  # ]:          0 :                 if (stat(filename, &_st) < 0)
     924                 :          0 :                         return -errno;
     925                 :          0 :                 st = &_st;
     926                 :            :         }
     927                 :            : 
     928         [ #  # ]:          0 :         if ((st->st_mode & S_IRWXO) == 0)
     929                 :          0 :                 return 0;
     930                 :            : 
     931         [ #  # ]:          0 :         if (unit)
     932         [ #  # ]:          0 :                 log_syntax(unit, LOG_WARNING, filename, line, 0,
     933                 :            :                            "%s has %04o mode that is too permissive, please adjust the access mode.",
     934                 :            :                            filename, st->st_mode & 07777);
     935                 :            :         else
     936         [ #  # ]:          0 :                 log_warning("%s has %04o mode that is too permissive, please adjust the access mode.",
     937                 :            :                             filename, st->st_mode & 07777);
     938                 :          0 :         return 0;
     939                 :            : }

Generated by: LCOV version 1.14