]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/io-util.c
tree-wide: remove Lennart's copyright lines
[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
TA
6#include <stdio.h>
7#include <time.h>
c004493c
LP
8#include <unistd.h>
9
10#include "io-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}