]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/io-util.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
9 #include "string-util.h"
10 #include "time-util.h"
12 int flush_fd(int fd
) {
15 /* Read from the specified file descriptor, until POLLIN is not set anymore, throwing away everything
16 * read. Note that some file descriptors (notable IP sockets) will trigger POLLIN even when no data can be read
17 * (due to IP packet checksum mismatches), hence this function is only safe to be non-blocking if the fd used
18 * was set to non-blocking too. */
25 r
= fd_wait_for_event(fd
, POLLIN
, 0);
35 l
= read(fd
, buf
, sizeof(buf
));
51 ssize_t
loop_read(int fd
, void *buf
, size_t nbytes
, bool do_poll
) {
52 uint8_t *p
= ASSERT_PTR(buf
);
57 /* If called with nbytes == 0, let's call read() at least once, to validate the operation */
59 if (nbytes
> (size_t) SSIZE_MAX
)
65 k
= read(fd
, p
, nbytes
);
70 if (errno
== EAGAIN
&& do_poll
) {
72 /* We knowingly ignore any return value here,
73 * and expect that any error/EOF is reported
76 (void) fd_wait_for_event(fd
, POLLIN
, USEC_INFINITY
);
80 return n
> 0 ? n
: -errno
;
86 assert((size_t) k
<= nbytes
);
96 int loop_read_exact(int fd
, void *buf
, size_t nbytes
, bool do_poll
) {
99 n
= loop_read(fd
, buf
, nbytes
, do_poll
);
102 if ((size_t) n
!= nbytes
)
108 int loop_write(int fd
, const void *buf
, size_t nbytes
, bool do_poll
) {
114 static const dummy_t dummy
[0];
115 assert_cc(sizeof(dummy
) == 0);
116 p
= (const void*) dummy
; /* Some valid pointer, in case NULL was specified */
120 if (nbytes
== SIZE_MAX
)
121 nbytes
= strlen(buf
);
122 else if (_unlikely_(nbytes
> (size_t) SSIZE_MAX
))
131 k
= write(fd
, p
, nbytes
);
136 if (errno
== EAGAIN
&& do_poll
) {
137 /* We knowingly ignore any return value here,
138 * and expect that any error/EOF is reported
141 (void) fd_wait_for_event(fd
, POLLOUT
, USEC_INFINITY
);
148 if (_unlikely_(nbytes
> 0 && k
== 0)) /* Can't really happen */
151 assert((size_t) k
<= nbytes
);
155 } while (nbytes
> 0);
160 int pipe_eof(int fd
) {
163 r
= fd_wait_for_event(fd
, POLLIN
, 0);
167 return !!(r
& POLLHUP
);
170 int ppoll_usec(struct pollfd
*fds
, size_t nfds
, usec_t timeout
) {
173 assert(fds
|| nfds
== 0);
175 /* This is a wrapper around ppoll() that does primarily two things:
177 * ✅ Takes a usec_t instead of a struct timespec
179 * ✅ Guarantees that if an invalid fd is specified we return EBADF (i.e. converts POLLNVAL to
180 * EBADF). This is done because EBADF is a programming error usually, and hence should bubble up
181 * as error, and not be eaten up as non-error POLLNVAL event.
183 * ⚠️ ⚠️ ⚠️ Note that this function does not add any special handling for EINTR. Don't forget
184 * poll()/ppoll() will return with EINTR on any received signal always, there is no automatic
185 * restarting via SA_RESTART available. Thus, typically you want to handle EINTR not as an error,
186 * but just as reason to restart things, under the assumption you use a more appropriate mechanism
187 * to handle signals, such as signalfd() or signal handlers. ⚠️ ⚠️ ⚠️
193 r
= ppoll(fds
, nfds
, timeout
== USEC_INFINITY
? NULL
: TIMESPEC_STORE(timeout
), NULL
);
199 for (size_t i
= 0, n
= r
; i
< nfds
&& n
> 0; i
++) {
200 if (fds
[i
].revents
== 0)
202 if (fds
[i
].revents
& POLLNVAL
)
210 int fd_wait_for_event(int fd
, int event
, usec_t timeout
) {
211 struct pollfd pollfd
= {
217 /* ⚠️ ⚠️ ⚠️ Keep in mind you almost certainly want to handle -EINTR gracefully in the caller, see
218 * ppoll_usec() above! ⚠️ ⚠️ ⚠️ */
220 r
= ppoll_usec(&pollfd
, 1, timeout
);
224 return pollfd
.revents
;
227 static size_t nul_length(const uint8_t *p
, size_t sz
) {
242 ssize_t
sparse_write(int fd
, const void *p
, size_t sz
, size_t run_length
) {
243 const uint8_t *q
, *w
, *e
;
251 n
= nul_length(q
, e
- q
);
253 /* If there are more than the specified run length of
254 * NUL bytes, or if this is the beginning or the end
255 * of the buffer, then seek instead of write */
256 if ((n
> run_length
) ||
258 (n
> 0 && q
+ n
>= e
)) {
260 l
= write(fd
, w
, q
- w
);
267 if (lseek(fd
, n
, SEEK_CUR
) == (off_t
) -1)
279 l
= write(fd
, w
, q
- w
);
286 return q
- (const uint8_t*) p
;
289 char* set_iovec_string_field(struct iovec
*iovec
, size_t *n_iovec
, const char *field
, const char *value
) {
292 x
= strjoin(field
, value
);
294 iovec
[(*n_iovec
)++] = IOVEC_MAKE_STRING(x
);
298 char* set_iovec_string_field_free(struct iovec
*iovec
, size_t *n_iovec
, const char *field
, char *value
) {
301 x
= set_iovec_string_field(iovec
, n_iovec
, field
, value
);
306 struct iovec_wrapper
*iovw_new(void) {
307 return malloc0(sizeof(struct iovec_wrapper
));
310 void iovw_free_contents(struct iovec_wrapper
*iovw
, bool free_vectors
) {
312 for (size_t i
= 0; i
< iovw
->count
; i
++)
313 free(iovw
->iovec
[i
].iov_base
);
315 iovw
->iovec
= mfree(iovw
->iovec
);
319 struct iovec_wrapper
*iovw_free_free(struct iovec_wrapper
*iovw
) {
320 iovw_free_contents(iovw
, true);
325 struct iovec_wrapper
*iovw_free(struct iovec_wrapper
*iovw
) {
326 iovw_free_contents(iovw
, false);
331 int iovw_put(struct iovec_wrapper
*iovw
, void *data
, size_t len
) {
332 if (iovw
->count
>= IOV_MAX
)
335 if (!GREEDY_REALLOC(iovw
->iovec
, iovw
->count
+ 1))
338 iovw
->iovec
[iovw
->count
++] = IOVEC_MAKE(data
, len
);
342 int iovw_put_string_field(struct iovec_wrapper
*iovw
, const char *field
, const char *value
) {
343 _cleanup_free_
char *x
= NULL
;
346 x
= strjoin(field
, value
);
350 r
= iovw_put(iovw
, x
, strlen(x
));
357 int iovw_put_string_field_free(struct iovec_wrapper
*iovw
, const char *field
, char *value
) {
358 _cleanup_free_ _unused_
char *free_ptr
= value
;
360 return iovw_put_string_field(iovw
, field
, value
);
363 void iovw_rebase(struct iovec_wrapper
*iovw
, char *old
, char *new) {
364 for (size_t i
= 0; i
< iovw
->count
; i
++)
365 iovw
->iovec
[i
].iov_base
= (char *)iovw
->iovec
[i
].iov_base
- old
+ new;
368 size_t iovw_size(struct iovec_wrapper
*iovw
) {
371 for (size_t i
= 0; i
< iovw
->count
; i
++)
372 n
+= iovw
->iovec
[i
].iov_len
;
377 void iovec_array_free(struct iovec
*iov
, size_t n
) {
381 for (size_t i
= 0; i
< n
; i
++)
382 free(iov
[i
].iov_base
);