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