]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/io-util.c
tree-wide: drop time.h when time-util.h is included
[thirdparty/systemd.git] / src / basic / io-util.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
c004493c 2
11c3a366
TA
3#include <errno.h>
4#include <limits.h>
c004493c 5#include <poll.h>
11c3a366 6#include <stdio.h>
c004493c
LP
7#include <unistd.h>
8
9#include "io-util.h"
084eeb86 10#include "string-util.h"
11c3a366 11#include "time-util.h"
c004493c
LP
12
13int flush_fd(int fd) {
14 struct pollfd pollfd = {
15 .fd = fd,
16 .events = POLLIN,
17 };
665dfe93 18 int count = 0;
c004493c 19
60d9771c
LP
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
c004493c
LP
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)
665dfe93 38 return count;
c004493c
LP
39
40 l = read(fd, buf, sizeof(buf));
41 if (l < 0) {
42
43 if (errno == EINTR)
44 continue;
45
46 if (errno == EAGAIN)
665dfe93 47 return count;
c004493c
LP
48
49 return -errno;
50 } else if (l == 0)
665dfe93
LP
51 return count;
52
53 count += (int) l;
c004493c
LP
54 }
55}
56
57ssize_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
104int 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
116int 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
7f7210c2 122 if (_unlikely_(nbytes > (size_t) SSIZE_MAX))
c004493c
LP
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
157int 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
175int 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;
c004493c
LP
188 if (r == 0)
189 return 0;
190
191 return pollfd.revents;
192}
193
194static 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
209ssize_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
313cefa1 242 q++;
c004493c
LP
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}
084eeb86
ZJS
255
256char* set_iovec_string_field(struct iovec *iovec, size_t *n_iovec, const char *field, const char *value) {
257 char *x;
258
b910cc72 259 x = strjoin(field, value);
084eeb86
ZJS
260 if (x)
261 iovec[(*n_iovec)++] = IOVEC_MAKE_STRING(x);
262 return x;
263}
30a0554e
FB
264
265char* set_iovec_string_field_free(struct iovec *iovec, size_t *n_iovec, const char *field, char *value) {
266 char *x;
267
268 x = set_iovec_string_field(iovec, n_iovec, field, value);
269 free(value);
270 return x;
271}
11e6d971
FB
272
273struct iovec_wrapper *iovw_new(void) {
274 return malloc0(sizeof(struct iovec_wrapper));
275}
276
277void iovw_free_contents(struct iovec_wrapper *iovw, bool free_vectors) {
278 if (free_vectors)
279 for (size_t i = 0; i < iovw->count; i++)
280 free(iovw->iovec[i].iov_base);
281
282 iovw->iovec = mfree(iovw->iovec);
283 iovw->count = 0;
284 iovw->size_bytes = 0;
285}
286
287struct iovec_wrapper *iovw_free_free(struct iovec_wrapper *iovw) {
288 iovw_free_contents(iovw, true);
289
290 return mfree(iovw);
291}
292
293struct iovec_wrapper *iovw_free(struct iovec_wrapper *iovw) {
294 iovw_free_contents(iovw, false);
295
296 return mfree(iovw);
297}
298
299int iovw_put(struct iovec_wrapper *iovw, void *data, size_t len) {
300 if (iovw->count >= IOV_MAX)
301 return -E2BIG;
302
303 if (!GREEDY_REALLOC(iovw->iovec, iovw->size_bytes, iovw->count + 1))
304 return log_oom();
305
306 iovw->iovec[iovw->count++] = IOVEC_MAKE(data, len);
307 return 0;
308}
309
ae41fdb6
FB
310int iovw_put_string_field(struct iovec_wrapper *iovw, const char *field, const char *value) {
311 _cleanup_free_ char *x = NULL;
312 int r;
313
b910cc72 314 x = strjoin(field, value);
ae41fdb6
FB
315 if (!x)
316 return log_oom();
317
318 r = iovw_put(iovw, x, strlen(x));
319 if (r >= 0)
320 TAKE_PTR(x);
321
322 return r;
323}
324
325int iovw_put_string_field_free(struct iovec_wrapper *iovw, const char *field, char *value) {
326 _cleanup_free_ _unused_ char *free_ptr = value;
327
328 return iovw_put_string_field(iovw, field, value);
329}
330
11e6d971
FB
331void iovw_rebase(struct iovec_wrapper *iovw, char *old, char *new) {
332 size_t i;
333
334 for (i = 0; i < iovw->count; i++)
335 iovw->iovec[i].iov_base = (char *)iovw->iovec[i].iov_base - old + new;
336}
337
338size_t iovw_size(struct iovec_wrapper *iovw) {
339 size_t n = 0, i;
340
341 for (i = 0; i < iovw->count; i++)
342 n += iovw->iovec[i].iov_len;
343
344 return n;
345}