LCOV - code coverage report
Current view: top level - basic - io-util.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 96 178 53.9 %
Date: 2019-08-22 15:41:25 Functions: 10 19 52.6 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: LGPL-2.1+ */
       2             : 
       3             : #include <errno.h>
       4             : #include <limits.h>
       5             : #include <poll.h>
       6             : #include <stdio.h>
       7             : #include <time.h>
       8             : #include <unistd.h>
       9             : 
      10             : #include "io-util.h"
      11             : #include "string-util.h"
      12             : #include "time-util.h"
      13             : 
      14          21 : int flush_fd(int fd) {
      15          21 :         struct pollfd pollfd = {
      16             :                 .fd = fd,
      17             :                 .events = POLLIN,
      18             :         };
      19          21 :         int count = 0;
      20             : 
      21             :         /* Read from the specified file descriptor, until POLLIN is not set anymore, throwing away everything
      22             :          * read. Note that some file descriptors (notable IP sockets) will trigger POLLIN even when no data can be read
      23             :          * (due to IP packet checksum mismatches), hence this function is only safe to be non-blocking if the fd used
      24             :          * was set to non-blocking too. */
      25             : 
      26          14 :         for (;;) {
      27             :                 char buf[LINE_MAX];
      28             :                 ssize_t l;
      29             :                 int r;
      30             : 
      31          35 :                 r = poll(&pollfd, 1, 0);
      32          35 :                 if (r < 0) {
      33           0 :                         if (errno == EINTR)
      34           0 :                                 continue;
      35             : 
      36          21 :                         return -errno;
      37             : 
      38          35 :                 } else if (r == 0)
      39          21 :                         return count;
      40             : 
      41          14 :                 l = read(fd, buf, sizeof(buf));
      42          14 :                 if (l < 0) {
      43             : 
      44           0 :                         if (errno == EINTR)
      45           0 :                                 continue;
      46             : 
      47           0 :                         if (errno == EAGAIN)
      48           0 :                                 return count;
      49             : 
      50           0 :                         return -errno;
      51          14 :                 } else if (l == 0)
      52           0 :                         return count;
      53             : 
      54          14 :                 count += (int) l;
      55             :         }
      56             : }
      57             : 
      58         725 : ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) {
      59         725 :         uint8_t *p = buf;
      60         725 :         ssize_t n = 0;
      61             : 
      62         725 :         assert(fd >= 0);
      63         725 :         assert(buf);
      64             : 
      65             :         /* If called with nbytes == 0, let's call read() at least
      66             :          * once, to validate the operation */
      67             : 
      68         725 :         if (nbytes > (size_t) SSIZE_MAX)
      69           0 :                 return -EINVAL;
      70             : 
      71             :         do {
      72             :                 ssize_t k;
      73             : 
      74         776 :                 k = read(fd, p, nbytes);
      75         776 :                 if (k < 0) {
      76           0 :                         if (errno == EINTR)
      77           0 :                                 continue;
      78             : 
      79           0 :                         if (errno == EAGAIN && do_poll) {
      80             : 
      81             :                                 /* We knowingly ignore any return value here,
      82             :                                  * and expect that any error/EOF is reported
      83             :                                  * via read() */
      84             : 
      85           0 :                                 (void) fd_wait_for_event(fd, POLLIN, USEC_INFINITY);
      86           0 :                                 continue;
      87             :                         }
      88             : 
      89           0 :                         return n > 0 ? n : -errno;
      90             :                 }
      91             : 
      92         776 :                 if (k == 0)
      93          51 :                         return n;
      94             : 
      95         725 :                 assert((size_t) k <= nbytes);
      96             : 
      97         725 :                 p += k;
      98         725 :                 nbytes -= k;
      99         725 :                 n += k;
     100         725 :         } while (nbytes > 0);
     101             : 
     102         674 :         return n;
     103             : }
     104             : 
     105         674 : int loop_read_exact(int fd, void *buf, size_t nbytes, bool do_poll) {
     106             :         ssize_t n;
     107             : 
     108         674 :         n = loop_read(fd, buf, nbytes, do_poll);
     109         674 :         if (n < 0)
     110           0 :                 return (int) n;
     111         674 :         if ((size_t) n != nbytes)
     112           0 :                 return -EIO;
     113             : 
     114         674 :         return 0;
     115             : }
     116             : 
     117          52 : int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) {
     118          52 :         const uint8_t *p = buf;
     119             : 
     120          52 :         assert(fd >= 0);
     121          52 :         assert(buf);
     122             : 
     123          52 :         if (_unlikely_(nbytes > (size_t) SSIZE_MAX))
     124           0 :                 return -EINVAL;
     125             : 
     126             :         do {
     127             :                 ssize_t k;
     128             : 
     129          52 :                 k = write(fd, p, nbytes);
     130          52 :                 if (k < 0) {
     131           0 :                         if (errno == EINTR)
     132           0 :                                 continue;
     133             : 
     134           0 :                         if (errno == EAGAIN && do_poll) {
     135             :                                 /* We knowingly ignore any return value here,
     136             :                                  * and expect that any error/EOF is reported
     137             :                                  * via write() */
     138             : 
     139           0 :                                 (void) fd_wait_for_event(fd, POLLOUT, USEC_INFINITY);
     140           0 :                                 continue;
     141             :                         }
     142             : 
     143           0 :                         return -errno;
     144             :                 }
     145             : 
     146          52 :                 if (_unlikely_(nbytes > 0 && k == 0)) /* Can't really happen */
     147           0 :                         return -EIO;
     148             : 
     149          52 :                 assert((size_t) k <= nbytes);
     150             : 
     151          52 :                 p += k;
     152          52 :                 nbytes -= k;
     153          52 :         } while (nbytes > 0);
     154             : 
     155          52 :         return 0;
     156             : }
     157             : 
     158           0 : int pipe_eof(int fd) {
     159           0 :         struct pollfd pollfd = {
     160             :                 .fd = fd,
     161             :                 .events = POLLIN|POLLHUP,
     162             :         };
     163             : 
     164             :         int r;
     165             : 
     166           0 :         r = poll(&pollfd, 1, 0);
     167           0 :         if (r < 0)
     168           0 :                 return -errno;
     169             : 
     170           0 :         if (r == 0)
     171           0 :                 return 0;
     172             : 
     173           0 :         return pollfd.revents & POLLHUP;
     174             : }
     175             : 
     176           7 : int fd_wait_for_event(int fd, int event, usec_t t) {
     177             : 
     178           7 :         struct pollfd pollfd = {
     179             :                 .fd = fd,
     180             :                 .events = event,
     181             :         };
     182             : 
     183             :         struct timespec ts;
     184             :         int r;
     185             : 
     186           7 :         r = ppoll(&pollfd, 1, t == USEC_INFINITY ? NULL : timespec_store(&ts, t), NULL);
     187           7 :         if (r < 0)
     188           0 :                 return -errno;
     189           7 :         if (r == 0)
     190           0 :                 return 0;
     191             : 
     192           7 :         return pollfd.revents;
     193             : }
     194             : 
     195          58 : static size_t nul_length(const uint8_t *p, size_t sz) {
     196          58 :         size_t n = 0;
     197             : 
     198         110 :         while (sz > 0) {
     199         105 :                 if (*p != 0)
     200          53 :                         break;
     201             : 
     202          52 :                 n++;
     203          52 :                 p++;
     204          52 :                 sz--;
     205             :         }
     206             : 
     207          58 :         return n;
     208             : }
     209             : 
     210           5 : ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length) {
     211             :         const uint8_t *q, *w, *e;
     212             :         ssize_t l;
     213             : 
     214           5 :         q = w = p;
     215           5 :         e = q + sz;
     216          63 :         while (q < e) {
     217             :                 size_t n;
     218             : 
     219          58 :                 n = nul_length(q, e - q);
     220             : 
     221             :                 /* If there are more than the specified run length of
     222             :                  * NUL bytes, or if this is the beginning or the end
     223             :                  * of the buffer, then seek instead of write */
     224          58 :                 if ((n > run_length) ||
     225          54 :                     (n > 0 && q == p) ||
     226           7 :                     (n > 0 && q + n >= e)) {
     227           9 :                         if (q > w) {
     228           6 :                                 l = write(fd, w, q - w);
     229           6 :                                 if (l < 0)
     230           0 :                                         return -errno;
     231           6 :                                 if (l != q -w)
     232           0 :                                         return -EIO;
     233             :                         }
     234             : 
     235           9 :                         if (lseek(fd, n, SEEK_CUR) == (off_t) -1)
     236           0 :                                 return -errno;
     237             : 
     238           9 :                         q += n;
     239           9 :                         w = q;
     240          49 :                 } else if (n > 0)
     241           5 :                         q += n;
     242             :                 else
     243          44 :                         q++;
     244             :         }
     245             : 
     246           5 :         if (q > w) {
     247           0 :                 l = write(fd, w, q - w);
     248           0 :                 if (l < 0)
     249           0 :                         return -errno;
     250           0 :                 if (l != q - w)
     251           0 :                         return -EIO;
     252             :         }
     253             : 
     254           5 :         return q - (const uint8_t*) p;
     255             : }
     256             : 
     257           0 : char* set_iovec_string_field(struct iovec *iovec, size_t *n_iovec, const char *field, const char *value) {
     258             :         char *x;
     259             : 
     260           0 :         x = strjoin(field, value);
     261           0 :         if (x)
     262           0 :                 iovec[(*n_iovec)++] = IOVEC_MAKE_STRING(x);
     263           0 :         return x;
     264             : }
     265             : 
     266           0 : char* set_iovec_string_field_free(struct iovec *iovec, size_t *n_iovec, const char *field, char *value) {
     267             :         char *x;
     268             : 
     269           0 :         x = set_iovec_string_field(iovec, n_iovec, field, value);
     270           0 :         free(value);
     271           0 :         return x;
     272             : }
     273             : 
     274           0 : struct iovec_wrapper *iovw_new(void) {
     275           0 :         return malloc0(sizeof(struct iovec_wrapper));
     276             : }
     277             : 
     278           2 : void iovw_free_contents(struct iovec_wrapper *iovw, bool free_vectors) {
     279           2 :         if (free_vectors)
     280           0 :                 for (size_t i = 0; i < iovw->count; i++)
     281           0 :                         free(iovw->iovec[i].iov_base);
     282             : 
     283           2 :         iovw->iovec = mfree(iovw->iovec);
     284           2 :         iovw->count = 0;
     285           2 :         iovw->size_bytes = 0;
     286           2 : }
     287             : 
     288           0 : struct iovec_wrapper *iovw_free_free(struct iovec_wrapper *iovw) {
     289           0 :         iovw_free_contents(iovw, true);
     290             : 
     291           0 :         return mfree(iovw);
     292             : }
     293             : 
     294           0 : struct iovec_wrapper *iovw_free(struct iovec_wrapper *iovw) {
     295           0 :         iovw_free_contents(iovw, false);
     296             : 
     297           0 :         return mfree(iovw);
     298             : }
     299             : 
     300           7 : int iovw_put(struct iovec_wrapper *iovw, void *data, size_t len) {
     301           7 :         if (iovw->count >= IOV_MAX)
     302           0 :                 return -E2BIG;
     303             : 
     304           7 :         if (!GREEDY_REALLOC(iovw->iovec, iovw->size_bytes, iovw->count + 1))
     305           0 :                 return log_oom();
     306             : 
     307           7 :         iovw->iovec[iovw->count++] = IOVEC_MAKE(data, len);
     308           7 :         return 0;
     309             : }
     310             : 
     311           0 : int iovw_put_string_field(struct iovec_wrapper *iovw, const char *field, const char *value) {
     312           0 :         _cleanup_free_ char *x = NULL;
     313             :         int r;
     314             : 
     315           0 :         x = strjoin(field, value);
     316           0 :         if (!x)
     317           0 :                 return log_oom();
     318             : 
     319           0 :         r = iovw_put(iovw, x, strlen(x));
     320           0 :         if (r >= 0)
     321           0 :                 TAKE_PTR(x);
     322             : 
     323           0 :         return r;
     324             : }
     325             : 
     326           0 : int iovw_put_string_field_free(struct iovec_wrapper *iovw, const char *field, char *value) {
     327           0 :         _cleanup_free_ _unused_ char *free_ptr = value;
     328             : 
     329           0 :         return iovw_put_string_field(iovw, field, value);
     330             : }
     331             : 
     332           2 : void iovw_rebase(struct iovec_wrapper *iovw, char *old, char *new) {
     333             :         size_t i;
     334             : 
     335           2 :         for (i = 0; i < iovw->count; i++)
     336           0 :                 iovw->iovec[i].iov_base = (char *)iovw->iovec[i].iov_base - old + new;
     337           2 : }
     338             : 
     339           0 : size_t iovw_size(struct iovec_wrapper *iovw) {
     340           0 :         size_t n = 0, i;
     341             : 
     342           0 :         for (i = 0; i < iovw->count; i++)
     343           0 :                 n += iovw->iovec[i].iov_len;
     344             : 
     345           0 :         return n;
     346             : }

Generated by: LCOV version 1.14