chiark / gitweb /
Prep v232: Apply missing updates from upstream
[elogind.git] / src / basic / io-util.c
1 /***
2   This file is part of systemd.
3
4   Copyright 2010 Lennart Poettering
5
6   systemd is free software; you can redistribute it and/or modify it
7   under the terms of the GNU Lesser General Public License as published by
8   the Free Software Foundation; either version 2.1 of the License, or
9   (at your option) any later version.
10
11   systemd is distributed in the hope that it will be useful, but
12   WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14   Lesser General Public License for more details.
15
16   You should have received a copy of the GNU Lesser General Public License
17   along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include <errno.h>
21 #include <limits.h>
22 #include <poll.h>
23 #include <stdio.h>
24 #include <time.h>
25 #include <unistd.h>
26
27 #include "io-util.h"
28 #include "time-util.h"
29
30 int flush_fd(int fd) {
31         struct pollfd pollfd = {
32                 .fd = fd,
33                 .events = POLLIN,
34         };
35
36         /* Read from the specified file descriptor, until POLLIN is not set anymore, throwing away everything
37          * read. Note that some file descriptors (notable IP sockets) will trigger POLLIN even when no data can be read
38          * (due to IP packet checksum mismatches), hence this function is only safe to be non-blocking if the fd used
39          * was set to non-blocking too. */
40
41         for (;;) {
42                 char buf[LINE_MAX];
43                 ssize_t l;
44                 int r;
45
46                 r = poll(&pollfd, 1, 0);
47                 if (r < 0) {
48                         if (errno == EINTR)
49                                 continue;
50
51                         return -errno;
52
53                 } else if (r == 0)
54                         return 0;
55
56                 l = read(fd, buf, sizeof(buf));
57                 if (l < 0) {
58
59                         if (errno == EINTR)
60                                 continue;
61
62                         if (errno == EAGAIN)
63                                 return 0;
64
65                         return -errno;
66                 } else if (l == 0)
67                         return 0;
68         }
69 }
70
71 ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) {
72         uint8_t *p = buf;
73         ssize_t n = 0;
74
75         assert(fd >= 0);
76         assert(buf);
77
78         /* If called with nbytes == 0, let's call read() at least
79          * once, to validate the operation */
80
81         if (nbytes > (size_t) SSIZE_MAX)
82                 return -EINVAL;
83
84         do {
85                 ssize_t k;
86
87                 k = read(fd, p, nbytes);
88                 if (k < 0) {
89                         if (errno == EINTR)
90                                 continue;
91
92                         if (errno == EAGAIN && do_poll) {
93
94                                 /* We knowingly ignore any return value here,
95                                  * and expect that any error/EOF is reported
96                                  * via read() */
97
98                                 (void) fd_wait_for_event(fd, POLLIN, USEC_INFINITY);
99                                 continue;
100                         }
101
102                         return n > 0 ? n : -errno;
103                 }
104
105                 if (k == 0)
106                         return n;
107
108                 assert((size_t) k <= nbytes);
109
110                 p += k;
111                 nbytes -= k;
112                 n += k;
113         } while (nbytes > 0);
114
115         return n;
116 }
117
118 int loop_read_exact(int fd, void *buf, size_t nbytes, bool do_poll) {
119         ssize_t n;
120
121         n = loop_read(fd, buf, nbytes, do_poll);
122         if (n < 0)
123                 return (int) n;
124         if ((size_t) n != nbytes)
125                 return -EIO;
126
127         return 0;
128 }
129
130 int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) {
131         const uint8_t *p = buf;
132
133         assert(fd >= 0);
134         assert(buf);
135
136         if (nbytes > (size_t) SSIZE_MAX)
137                 return -EINVAL;
138
139         do {
140                 ssize_t k;
141
142                 k = write(fd, p, nbytes);
143                 if (k < 0) {
144                         if (errno == EINTR)
145                                 continue;
146
147                         if (errno == EAGAIN && do_poll) {
148                                 /* We knowingly ignore any return value here,
149                                  * and expect that any error/EOF is reported
150                                  * via write() */
151
152                                 (void) fd_wait_for_event(fd, POLLOUT, USEC_INFINITY);
153                                 continue;
154                         }
155
156                         return -errno;
157                 }
158
159                 if (_unlikely_(nbytes > 0 && k == 0)) /* Can't really happen */
160                         return -EIO;
161
162                 assert((size_t) k <= nbytes);
163
164                 p += k;
165                 nbytes -= k;
166         } while (nbytes > 0);
167
168         return 0;
169 }
170
171 int pipe_eof(int fd) {
172         struct pollfd pollfd = {
173                 .fd = fd,
174                 .events = POLLIN|POLLHUP,
175         };
176
177         int r;
178
179         r = poll(&pollfd, 1, 0);
180         if (r < 0)
181                 return -errno;
182
183         if (r == 0)
184                 return 0;
185
186         return pollfd.revents & POLLHUP;
187 }
188
189 int fd_wait_for_event(int fd, int event, usec_t t) {
190
191         struct pollfd pollfd = {
192                 .fd = fd,
193                 .events = event,
194         };
195
196         struct timespec ts;
197         int r;
198
199         r = ppoll(&pollfd, 1, t == USEC_INFINITY ? NULL : timespec_store(&ts, t), NULL);
200         if (r < 0)
201                 return -errno;
202
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 }