]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/io-util.c
sd-resolve: propagate timeouts in sd_resolve_wait() the same way as in sd_bus_wait...
[thirdparty/systemd.git] / src / basic / io-util.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright 2010 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #include <errno.h>
22 #include <limits.h>
23 #include <poll.h>
24 #include <stdio.h>
25 #include <time.h>
26 #include <unistd.h>
27
28 #include "io-util.h"
29 #include "time-util.h"
30
31 int flush_fd(int fd) {
32 struct pollfd pollfd = {
33 .fd = fd,
34 .events = POLLIN,
35 };
36
37 /* Read from the specified file descriptor, until POLLIN is not set anymore, throwing away everything
38 * read. Note that some file descriptors (notable IP sockets) will trigger POLLIN even when no data can be read
39 * (due to IP packet checksum mismatches), hence this function is only safe to be non-blocking if the fd used
40 * was set to non-blocking too. */
41
42 for (;;) {
43 char buf[LINE_MAX];
44 ssize_t l;
45 int r;
46
47 r = poll(&pollfd, 1, 0);
48 if (r < 0) {
49 if (errno == EINTR)
50 continue;
51
52 return -errno;
53
54 } else if (r == 0)
55 return 0;
56
57 l = read(fd, buf, sizeof(buf));
58 if (l < 0) {
59
60 if (errno == EINTR)
61 continue;
62
63 if (errno == EAGAIN)
64 return 0;
65
66 return -errno;
67 } else if (l == 0)
68 return 0;
69 }
70 }
71
72 ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) {
73 uint8_t *p = buf;
74 ssize_t n = 0;
75
76 assert(fd >= 0);
77 assert(buf);
78
79 /* If called with nbytes == 0, let's call read() at least
80 * once, to validate the operation */
81
82 if (nbytes > (size_t) SSIZE_MAX)
83 return -EINVAL;
84
85 do {
86 ssize_t k;
87
88 k = read(fd, p, nbytes);
89 if (k < 0) {
90 if (errno == EINTR)
91 continue;
92
93 if (errno == EAGAIN && do_poll) {
94
95 /* We knowingly ignore any return value here,
96 * and expect that any error/EOF is reported
97 * via read() */
98
99 (void) fd_wait_for_event(fd, POLLIN, USEC_INFINITY);
100 continue;
101 }
102
103 return n > 0 ? n : -errno;
104 }
105
106 if (k == 0)
107 return n;
108
109 assert((size_t) k <= nbytes);
110
111 p += k;
112 nbytes -= k;
113 n += k;
114 } while (nbytes > 0);
115
116 return n;
117 }
118
119 int loop_read_exact(int fd, void *buf, size_t nbytes, bool do_poll) {
120 ssize_t n;
121
122 n = loop_read(fd, buf, nbytes, do_poll);
123 if (n < 0)
124 return (int) n;
125 if ((size_t) n != nbytes)
126 return -EIO;
127
128 return 0;
129 }
130
131 int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) {
132 const uint8_t *p = buf;
133
134 assert(fd >= 0);
135 assert(buf);
136
137 if (nbytes > (size_t) SSIZE_MAX)
138 return -EINVAL;
139
140 do {
141 ssize_t k;
142
143 k = write(fd, p, nbytes);
144 if (k < 0) {
145 if (errno == EINTR)
146 continue;
147
148 if (errno == EAGAIN && do_poll) {
149 /* We knowingly ignore any return value here,
150 * and expect that any error/EOF is reported
151 * via write() */
152
153 (void) fd_wait_for_event(fd, POLLOUT, USEC_INFINITY);
154 continue;
155 }
156
157 return -errno;
158 }
159
160 if (_unlikely_(nbytes > 0 && k == 0)) /* Can't really happen */
161 return -EIO;
162
163 assert((size_t) k <= nbytes);
164
165 p += k;
166 nbytes -= k;
167 } while (nbytes > 0);
168
169 return 0;
170 }
171
172 int pipe_eof(int fd) {
173 struct pollfd pollfd = {
174 .fd = fd,
175 .events = POLLIN|POLLHUP,
176 };
177
178 int r;
179
180 r = poll(&pollfd, 1, 0);
181 if (r < 0)
182 return -errno;
183
184 if (r == 0)
185 return 0;
186
187 return pollfd.revents & POLLHUP;
188 }
189
190 int fd_wait_for_event(int fd, int event, usec_t t) {
191
192 struct pollfd pollfd = {
193 .fd = fd,
194 .events = event,
195 };
196
197 struct timespec ts;
198 int r;
199
200 r = ppoll(&pollfd, 1, t == USEC_INFINITY ? NULL : timespec_store(&ts, t), NULL);
201 if (r < 0)
202 return -errno;
203 if (r == 0)
204 return 0;
205
206 return pollfd.revents;
207 }
208
209 static size_t nul_length(const uint8_t *p, size_t sz) {
210 size_t n = 0;
211
212 while (sz > 0) {
213 if (*p != 0)
214 break;
215
216 n++;
217 p++;
218 sz--;
219 }
220
221 return n;
222 }
223
224 ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length) {
225 const uint8_t *q, *w, *e;
226 ssize_t l;
227
228 q = w = p;
229 e = q + sz;
230 while (q < e) {
231 size_t n;
232
233 n = nul_length(q, e - q);
234
235 /* If there are more than the specified run length of
236 * NUL bytes, or if this is the beginning or the end
237 * of the buffer, then seek instead of write */
238 if ((n > run_length) ||
239 (n > 0 && q == p) ||
240 (n > 0 && q + n >= e)) {
241 if (q > w) {
242 l = write(fd, w, q - w);
243 if (l < 0)
244 return -errno;
245 if (l != q -w)
246 return -EIO;
247 }
248
249 if (lseek(fd, n, SEEK_CUR) == (off_t) -1)
250 return -errno;
251
252 q += n;
253 w = q;
254 } else if (n > 0)
255 q += n;
256 else
257 q++;
258 }
259
260 if (q > w) {
261 l = write(fd, w, q - w);
262 if (l < 0)
263 return -errno;
264 if (l != q - w)
265 return -EIO;
266 }
267
268 return q - (const uint8_t*) p;
269 }