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