]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/io-util.c
alloc-util: simplify GREEDY_REALLOC() logic by relying on malloc_usable_size()
[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 = buf;
53 ssize_t n = 0;
54
55 assert(fd >= 0);
56 assert(buf);
57
58 /* If called with nbytes == 0, let's call read() at least
59 * once, to validate the operation */
60
61 if (nbytes > (size_t) SSIZE_MAX)
62 return -EINVAL;
63
64 do {
65 ssize_t k;
66
67 k = read(fd, p, nbytes);
68 if (k < 0) {
69 if (errno == EINTR)
70 continue;
71
72 if (errno == EAGAIN && do_poll) {
73
74 /* We knowingly ignore any return value here,
75 * and expect that any error/EOF is reported
76 * via read() */
77
78 (void) fd_wait_for_event(fd, POLLIN, USEC_INFINITY);
79 continue;
80 }
81
82 return n > 0 ? n : -errno;
83 }
84
85 if (k == 0)
86 return n;
87
88 assert((size_t) k <= nbytes);
89
90 p += k;
91 nbytes -= k;
92 n += k;
93 } while (nbytes > 0);
94
95 return n;
96 }
97
98 int loop_read_exact(int fd, void *buf, size_t nbytes, bool do_poll) {
99 ssize_t n;
100
101 n = loop_read(fd, buf, nbytes, do_poll);
102 if (n < 0)
103 return (int) n;
104 if ((size_t) n != nbytes)
105 return -EIO;
106
107 return 0;
108 }
109
110 int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) {
111 const uint8_t *p = buf;
112
113 assert(fd >= 0);
114 assert(buf);
115
116 if (_unlikely_(nbytes > (size_t) SSIZE_MAX))
117 return -EINVAL;
118
119 do {
120 ssize_t k;
121
122 k = write(fd, p, nbytes);
123 if (k < 0) {
124 if (errno == EINTR)
125 continue;
126
127 if (errno == EAGAIN && do_poll) {
128 /* We knowingly ignore any return value here,
129 * and expect that any error/EOF is reported
130 * via write() */
131
132 (void) fd_wait_for_event(fd, POLLOUT, USEC_INFINITY);
133 continue;
134 }
135
136 return -errno;
137 }
138
139 if (_unlikely_(nbytes > 0 && k == 0)) /* Can't really happen */
140 return -EIO;
141
142 assert((size_t) k <= nbytes);
143
144 p += k;
145 nbytes -= k;
146 } while (nbytes > 0);
147
148 return 0;
149 }
150
151 int pipe_eof(int fd) {
152 int r;
153
154 r = fd_wait_for_event(fd, POLLIN, 0);
155 if (r <= 0)
156 return r;
157
158 return !!(r & POLLHUP);
159 }
160
161 int ppoll_usec(struct pollfd *fds, size_t nfds, usec_t timeout) {
162 struct timespec ts;
163 int r;
164
165 assert(fds || nfds == 0);
166
167 if (nfds == 0)
168 return 0;
169
170 r = ppoll(fds, nfds, timeout == USEC_INFINITY ? NULL : timespec_store(&ts, timeout), NULL);
171 if (r < 0)
172 return -errno;
173 if (r == 0)
174 return 0;
175
176 for (size_t i = 0, n = r; i < nfds && n > 0; i++) {
177 if (fds[i].revents == 0)
178 continue;
179 if (fds[i].revents & POLLNVAL)
180 return -EBADF;
181 n--;
182 }
183
184 return r;
185 }
186
187 int fd_wait_for_event(int fd, int event, usec_t timeout) {
188 struct pollfd pollfd = {
189 .fd = fd,
190 .events = event,
191 };
192 int r;
193
194 r = ppoll_usec(&pollfd, 1, timeout);
195 if (r <= 0)
196 return r;
197
198 return pollfd.revents;
199 }
200
201 static size_t nul_length(const uint8_t *p, size_t sz) {
202 size_t n = 0;
203
204 while (sz > 0) {
205 if (*p != 0)
206 break;
207
208 n++;
209 p++;
210 sz--;
211 }
212
213 return n;
214 }
215
216 ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length) {
217 const uint8_t *q, *w, *e;
218 ssize_t l;
219
220 q = w = p;
221 e = q + sz;
222 while (q < e) {
223 size_t n;
224
225 n = nul_length(q, e - q);
226
227 /* If there are more than the specified run length of
228 * NUL bytes, or if this is the beginning or the end
229 * of the buffer, then seek instead of write */
230 if ((n > run_length) ||
231 (n > 0 && q == p) ||
232 (n > 0 && q + n >= e)) {
233 if (q > w) {
234 l = write(fd, w, q - w);
235 if (l < 0)
236 return -errno;
237 if (l != q -w)
238 return -EIO;
239 }
240
241 if (lseek(fd, n, SEEK_CUR) == (off_t) -1)
242 return -errno;
243
244 q += n;
245 w = q;
246 } else if (n > 0)
247 q += n;
248 else
249 q++;
250 }
251
252 if (q > w) {
253 l = write(fd, w, q - w);
254 if (l < 0)
255 return -errno;
256 if (l != q - w)
257 return -EIO;
258 }
259
260 return q - (const uint8_t*) p;
261 }
262
263 char* set_iovec_string_field(struct iovec *iovec, size_t *n_iovec, const char *field, const char *value) {
264 char *x;
265
266 x = strjoin(field, value);
267 if (x)
268 iovec[(*n_iovec)++] = IOVEC_MAKE_STRING(x);
269 return x;
270 }
271
272 char* set_iovec_string_field_free(struct iovec *iovec, size_t *n_iovec, const char *field, char *value) {
273 char *x;
274
275 x = set_iovec_string_field(iovec, n_iovec, field, value);
276 free(value);
277 return x;
278 }
279
280 struct iovec_wrapper *iovw_new(void) {
281 return malloc0(sizeof(struct iovec_wrapper));
282 }
283
284 void iovw_free_contents(struct iovec_wrapper *iovw, bool free_vectors) {
285 if (free_vectors)
286 for (size_t i = 0; i < iovw->count; i++)
287 free(iovw->iovec[i].iov_base);
288
289 iovw->iovec = mfree(iovw->iovec);
290 iovw->count = 0;
291 }
292
293 struct iovec_wrapper *iovw_free_free(struct iovec_wrapper *iovw) {
294 iovw_free_contents(iovw, true);
295
296 return mfree(iovw);
297 }
298
299 struct iovec_wrapper *iovw_free(struct iovec_wrapper *iovw) {
300 iovw_free_contents(iovw, false);
301
302 return mfree(iovw);
303 }
304
305 int iovw_put(struct iovec_wrapper *iovw, void *data, size_t len) {
306 if (iovw->count >= IOV_MAX)
307 return -E2BIG;
308
309 if (!GREEDY_REALLOC(iovw->iovec, iovw->count + 1))
310 return -ENOMEM;
311
312 iovw->iovec[iovw->count++] = IOVEC_MAKE(data, len);
313 return 0;
314 }
315
316 int iovw_put_string_field(struct iovec_wrapper *iovw, const char *field, const char *value) {
317 _cleanup_free_ char *x = NULL;
318 int r;
319
320 x = strjoin(field, value);
321 if (!x)
322 return -ENOMEM;
323
324 r = iovw_put(iovw, x, strlen(x));
325 if (r >= 0)
326 TAKE_PTR(x);
327
328 return r;
329 }
330
331 int iovw_put_string_field_free(struct iovec_wrapper *iovw, const char *field, char *value) {
332 _cleanup_free_ _unused_ char *free_ptr = value;
333
334 return iovw_put_string_field(iovw, field, value);
335 }
336
337 void iovw_rebase(struct iovec_wrapper *iovw, char *old, char *new) {
338 for (size_t i = 0; i < iovw->count; i++)
339 iovw->iovec[i].iov_base = (char *)iovw->iovec[i].iov_base - old + new;
340 }
341
342 size_t iovw_size(struct iovec_wrapper *iovw) {
343 size_t n = 0;
344
345 for (size_t i = 0; i < iovw->count; i++)
346 n += iovw->iovec[i].iov_len;
347
348 return n;
349 }