]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/io-util.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / basic / io-util.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
c004493c
LP
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
11c3a366
TA
21#include <errno.h>
22#include <limits.h>
c004493c 23#include <poll.h>
11c3a366
TA
24#include <stdio.h>
25#include <time.h>
c004493c
LP
26#include <unistd.h>
27
28#include "io-util.h"
11c3a366 29#include "time-util.h"
c004493c
LP
30
31int flush_fd(int fd) {
32 struct pollfd pollfd = {
33 .fd = fd,
34 .events = POLLIN,
35 };
36
60d9771c
LP
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
c004493c
LP
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
72ssize_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
119int 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
131int 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
172int 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
190int 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
204 if (r == 0)
205 return 0;
206
207 return pollfd.revents;
208}
209
210static size_t nul_length(const uint8_t *p, size_t sz) {
211 size_t n = 0;
212
213 while (sz > 0) {
214 if (*p != 0)
215 break;
216
217 n++;
218 p++;
219 sz--;
220 }
221
222 return n;
223}
224
225ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length) {
226 const uint8_t *q, *w, *e;
227 ssize_t l;
228
229 q = w = p;
230 e = q + sz;
231 while (q < e) {
232 size_t n;
233
234 n = nul_length(q, e - q);
235
236 /* If there are more than the specified run length of
237 * NUL bytes, or if this is the beginning or the end
238 * of the buffer, then seek instead of write */
239 if ((n > run_length) ||
240 (n > 0 && q == p) ||
241 (n > 0 && q + n >= e)) {
242 if (q > w) {
243 l = write(fd, w, q - w);
244 if (l < 0)
245 return -errno;
246 if (l != q -w)
247 return -EIO;
248 }
249
250 if (lseek(fd, n, SEEK_CUR) == (off_t) -1)
251 return -errno;
252
253 q += n;
254 w = q;
255 } else if (n > 0)
256 q += n;
257 else
313cefa1 258 q++;
c004493c
LP
259 }
260
261 if (q > w) {
262 l = write(fd, w, q - w);
263 if (l < 0)
264 return -errno;
265 if (l != q - w)
266 return -EIO;
267 }
268
269 return q - (const uint8_t*) p;
270}