LCOV - code coverage report
Current view: top level - basic - fileio.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 309 463 66.7 %
Date: 2019-08-22 15:41:25 Functions: 21 28 75.0 %

          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       20594 : int fopen_unlocked(const char *path, const char *options, FILE **ret) {
      34       20594 :         assert(ret);
      35             : 
      36       20594 :         FILE *f = fopen(path, options);
      37       20594 :         if (!f)
      38        7470 :                 return -errno;
      39             : 
      40       13124 :         (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
      41             : 
      42       13124 :         *ret = f;
      43       13124 :         return 0;
      44             : }
      45             : 
      46           6 : int fdopen_unlocked(int fd, const char *options, FILE **ret) {
      47           6 :         assert(ret);
      48             : 
      49           6 :         FILE *f = fdopen(fd, options);
      50           6 :         if (!f)
      51           0 :                 return -errno;
      52             : 
      53           6 :         (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
      54             : 
      55           6 :         *ret = f;
      56           6 :         return 0;
      57             : }
      58             : 
      59         546 : FILE* open_memstream_unlocked(char **ptr, size_t *sizeloc) {
      60         546 :         FILE *f = open_memstream(ptr, sizeloc);
      61         546 :         if (!f)
      62           0 :                 return NULL;
      63             : 
      64         546 :         (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
      65             : 
      66         546 :         return f;
      67             : }
      68             : 
      69          14 : FILE* fmemopen_unlocked(void *buf, size_t size, const char *mode) {
      70          14 :         FILE *f = fmemopen(buf, size, mode);
      71          14 :         if (!f)
      72           0 :                 return NULL;
      73             : 
      74          14 :         (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
      75             : 
      76          14 :         return f;
      77             : }
      78             : 
      79         118 : 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         118 :         assert(f);
      89         118 :         assert(line);
      90             : 
      91         118 :         if (ferror(f))
      92           0 :                 return -EIO;
      93             : 
      94         118 :         needs_nl = !(flags & WRITE_STRING_FILE_AVOID_NEWLINE) && !endswith(line, "\n");
      95             : 
      96         118 :         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         118 :         if (fputs(line, f) == EOF)
     105           1 :                 return -errno;
     106             : 
     107         117 :         if (needs_nl)
     108          62 :                 if (fputc('\n', f) == EOF)
     109           0 :                         return -errno;
     110             : 
     111         117 :         if (flags & WRITE_STRING_FILE_SYNC)
     112           0 :                 r = fflush_sync_and_check(f);
     113             :         else
     114         117 :                 r = fflush_and_check(f);
     115         117 :         if (r < 0)
     116           0 :                 return r;
     117             : 
     118         117 :         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         117 :         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         106 : int write_string_file_ts(
     164             :                 const char *fn,
     165             :                 const char *line,
     166             :                 WriteStringFileFlags flags,
     167             :                 struct timespec *ts) {
     168             : 
     169         106 :         _cleanup_fclose_ FILE *f = NULL;
     170             :         int q, r;
     171             : 
     172         106 :         assert(fn);
     173         106 :         assert(line);
     174             : 
     175             :         /* We don't know how to verify whether the file contents was already on-disk. */
     176         106 :         assert(!((flags & WRITE_STRING_FILE_VERIFY_ON_FAILURE) && (flags & WRITE_STRING_FILE_SYNC)));
     177             : 
     178         106 :         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         106 :         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         106 :                 assert(!ts);
     194             : 
     195         106 :         if (flags & WRITE_STRING_FILE_CREATE) {
     196          89 :                 r = fopen_unlocked(fn, "we", &f);
     197          89 :                 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          17 :                 fd = open(fn, O_WRONLY|O_CLOEXEC|O_NOCTTY | ((flags & WRITE_STRING_FILE_NOFOLLOW) ? O_NOFOLLOW : 0));
     205          17 :                 if (fd < 0) {
     206          16 :                         r = -errno;
     207          16 :                         goto fail;
     208             :                 }
     209             : 
     210           1 :                 r = fdopen_unlocked(fd, "w", &f);
     211           1 :                 if (r < 0) {
     212           0 :                         safe_close(fd);
     213           0 :                         goto fail;
     214             :                 }
     215             :         }
     216             : 
     217          90 :         if (flags & WRITE_STRING_FILE_DISABLE_BUFFER)
     218           0 :                 setvbuf(f, NULL, _IONBF, 0);
     219             : 
     220          90 :         r = write_string_stream_ts(f, line, flags, ts);
     221          90 :         if (r < 0)
     222           0 :                 goto fail;
     223             : 
     224          90 :         return 0;
     225             : 
     226          16 : fail:
     227          16 :         if (!(flags & WRITE_STRING_FILE_VERIFY_ON_FAILURE))
     228          12 :                 return r;
     229             : 
     230           4 :         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           4 :         q = verify_file(fn, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE));
     236           4 :         if (q <= 0)
     237           1 :                 return r;
     238             : 
     239           3 :         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        2426 : int read_one_line_file(const char *fn, char **line) {
     262        2426 :         _cleanup_fclose_ FILE *f = NULL;
     263             :         int r;
     264             : 
     265        2426 :         assert(fn);
     266        2426 :         assert(line);
     267             : 
     268        2426 :         r = fopen_unlocked(fn, "re", &f);
     269        2426 :         if (r < 0)
     270         414 :                 return r;
     271             : 
     272        2012 :         return read_line(f, LONG_LINE_MAX, line);
     273             : }
     274             : 
     275           4 : int verify_file(const char *fn, const char *blob, bool accept_extra_nl) {
     276           4 :         _cleanup_fclose_ FILE *f = NULL;
     277           4 :         _cleanup_free_ char *buf = NULL;
     278             :         size_t l, k;
     279             :         int r;
     280             : 
     281           4 :         assert(fn);
     282           4 :         assert(blob);
     283             : 
     284           4 :         l = strlen(blob);
     285             : 
     286           4 :         if (accept_extra_nl && endswith(blob, "\n"))
     287           1 :                 accept_extra_nl = false;
     288             : 
     289           4 :         buf = malloc(l + accept_extra_nl + 1);
     290           4 :         if (!buf)
     291           0 :                 return -ENOMEM;
     292             : 
     293           4 :         r = fopen_unlocked(fn, "re", &f);
     294           4 :         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           4 :         errno = 0;
     299           4 :         k = fread(buf, 1, l + accept_extra_nl + 1, f);
     300           4 :         if (ferror(f))
     301           0 :                 return errno_or_else(EIO);
     302             : 
     303           4 :         if (k != l && k != l + accept_extra_nl)
     304           1 :                 return 0;
     305           3 :         if (memcmp(buf, blob, l) != 0)
     306           0 :                 return 0;
     307           3 :         if (k > l && buf[l] != '\n')
     308           0 :                 return 0;
     309             : 
     310           3 :         return 1;
     311             : }
     312             : 
     313        8332 : 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        8332 :         _cleanup_free_ char *buf = NULL;
     321             :         struct stat st;
     322             :         size_t n, n_next, l;
     323             :         int fd, r;
     324             : 
     325        8332 :         assert(f);
     326        8332 :         assert(ret_contents);
     327        8332 :         assert(!FLAGS_SET(flags, READ_FULL_FILE_UNBASE64 | READ_FULL_FILE_UNHEX));
     328        8332 :         assert(!(flags & (READ_FULL_FILE_UNBASE64 | READ_FULL_FILE_UNHEX)) || ret_size);
     329             : 
     330        8332 :         n_next = LINE_MAX; /* Start size */
     331             : 
     332        8332 :         fd = fileno(f);
     333        8332 :         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        8331 :                 if (fstat(fd, &st) < 0)
     337           0 :                         return -errno;
     338             : 
     339        8331 :                 if (S_ISREG(st.st_mode)) {
     340             : 
     341             :                         /* Safety check */
     342        8331 :                         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        8331 :                         if (st.st_size > 0)
     349        7783 :                                 n_next = st.st_size + 1;
     350             : 
     351        8331 :                         if (flags & READ_FULL_FILE_SECURE)
     352           0 :                                 (void) warn_file_is_world_accessible(filename, &st, NULL, 0);
     353             :                 }
     354             :         }
     355             : 
     356        8332 :         n = l = 0;
     357           0 :         for (;;) {
     358             :                 char *t;
     359             :                 size_t k;
     360             : 
     361        8332 :                 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        8332 :                         t = realloc(buf, n_next + 1);
     372        8332 :                         if (!t)
     373           0 :                                 return -ENOMEM;
     374             :                 }
     375             : 
     376        8332 :                 buf = t;
     377        8332 :                 n = n_next;
     378             : 
     379        8332 :                 errno = 0;
     380        8332 :                 k = fread(buf + l, 1, n - l, f);
     381        8332 :                 if (k > 0)
     382        6040 :                         l += k;
     383             : 
     384        8332 :                 if (ferror(f)) {
     385           3 :                         r = errno_or_else(EIO);
     386           3 :                         goto finalize;
     387             :                 }
     388             : 
     389        8329 :                 if (feof(f))
     390        8329 :                         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        8329 :         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        8329 :         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          92 :                 if (memchr(buf, 0, l)) {
     421           0 :                         r = -EBADMSG;
     422           0 :                         goto finalize;
     423             :                 }
     424             :         }
     425             : 
     426        8329 :         buf[l] = 0;
     427        8329 :         *ret_contents = TAKE_PTR(buf);
     428             : 
     429        8329 :         if (ret_size)
     430        8237 :                 *ret_size = l;
     431             : 
     432        8329 :         return 0;
     433             : 
     434           3 : finalize:
     435           3 :         if (flags & READ_FULL_FILE_SECURE)
     436           0 :                 explicit_bzero_safe(buf, n);
     437             : 
     438           3 :         return r;
     439             : }
     440             : 
     441       14987 : int read_full_file_full(const char *filename, ReadFullFileFlags flags, char **contents, size_t *size) {
     442       14987 :         _cleanup_fclose_ FILE *f = NULL;
     443             :         int r;
     444             : 
     445       14987 :         assert(filename);
     446       14987 :         assert(contents);
     447             : 
     448       14987 :         r = fopen_unlocked(filename, "re", &f);
     449       14987 :         if (r < 0)
     450        6661 :                 return r;
     451             : 
     452        8326 :         return read_full_stream_full(f, filename, flags, contents, size);
     453             : }
     454             : 
     455           3 : int executable_is_script(const char *path, char **interpreter) {
     456           3 :         _cleanup_free_ char *line = NULL;
     457             :         size_t len;
     458             :         char *ans;
     459             :         int r;
     460             : 
     461           3 :         assert(path);
     462             : 
     463           3 :         r = read_one_line_file(path, &line);
     464           3 :         if (r == -ENOBUFS) /* First line overly long? if so, then it's not a script */
     465           0 :                 return 0;
     466           3 :         if (r < 0)
     467           0 :                 return r;
     468             : 
     469           3 :         if (!startswith(line, "#!"))
     470           1 :                 return 0;
     471             : 
     472           2 :         ans = strstrip(line + 2);
     473           2 :         len = strcspn(ans, " \t");
     474             : 
     475           2 :         if (len == 0)
     476           0 :                 return 0;
     477             : 
     478           2 :         ans = strndup(ans, len);
     479           2 :         if (!ans)
     480           0 :                 return -ENOMEM;
     481             : 
     482           2 :         *interpreter = ans;
     483           2 :         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           6 : int get_proc_field(const char *filename, const char *pattern, const char *terminator, char **field) {
     495           6 :         _cleanup_free_ char *status = NULL;
     496             :         char *t, *f;
     497             :         size_t len;
     498             :         int r;
     499             : 
     500           6 :         assert(terminator);
     501           6 :         assert(filename);
     502           6 :         assert(pattern);
     503           6 :         assert(field);
     504             : 
     505           6 :         r = read_full_file(filename, &status, NULL);
     506           6 :         if (r < 0)
     507           0 :                 return r;
     508             : 
     509           6 :         t = status;
     510             : 
     511             :         do {
     512             :                 bool pattern_ok;
     513             : 
     514             :                 do {
     515           6 :                         t = strstr(t, pattern);
     516           6 :                         if (!t)
     517           1 :                                 return -ENOENT;
     518             : 
     519             :                         /* Check that pattern occurs in beginning of line. */
     520           5 :                         pattern_ok = (t == status || t[-1] == '\n');
     521             : 
     522           5 :                         t += strlen(pattern);
     523             : 
     524           5 :                 } while (!pattern_ok);
     525             : 
     526           5 :                 t += strspn(t, " \t");
     527           5 :                 if (!*t)
     528           0 :                         return -ENOENT;
     529             : 
     530           5 :         } while (*t != ':');
     531             : 
     532           5 :         t++;
     533             : 
     534           5 :         if (*t) {
     535           5 :                 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           5 :                 t += strspn(t, "0");
     543             :                 /* Back off one char if there's nothing but whitespace
     544             :                    and zeros */
     545           5 :                 if (!*t || isspace(*t))
     546           2 :                         t--;
     547             :         }
     548             : 
     549           5 :         len = strcspn(t, terminator);
     550             : 
     551           5 :         f = strndup(t, len);
     552           5 :         if (!f)
     553           0 :                 return -ENOMEM;
     554             : 
     555           5 :         *field = f;
     556           5 :         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           7 : static int search_and_fopen_internal(const char *path, const char *mode, const char *root, char **search, FILE **_f) {
     579             :         char **i;
     580             : 
     581           7 :         assert(path);
     582           7 :         assert(mode);
     583           7 :         assert(_f);
     584             : 
     585           7 :         if (!path_strv_resolve_uniq(search, root))
     586           0 :                 return -ENOMEM;
     587             : 
     588          18 :         STRV_FOREACH(i, search) {
     589          14 :                 _cleanup_free_ char *p = NULL;
     590             :                 FILE *f;
     591             : 
     592          14 :                 p = path_join(root, *i, path);
     593          14 :                 if (!p)
     594           0 :                         return -ENOMEM;
     595             : 
     596          14 :                 f = fopen(p, mode);
     597          14 :                 if (f) {
     598           3 :                         *_f = f;
     599           3 :                         return 0;
     600             :                 }
     601             : 
     602          11 :                 if (errno != ENOENT)
     603           0 :                         return -errno;
     604             :         }
     605             : 
     606           4 :         return -ENOENT;
     607             : }
     608             : 
     609           6 : int search_and_fopen(const char *path, const char *mode, const char *root, const char **search, FILE **_f) {
     610           6 :         _cleanup_strv_free_ char **copy = NULL;
     611             : 
     612           6 :         assert(path);
     613           6 :         assert(mode);
     614           6 :         assert(_f);
     615             : 
     616           6 :         if (path_is_absolute(path)) {
     617             :                 FILE *f;
     618             : 
     619           2 :                 f = fopen(path, mode);
     620           2 :                 if (f) {
     621           1 :                         *_f = f;
     622           1 :                         return 0;
     623             :                 }
     624             : 
     625           1 :                 return -errno;
     626             :         }
     627             : 
     628           4 :         copy = strv_copy((char**) search);
     629           4 :         if (!copy)
     630           0 :                 return -ENOMEM;
     631             : 
     632           4 :         return search_and_fopen_internal(path, mode, root, copy, _f);
     633             : }
     634             : 
     635           5 : int search_and_fopen_nulstr(const char *path, const char *mode, const char *root, const char *search, FILE **_f) {
     636           5 :         _cleanup_strv_free_ char **s = NULL;
     637             : 
     638           5 :         if (path_is_absolute(path)) {
     639             :                 FILE *f;
     640             : 
     641           2 :                 f = fopen(path, mode);
     642           2 :                 if (f) {
     643           1 :                         *_f = f;
     644           1 :                         return 0;
     645             :                 }
     646             : 
     647           1 :                 return -errno;
     648             :         }
     649             : 
     650           3 :         s = strv_split_nulstr(search);
     651           3 :         if (!s)
     652           0 :                 return -ENOMEM;
     653             : 
     654           3 :         return search_and_fopen_internal(path, mode, root, s, _f);
     655             : }
     656             : 
     657         696 : int fflush_and_check(FILE *f) {
     658         696 :         assert(f);
     659             : 
     660         696 :         errno = 0;
     661         696 :         fflush(f);
     662             : 
     663         696 :         if (ferror(f))
     664           0 :                 return errno_or_else(EIO);
     665             : 
     666         696 :         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          11 : int fputs_with_space(FILE *f, const char *s, const char *separator, bool *space) {
     723             :         int r;
     724             : 
     725          11 :         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          11 :         if (!f)
     733           0 :                 f = stdout;
     734             : 
     735          11 :         if (space) {
     736          11 :                 if (!separator)
     737          11 :                         separator = " ";
     738             : 
     739          11 :                 if (*space) {
     740           8 :                         r = fputs(separator, f);
     741           8 :                         if (r < 0)
     742           0 :                                 return r;
     743             :                 }
     744             : 
     745          11 :                 *space = true;
     746             :         }
     747             : 
     748          11 :         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    10642503 : static EndOfLineMarker categorize_eol(char c, ReadLineFlags flags) {
     760             : 
     761    10642503 :         if (!IN_SET(flags, READ_LINE_ONLY_NUL)) {
     762    10642424 :                 if (c == '\n')
     763      410279 :                         return EOL_TEN;
     764    10232145 :                 if (c == '\r')
     765          16 :                         return EOL_THIRTEEN;
     766             :         }
     767             : 
     768    10232208 :         if (c == '\0')
     769          29 :                 return EOL_ZERO;
     770             : 
     771    10232179 :         return EOL_NONE;
     772             : }
     773             : 
     774      320714 : DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, funlockfile);
     775             : 
     776      320714 : int read_line_full(FILE *f, size_t limit, ReadLineFlags flags, char **ret) {
     777      320714 :         size_t n = 0, allocated = 0, count = 0;
     778      320714 :         _cleanup_free_ char *buffer = NULL;
     779      320714 :         int r, tty = -1;
     780             : 
     781      320714 :         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      320714 :         if (ret) {
     808      320681 :                 if (!GREEDY_REALLOC(buffer, allocated, 1))
     809           0 :                         return -ENOMEM;
     810             :         }
     811             : 
     812             :         {
     813      320714 :                 _unused_ _cleanup_(funlockfilep) FILE *flocked = f;
     814      320714 :                 EndOfLineMarker previous_eol = EOL_NONE;
     815      320714 :                 flockfile(f);
     816             : 
     817    10328181 :                 for (;;) {
     818             :                         EndOfLineMarker eol;
     819             :                         char c;
     820             : 
     821    10648895 :                         if (n >= limit)
     822           3 :                                 return -ENOBUFS;
     823             : 
     824    10648892 :                         if (count >= INT_MAX) /* We couldn't return the counter anymore as "int", hence refuse this */
     825           0 :                                 return -ENOBUFS;
     826             : 
     827    10648892 :                         r = safe_fgetc(f, &c);
     828    10648892 :                         if (r < 0)
     829           0 :                                 return r;
     830    10648892 :                         if (r == 0) /* EOF is definitely EOL */
     831      320711 :                                 break;
     832             : 
     833    10642503 :                         eol = categorize_eol(c, flags);
     834             : 
     835    10642503 :                         if (FLAGS_SET(previous_eol, EOL_ZERO) ||
     836    10642487 :                             (eol == EOL_NONE && previous_eol != EOL_NONE) ||
     837      410319 :                             (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      314322 :                                 assert_se(ungetc((unsigned char) c, f) != EOF);
     848      314322 :                                 break;
     849             :                         }
     850             : 
     851    10328181 :                         count++;
     852             : 
     853    10328181 :                         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      319602 :                                 if (tty < 0)
     859      319576 :                                         tty = isatty(fileno(f));
     860      319602 :                                 if (tty > 0)
     861           0 :                                         break;
     862             :                         }
     863             : 
     864    10328181 :                         if (eol != EOL_NONE) {
     865      319602 :                                 previous_eol |= eol;
     866      319602 :                                 continue;
     867             :                         }
     868             : 
     869    10008579 :                         if (ret) {
     870    10008469 :                                 if (!GREEDY_REALLOC(buffer, allocated, n + 2))
     871           0 :                                         return -ENOMEM;
     872             : 
     873    10008469 :                                 buffer[n] = c;
     874             :                         }
     875             : 
     876    10008579 :                         n++;
     877             :                 }
     878             :         }
     879             : 
     880      320711 :         if (ret) {
     881      320678 :                 buffer[n] = 0;
     882             : 
     883      320678 :                 *ret = TAKE_PTR(buffer);
     884             :         }
     885             : 
     886      320711 :         return (int) count;
     887             : }
     888             : 
     889    10656188 : int safe_fgetc(FILE *f, char *ret) {
     890             :         int k;
     891             : 
     892    10656188 :         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    10656188 :         errno = 0;
     899    10656188 :         k = fgetc(f);
     900    10656188 :         if (k == EOF) {
     901        6391 :                 if (ferror(f))
     902           0 :                         return errno_or_else(EIO);
     903             : 
     904        6391 :                 if (ret)
     905        6391 :                         *ret = 0;
     906             : 
     907        6391 :                 return 0;
     908             :         }
     909             : 
     910    10649797 :         if (ret)
     911    10649797 :                 *ret = k;
     912             : 
     913    10649797 :         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