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