/* * Copyright © 2020 Red Hat, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #pragma once #include "config.h" #include #include #include #include #include #include #include #include #include "util-strings.h" #include "util-mem.h" /** * Wrapper to convert an errno-setting syscall into a * value-or-negative-errno. * * Use: int rc = xerrno(foo(bar)); */ static inline int xerrno(int value) { return value < 0 ? -errno : value; } /** * Wrapper around close(). It checks for fd != -1 to satisfy coverity and * friends and always returns -1. */ static inline int xclose(int fd) { if (fd != -1) close(fd); return -1; } DEFINE_TRIVIAL_CLEANUP_FUNC(int, xclose); #define _cleanup_close_ _cleanup_(xclosep) DEFINE_TRIVIAL_CLEANUP_FUNC(FILE *, fclose); #define _cleanup_fclose_ _cleanup_(fclosep) /** * Wrapper around read(). Returns the number of bytes read or a negative * errno on failure. */ static inline int xread(int fd, void *buf, size_t count) { return xerrno(read(fd, buf, count)); } /** * Wrapper around read(). Returns the number of bytes read or a negative * errno on failure. Any fds passed along with the message * are stored in the -1-terminated allocated fds array, to be freed by the * caller. Where no fds were passed, the array is NULL. */ int xread_with_fds(int fd, void *buf, size_t count, int **fds); /** * Wrapper around write(). Returns the number of bytes written or a negative * errno on failure. */ static inline int xwrite(int fd, const void *buf, size_t count) { return xerrno(write(fd, buf, count)); } /** * Wrapper around send() that always sets MSG_NOSIGNAL. Returns the number * of bytes written or a negative errno on failure. */ static inline int xsend(int fd, const void *buf, size_t len) { return xerrno(send(fd, buf, len, MSG_NOSIGNAL)); } /** * Wrapper around send() that always sets MSG_NOSIGNAL and allows appending * file descriptors to the message. * * @param fds Array of file descriptors, terminated by -1. */ int xsend_with_fd(int fd, const void *buf, size_t len, int *fds); /** * Connect to the socket in the given path. Returns an fd or a negative * errno on failure. */ static inline int xconnect(const char *path) { struct sockaddr_un addr = { .sun_family = AF_UNIX, .sun_path = {0}, }; if (!xsnprintf(addr.sun_path, sizeof(addr.sun_path), "%s", path)) return -EINVAL; int sockfd = socket(AF_UNIX, SOCK_STREAM|SOCK_NONBLOCK, 0); if (sockfd == -1) return -errno; if (connect(sockfd, (struct sockaddr*)&addr, sizeof(addr)) == -1) return -errno; return sockfd; } /** * Create a new iobuf structure with the given size. */ struct iobuf * iobuf_new(size_t size); /** * The count of data bytes in this buffer. */ size_t iobuf_len(struct iobuf *buf); /** * Pointer to the data bytes. Note that the buffer is considered binary * data. The caller must ensure that any strings stored in the buffer are * null-terminated. * * The returned pointer only valid in the immediate scope, any iobuf * function may invalidate the pointer. */ const char * iobuf_data(struct iobuf *buf); /** * Return the next available file descriptor in this buffer or -1. * The fd is removed from this buffer and belongs to the caller. */ int iobuf_take_fd(struct iobuf *buf); /** * Remove the data bytes from the buffer. The caller must free() the data. * The buffer state is the same as iobuf_new() after this call. */ char * iobuf_take_data(struct iobuf *buf); /** * Append len bytes to the buffer. If the data exceeds the current buffer * size it is resized automatically. */ void iobuf_append(struct iobuf *buf, const char *data, size_t len); /** * Append all available data from the file descriptor to the pointer. The * file descriptor shold be in O_NONBLOCK or this call will block. If the * data exceeds the current buffer size it is resized automatically. * * @return The number of bytes read or a negative errno on failure. Zero * indicates EOF. */ int iobuf_append_from_fd(struct iobuf *buf, int fd); /** * Append all available data from the file descriptor to the pointer. The * file descriptor shold be in O_NONBLOCK or this call will block. If the * data exceeds the current buffer size it is resized automatically. * * Any file descriptors passed through the fd are placed * * @return The number of bytes read or a negative errno on failure. Zero * indicates EOF. */ int iobuf_recv_from_fd(struct iobuf *buf, int fd); /** * Release the memory associated with this iobuf. Use iobuf_take_data() * prevent the data from being free()d. */ struct iobuf * iobuf_free(struct iobuf *buf); static inline void _iobuf_cleanup(struct iobuf **buf) { iobuf_free(*buf); } /** * Helper macro to auto-free a iobuf struct when the variable goes out of * scope. Use like this: * _cleanup_iobuf_ struct iobuf *foo = iobuf_new(64); */ #define _cleanup_iobuf_ __attribute__((cleanup(_iobuf_cleanup)))