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