]>
Commit | Line | Data |
---|---|---|
a032b68d | 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
bb4f798a MB |
2 | #pragma once |
3 | ||
f2dec872 BR |
4 | #include <stdlib.h> |
5 | #include <string.h> | |
6 | ||
bb4f798a MB |
7 | #include "macro.h" |
8 | ||
9 | static inline void _reset_errno_(int *saved_errno) { | |
10 | if (*saved_errno < 0) /* Invalidated by UNPROTECT_ERRNO? */ | |
11 | return; | |
12 | ||
13 | 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 | 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 | assert_return(errno > 0, -EINVAL); | |
31 | return -errno; | |
32 | } | |
33 | ||
f2dec872 BR |
34 | static inline const char *strerror_safe(int error) { |
35 | /* 'safe' here does NOT mean thread safety. */ | |
8b3d4ff0 | 36 | return strerror(abs(error)); /* lgtm [cpp/potentially-dangerous-function] */ |
f2dec872 BR |
37 | } |
38 | ||
39 | 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 | if (errno > 0) | |
45 | return -errno; | |
46 | ||
47 | return -abs(fallback); | |
48 | } | |
49 | ||
bb4f798a MB |
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 | |
a032b68d MB |
53 | * icmp_err_convert[] in net/ipv4/icmp.c in the kernel sources. |
54 | * | |
55 | * Hint #3: When asynchronous connect() on TCP fails because the host never acknowledges a single packet, | |
56 | * kernel tells us that with ETIMEDOUT, see tcp(7). */ | |
bb4f798a MB |
57 | static inline bool ERRNO_IS_DISCONNECT(int r) { |
58 | return IN_SET(abs(r), | |
59 | ECONNABORTED, | |
60 | ECONNREFUSED, | |
61 | ECONNRESET, | |
62 | EHOSTDOWN, | |
63 | EHOSTUNREACH, | |
64 | ENETDOWN, | |
65 | ENETRESET, | |
66 | ENETUNREACH, | |
67 | ENONET, | |
68 | ENOPROTOOPT, | |
69 | ENOTCONN, | |
70 | EPIPE, | |
71 | EPROTO, | |
a032b68d MB |
72 | ESHUTDOWN, |
73 | ETIMEDOUT); | |
bb4f798a MB |
74 | } |
75 | ||
76 | /* Transient errors we might get on accept() that we should ignore. As per error handling comment in | |
77 | * the accept(2) man page. */ | |
78 | static inline bool ERRNO_IS_ACCEPT_AGAIN(int r) { | |
79 | return ERRNO_IS_DISCONNECT(r) || | |
80 | IN_SET(abs(r), | |
81 | EAGAIN, | |
82 | EINTR, | |
83 | EOPNOTSUPP); | |
84 | } | |
85 | ||
86 | /* Resource exhaustion, could be our fault or general system trouble */ | |
87 | static inline bool ERRNO_IS_RESOURCE(int r) { | |
88 | return IN_SET(abs(r), | |
89 | EMFILE, | |
90 | ENFILE, | |
91 | ENOMEM); | |
92 | } | |
e1f67bc7 | 93 | |
a10f5d05 | 94 | /* Seven different errors for "operation/system call/ioctl/socket feature not supported" */ |
e1f67bc7 MB |
95 | static inline bool ERRNO_IS_NOT_SUPPORTED(int r) { |
96 | return IN_SET(abs(r), | |
97 | EOPNOTSUPP, | |
98 | ENOTTY, | |
a10f5d05 MB |
99 | ENOSYS, |
100 | EAFNOSUPPORT, | |
101 | EPFNOSUPPORT, | |
102 | EPROTONOSUPPORT, | |
103 | ESOCKTNOSUPPORT); | |
e1f67bc7 MB |
104 | } |
105 | ||
106 | /* Two different errors for access problems */ | |
107 | static inline bool ERRNO_IS_PRIVILEGE(int r) { | |
108 | return IN_SET(abs(r), | |
109 | EACCES, | |
110 | EPERM); | |
111 | } | |
46cdbd49 BR |
112 | |
113 | /* Three difference errors for "not enough disk space" */ | |
114 | static inline bool ERRNO_IS_DISK_SPACE(int r) { | |
115 | return IN_SET(abs(r), | |
116 | ENOSPC, | |
117 | EDQUOT, | |
118 | EFBIG); | |
119 | } |