chiark / gitweb /
tree-wide: remove Lennart's copyright lines
[elogind.git] / src / basic / io-util.c
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 "time-util.h"
12
13 int flush_fd(int fd) {
14         struct pollfd pollfd = {
15                 .fd = fd,
16                 .events = POLLIN,
17         };
18         int count = 0;
19
20         /* Read from the specified file descriptor, until POLLIN is not set anymore, throwing away everything
21          * read. Note that some file descriptors (notable IP sockets) will trigger POLLIN even when no data can be read
22          * (due to IP packet checksum mismatches), hence this function is only safe to be non-blocking if the fd used
23          * was set to non-blocking too. */
24
25         for (;;) {
26                 char buf[LINE_MAX];
27                 ssize_t l;
28                 int r;
29
30                 r = poll(&pollfd, 1, 0);
31                 if (r < 0) {
32                         if (errno == EINTR)
33                                 continue;
34
35                         return -errno;
36
37                 } else if (r == 0)
38                         return count;
39
40                 l = read(fd, buf, sizeof(buf));
41                 if (l < 0) {
42
43                         if (errno == EINTR)
44                                 continue;
45
46                         if (errno == EAGAIN)
47                                 return count;
48
49                         return -errno;
50                 } else if (l == 0)
51                         return count;
52
53                 count += (int) l;
54         }
55 }
56
57 ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) {
58         uint8_t *p = buf;
59         ssize_t n = 0;
60
61         assert(fd >= 0);
62         assert(buf);
63
64         /* If called with nbytes == 0, let's call read() at least
65          * once, to validate the operation */
66
67         if (nbytes > (size_t) SSIZE_MAX)
68                 return -EINVAL;
69
70         do {
71                 ssize_t k;
72
73                 k = read(fd, p, nbytes);
74                 if (k < 0) {
75                         if (errno == EINTR)
76                                 continue;
77
78                         if (errno == EAGAIN && do_poll) {
79
80                                 /* We knowingly ignore any return value here,
81                                  * and expect that any error/EOF is reported
82                                  * via read() */
83
84                                 (void) fd_wait_for_event(fd, POLLIN, USEC_INFINITY);
85                                 continue;
86                         }
87
88                         return n > 0 ? n : -errno;
89                 }
90
91                 if (k == 0)
92                         return n;
93
94                 assert((size_t) k <= nbytes);
95
96                 p += k;
97                 nbytes -= k;
98                 n += k;
99         } while (nbytes > 0);
100
101         return n;
102 }
103
104 int loop_read_exact(int fd, void *buf, size_t nbytes, bool do_poll) {
105         ssize_t n;
106
107         n = loop_read(fd, buf, nbytes, do_poll);
108         if (n < 0)
109                 return (int) n;
110         if ((size_t) n != nbytes)
111                 return -EIO;
112
113         return 0;
114 }
115
116 int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) {
117         const uint8_t *p = buf;
118
119         assert(fd >= 0);
120         assert(buf);
121
122         if (_unlikely_(nbytes > (size_t) SSIZE_MAX))
123                 return -EINVAL;
124
125         do {
126                 ssize_t k;
127
128                 k = write(fd, p, nbytes);
129                 if (k < 0) {
130                         if (errno == EINTR)
131                                 continue;
132
133                         if (errno == EAGAIN && do_poll) {
134                                 /* We knowingly ignore any return value here,
135                                  * and expect that any error/EOF is reported
136                                  * via write() */
137
138                                 (void) fd_wait_for_event(fd, POLLOUT, USEC_INFINITY);
139                                 continue;
140                         }
141
142                         return -errno;
143                 }
144
145                 if (_unlikely_(nbytes > 0 && k == 0)) /* Can't really happen */
146                         return -EIO;
147
148                 assert((size_t) k <= nbytes);
149
150                 p += k;
151                 nbytes -= k;
152         } while (nbytes > 0);
153
154         return 0;
155 }
156
157 int pipe_eof(int fd) {
158         struct pollfd pollfd = {
159                 .fd = fd,
160                 .events = POLLIN|POLLHUP,
161         };
162
163         int r;
164
165         r = poll(&pollfd, 1, 0);
166         if (r < 0)
167                 return -errno;
168
169         if (r == 0)
170                 return 0;
171
172         return pollfd.revents & POLLHUP;
173 }
174
175 int fd_wait_for_event(int fd, int event, usec_t t) {
176
177         struct pollfd pollfd = {
178                 .fd = fd,
179                 .events = event,
180         };
181
182         struct timespec ts;
183         int r;
184
185         r = ppoll(&pollfd, 1, t == USEC_INFINITY ? NULL : timespec_store(&ts, t), NULL);
186         if (r < 0)
187                 return -errno;
188         if (r == 0)
189                 return 0;
190
191         return pollfd.revents;
192 }
193
194 static size_t nul_length(const uint8_t *p, size_t sz) {
195         size_t n = 0;
196
197         while (sz > 0) {
198                 if (*p != 0)
199                         break;
200
201                 n++;
202                 p++;
203                 sz--;
204         }
205
206         return n;
207 }
208
209 ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length) {
210         const uint8_t *q, *w, *e;
211         ssize_t l;
212
213         q = w = p;
214         e = q + sz;
215         while (q < e) {
216                 size_t n;
217
218                 n = nul_length(q, e - q);
219
220                 /* If there are more than the specified run length of
221                  * NUL bytes, or if this is the beginning or the end
222                  * of the buffer, then seek instead of write */
223                 if ((n > run_length) ||
224                     (n > 0 && q == p) ||
225                     (n > 0 && q + n >= e)) {
226                         if (q > w) {
227                                 l = write(fd, w, q - w);
228                                 if (l < 0)
229                                         return -errno;
230                                 if (l != q -w)
231                                         return -EIO;
232                         }
233
234                         if (lseek(fd, n, SEEK_CUR) == (off_t) -1)
235                                 return -errno;
236
237                         q += n;
238                         w = q;
239                 } else if (n > 0)
240                         q += n;
241                 else
242                         q++;
243         }
244
245         if (q > w) {
246                 l = write(fd, w, q - w);
247                 if (l < 0)
248                         return -errno;
249                 if (l != q - w)
250                         return -EIO;
251         }
252
253         return q - (const uint8_t*) p;
254 }