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