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