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