chiark / gitweb /
sd-resolve: propagate timeouts in sd_resolve_wait() the same way as in sd_bus_wait...
[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         if (r == 0)
203                 return 0;
204
205         return pollfd.revents;
206 }
207
208 static size_t nul_length(const uint8_t *p, size_t sz) {
209         size_t n = 0;
210
211         while (sz > 0) {
212                 if (*p != 0)
213                         break;
214
215                 n++;
216                 p++;
217                 sz--;
218         }
219
220         return n;
221 }
222
223 ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length) {
224         const uint8_t *q, *w, *e;
225         ssize_t l;
226
227         q = w = p;
228         e = q + sz;
229         while (q < e) {
230                 size_t n;
231
232                 n = nul_length(q, e - q);
233
234                 /* If there are more than the specified run length of
235                  * NUL bytes, or if this is the beginning or the end
236                  * of the buffer, then seek instead of write */
237                 if ((n > run_length) ||
238                     (n > 0 && q == p) ||
239                     (n > 0 && q + n >= e)) {
240                         if (q > w) {
241                                 l = write(fd, w, q - w);
242                                 if (l < 0)
243                                         return -errno;
244                                 if (l != q -w)
245                                         return -EIO;
246                         }
247
248                         if (lseek(fd, n, SEEK_CUR) == (off_t) -1)
249                                 return -errno;
250
251                         q += n;
252                         w = q;
253                 } else if (n > 0)
254                         q += n;
255                 else
256                         q++;
257         }
258
259         if (q > w) {
260                 l = write(fd, w, q - w);
261                 if (l < 0)
262                         return -errno;
263                 if (l != q - w)
264                         return -EIO;
265         }
266
267         return q - (const uint8_t*) p;
268 }