]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/io-util.c
basic: include only what we use
[thirdparty/systemd.git] / src / basic / io-util.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <errno.h>
23 #include <limits.h>
24 #include <poll.h>
25 #include <stdio.h>
26 #include <time.h>
27 #include <unistd.h>
28
29 #include "io-util.h"
30 #include "time-util.h"
31
32 int flush_fd(int fd) {
33 struct pollfd pollfd = {
34 .fd = fd,
35 .events = POLLIN,
36 };
37
38 for (;;) {
39 char buf[LINE_MAX];
40 ssize_t l;
41 int r;
42
43 r = poll(&pollfd, 1, 0);
44 if (r < 0) {
45 if (errno == EINTR)
46 continue;
47
48 return -errno;
49
50 } else if (r == 0)
51 return 0;
52
53 l = read(fd, buf, sizeof(buf));
54 if (l < 0) {
55
56 if (errno == EINTR)
57 continue;
58
59 if (errno == EAGAIN)
60 return 0;
61
62 return -errno;
63 } else if (l == 0)
64 return 0;
65 }
66 }
67
68 ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) {
69 uint8_t *p = buf;
70 ssize_t n = 0;
71
72 assert(fd >= 0);
73 assert(buf);
74
75 /* If called with nbytes == 0, let's call read() at least
76 * once, to validate the operation */
77
78 if (nbytes > (size_t) SSIZE_MAX)
79 return -EINVAL;
80
81 do {
82 ssize_t k;
83
84 k = read(fd, p, nbytes);
85 if (k < 0) {
86 if (errno == EINTR)
87 continue;
88
89 if (errno == EAGAIN && do_poll) {
90
91 /* We knowingly ignore any return value here,
92 * and expect that any error/EOF is reported
93 * via read() */
94
95 (void) fd_wait_for_event(fd, POLLIN, USEC_INFINITY);
96 continue;
97 }
98
99 return n > 0 ? n : -errno;
100 }
101
102 if (k == 0)
103 return n;
104
105 assert((size_t) k <= nbytes);
106
107 p += k;
108 nbytes -= k;
109 n += k;
110 } while (nbytes > 0);
111
112 return n;
113 }
114
115 int loop_read_exact(int fd, void *buf, size_t nbytes, bool do_poll) {
116 ssize_t n;
117
118 n = loop_read(fd, buf, nbytes, do_poll);
119 if (n < 0)
120 return (int) n;
121 if ((size_t) n != nbytes)
122 return -EIO;
123
124 return 0;
125 }
126
127 int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) {
128 const uint8_t *p = buf;
129
130 assert(fd >= 0);
131 assert(buf);
132
133 if (nbytes > (size_t) SSIZE_MAX)
134 return -EINVAL;
135
136 do {
137 ssize_t k;
138
139 k = write(fd, p, nbytes);
140 if (k < 0) {
141 if (errno == EINTR)
142 continue;
143
144 if (errno == EAGAIN && do_poll) {
145 /* We knowingly ignore any return value here,
146 * and expect that any error/EOF is reported
147 * via write() */
148
149 (void) fd_wait_for_event(fd, POLLOUT, USEC_INFINITY);
150 continue;
151 }
152
153 return -errno;
154 }
155
156 if (_unlikely_(nbytes > 0 && k == 0)) /* Can't really happen */
157 return -EIO;
158
159 assert((size_t) k <= nbytes);
160
161 p += k;
162 nbytes -= k;
163 } while (nbytes > 0);
164
165 return 0;
166 }
167
168 int pipe_eof(int fd) {
169 struct pollfd pollfd = {
170 .fd = fd,
171 .events = POLLIN|POLLHUP,
172 };
173
174 int r;
175
176 r = poll(&pollfd, 1, 0);
177 if (r < 0)
178 return -errno;
179
180 if (r == 0)
181 return 0;
182
183 return pollfd.revents & POLLHUP;
184 }
185
186 int fd_wait_for_event(int fd, int event, usec_t t) {
187
188 struct pollfd pollfd = {
189 .fd = fd,
190 .events = event,
191 };
192
193 struct timespec ts;
194 int r;
195
196 r = ppoll(&pollfd, 1, t == USEC_INFINITY ? NULL : timespec_store(&ts, t), NULL);
197 if (r < 0)
198 return -errno;
199
200 if (r == 0)
201 return 0;
202
203 return pollfd.revents;
204 }
205
206 static size_t nul_length(const uint8_t *p, size_t sz) {
207 size_t n = 0;
208
209 while (sz > 0) {
210 if (*p != 0)
211 break;
212
213 n++;
214 p++;
215 sz--;
216 }
217
218 return n;
219 }
220
221 ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length) {
222 const uint8_t *q, *w, *e;
223 ssize_t l;
224
225 q = w = p;
226 e = q + sz;
227 while (q < e) {
228 size_t n;
229
230 n = nul_length(q, e - q);
231
232 /* If there are more than the specified run length of
233 * NUL bytes, or if this is the beginning or the end
234 * of the buffer, then seek instead of write */
235 if ((n > run_length) ||
236 (n > 0 && q == p) ||
237 (n > 0 && q + n >= e)) {
238 if (q > w) {
239 l = write(fd, w, q - w);
240 if (l < 0)
241 return -errno;
242 if (l != q -w)
243 return -EIO;
244 }
245
246 if (lseek(fd, n, SEEK_CUR) == (off_t) -1)
247 return -errno;
248
249 q += n;
250 w = q;
251 } else if (n > 0)
252 q += n;
253 else
254 q ++;
255 }
256
257 if (q > w) {
258 l = write(fd, w, q - w);
259 if (l < 0)
260 return -errno;
261 if (l != q - w)
262 return -EIO;
263 }
264
265 return q - (const uint8_t*) p;
266 }