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