Line data Source code
1 : /* SPDX-License-Identifier: LGPL-2.1+ */ 2 : #pragma once 3 : 4 : #include <stdlib.h> 5 : #include <string.h> 6 : 7 : #include "macro.h" 8 : 9 233757 : static inline void _reset_errno_(int *saved_errno) { 10 233757 : if (*saved_errno < 0) /* Invalidated by UNPROTECT_ERRNO? */ 11 1 : return; 12 : 13 233756 : errno = *saved_errno; 14 : } 15 : 16 : #define PROTECT_ERRNO \ 17 : _cleanup_(_reset_errno_) _unused_ int _saved_errno_ = errno 18 : 19 : #define UNPROTECT_ERRNO \ 20 : do { \ 21 : errno = _saved_errno_; \ 22 : _saved_errno_ = -1; \ 23 : } while (false) 24 : 25 0 : static inline int negative_errno(void) { 26 : /* This helper should be used to shut up gcc if you know 'errno' is 27 : * negative. Instead of "return -errno;", use "return negative_errno();" 28 : * It will suppress bogus gcc warnings in case it assumes 'errno' might 29 : * be 0 and thus the caller's error-handling might not be triggered. */ 30 0 : assert_return(errno > 0, -EINVAL); 31 0 : return -errno; 32 : } 33 : 34 112 : static inline const char *strerror_safe(int error) { 35 : /* 'safe' here does NOT mean thread safety. */ 36 112 : return strerror(abs(error)); 37 : } 38 : 39 141 : static inline int errno_or_else(int fallback) { 40 : /* To be used when invoking library calls where errno handling is not defined clearly: we return 41 : * errno if it is set, and the specified error otherwise. The idea is that the caller initializes 42 : * errno to zero before doing an API call, and then uses this helper to retrieve a somewhat useful 43 : * error code */ 44 141 : if (errno > 0) 45 3 : return -errno; 46 : 47 138 : return -abs(fallback); 48 : } 49 : 50 : /* Hint #1: ENETUNREACH happens if we try to connect to "non-existing" special IP addresses, such as ::5. 51 : * 52 : * Hint #2: The kernel sends e.g., EHOSTUNREACH or ENONET to userspace in some ICMP error cases. See the 53 : * icmp_err_convert[] in net/ipv4/icmp.c in the kernel sources */ 54 305 : static inline bool ERRNO_IS_DISCONNECT(int r) { 55 305 : return IN_SET(abs(r), 56 : ECONNABORTED, 57 : ECONNREFUSED, 58 : ECONNRESET, 59 : EHOSTDOWN, 60 : EHOSTUNREACH, 61 : ENETDOWN, 62 : ENETRESET, 63 : ENETUNREACH, 64 : ENONET, 65 : ENOPROTOOPT, 66 : ENOTCONN, 67 : EPIPE, 68 : EPROTO, 69 : ESHUTDOWN); 70 : } 71 : 72 : /* Transient errors we might get on accept() that we should ignore. As per error handling comment in 73 : * the accept(2) man page. */ 74 0 : static inline bool ERRNO_IS_ACCEPT_AGAIN(int r) { 75 0 : return ERRNO_IS_DISCONNECT(r) || 76 0 : IN_SET(abs(r), 77 : EAGAIN, 78 : EINTR, 79 : EOPNOTSUPP); 80 : } 81 : 82 : /* Resource exhaustion, could be our fault or general system trouble */ 83 82 : static inline bool ERRNO_IS_RESOURCE(int r) { 84 82 : return IN_SET(abs(r), 85 : EMFILE, 86 : ENFILE, 87 : ENOMEM); 88 : }