chiark / gitweb /
io-util: add an unlikely decorator for a test that should never hold
[elogind.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 (_unlikely_(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 }