Skip to main content

std/sys/io/error/
unix.rs

1use crate::ffi::c_int;
2#[cfg(not(target_os = "teeos"))]
3use crate::ffi::{CStr, c_char};
4use crate::{fmt, io};
5
6unsafe extern "C" {
7    #[cfg(not(any(
8        target_os = "dragonfly",
9        target_os = "vxworks",
10        target_os = "rtems",
11        target_os = "wasi"
12    )))]
13    #[cfg_attr(
14        any(
15            target_os = "linux",
16            target_os = "emscripten",
17            target_os = "fuchsia",
18            target_os = "l4re",
19            target_os = "hurd",
20            target_os = "teeos",
21        ),
22        link_name = "__errno_location"
23    )]
24    #[cfg_attr(
25        any(
26            target_os = "netbsd",
27            target_os = "openbsd",
28            target_os = "cygwin",
29            target_os = "android",
30            target_os = "redox",
31            target_os = "nuttx",
32            target_env = "newlib"
33        ),
34        link_name = "__errno"
35    )]
36    #[cfg_attr(any(target_os = "solaris", target_os = "illumos"), link_name = "___errno")]
37    #[cfg_attr(target_os = "nto", link_name = "__get_errno_ptr")]
38    #[cfg_attr(target_os = "qnx", link_name = "__get_errno_ptr")]
39    #[cfg_attr(any(target_os = "freebsd", target_vendor = "apple"), link_name = "__error")]
40    #[cfg_attr(target_os = "haiku", link_name = "_errnop")]
41    #[cfg_attr(target_os = "aix", link_name = "_Errno")]
42    // SAFETY: this will always return the same pointer on a given thread.
43    #[unsafe(ffi_const)]
44    pub safe fn errno_location() -> *mut c_int;
45}
46
47/// Returns the platform-specific value of errno
48#[cfg(not(any(
49    target_os = "dragonfly",
50    target_os = "vxworks",
51    target_os = "rtems",
52    target_os = "wasi"
53)))]
54#[inline]
55pub fn errno() -> i32 {
56    unsafe { (*errno_location()) as i32 }
57}
58
59/// Sets the platform-specific value of errno
60// needed for readdir and syscall!
61#[cfg(not(any(
62    target_os = "dragonfly",
63    target_os = "espidf",
64    target_os = "lynxos178",
65    target_os = "qurt",
66    target_os = "rtems",
67    target_os = "vxworks",
68    target_os = "wasi",
69)))]
70#[inline]
71pub fn set_errno(e: i32) {
72    unsafe { *errno_location() = e as c_int }
73}
74
75#[cfg(target_os = "vxworks")]
76#[inline]
77pub fn errno() -> i32 {
78    unsafe { libc::errnoGet() }
79}
80
81#[cfg(target_os = "rtems")]
82#[inline]
83pub fn errno() -> i32 {
84    unsafe extern "C" {
85        #[thread_local]
86        static _tls_errno: c_int;
87    }
88
89    unsafe { _tls_errno as i32 }
90}
91
92#[cfg(target_os = "dragonfly")]
93#[inline]
94pub fn errno() -> i32 {
95    unsafe extern "C" {
96        #[thread_local]
97        static mut errno: c_int;
98    }
99
100    unsafe { errno as i32 }
101}
102
103#[cfg(target_os = "dragonfly")]
104#[inline]
105pub fn set_errno(e: i32) {
106    unsafe extern "C" {
107        #[thread_local]
108        static mut errno: c_int;
109    }
110
111    unsafe { errno = e };
112}
113
114#[cfg(target_os = "wasi")]
115unsafe extern "C" {
116    #[thread_local]
117    #[link_name = "errno"]
118    static mut libc_errno: libc::c_int;
119}
120
121#[cfg(target_os = "wasi")]
122pub fn errno() -> i32 {
123    unsafe { libc_errno as i32 }
124}
125
126#[cfg(target_os = "wasi")]
127pub fn set_errno(val: i32) {
128    unsafe {
129        libc_errno = val;
130    }
131}
132
133#[inline]
134pub fn is_interrupted(errno: i32) -> bool {
135    errno == libc::EINTR
136}
137
138pub fn decode_error_kind(errno: i32) -> io::ErrorKind {
139    use io::ErrorKind::*;
140    match errno as libc::c_int {
141        libc::E2BIG => ArgumentListTooLong,
142        libc::EADDRINUSE => AddrInUse,
143        libc::EADDRNOTAVAIL => AddrNotAvailable,
144        libc::EBUSY => ResourceBusy,
145        libc::ECONNABORTED => ConnectionAborted,
146        libc::ECONNREFUSED => ConnectionRefused,
147        libc::ECONNRESET => ConnectionReset,
148        libc::EDEADLK => Deadlock,
149        libc::EDQUOT => QuotaExceeded,
150        libc::EEXIST => AlreadyExists,
151        libc::EFBIG => FileTooLarge,
152        libc::EHOSTUNREACH => HostUnreachable,
153        libc::EINTR => Interrupted,
154        libc::EINVAL => InvalidInput,
155        libc::EISDIR => IsADirectory,
156        libc::ELOOP => FilesystemLoop,
157        libc::ENOENT => NotFound,
158        libc::ENOMEM => OutOfMemory,
159        libc::ENOSPC => StorageFull,
160        libc::EMLINK => TooManyLinks,
161        libc::ENAMETOOLONG => InvalidFilename,
162        libc::ENETDOWN => NetworkDown,
163        libc::ENETUNREACH => NetworkUnreachable,
164        libc::ENOTCONN => NotConnected,
165        libc::ENOTDIR => NotADirectory,
166        #[cfg(not(target_os = "aix"))]
167        libc::ENOTEMPTY => DirectoryNotEmpty,
168        libc::EPIPE => BrokenPipe,
169        libc::EROFS => ReadOnlyFilesystem,
170        libc::ESPIPE => NotSeekable,
171        libc::ESTALE => StaleNetworkFileHandle,
172        libc::ETIMEDOUT => TimedOut,
173        libc::ETXTBSY => ExecutableFileBusy,
174        libc::EXDEV => CrossesDevices,
175        libc::EINPROGRESS => InProgress,
176        libc::EMFILE | libc::ENFILE => TooManyOpenFiles,
177        libc::EIO => InputOutputError,
178
179        libc::EACCES | libc::EPERM => PermissionDenied,
180
181        libc::ENOSYS => Unsupported,
182        // EOPNOTSUPP and ENOTSUP can have the same value on some systems,
183        // but different values on others (e.g. Apple), so we can't use a
184        // match clause
185        x if x == libc::EOPNOTSUPP || x == libc::ENOTSUP => Unsupported,
186
187        // These two constants can have the same value on some systems,
188        // but different values on others, so we can't use a match
189        // clause
190        x if x == libc::EAGAIN || x == libc::EWOULDBLOCK => WouldBlock,
191
192        _ => Uncategorized,
193    }
194}
195
196/// Gets a detailed string description for the given error number.
197#[cfg(any(target_family = "unix", target_os = "wasi"))]
198pub fn format_error(errno: i32, f: &mut fmt::Formatter<'_>) -> fmt::Result {
199    const TMPBUF_SZ: usize = if falsecfg!(target_os = "wasi") { 1024 } else { 128 };
200
201    unsafe extern "C" {
202        #[cfg_attr(
203            all(
204                any(
205                    target_os = "linux",
206                    target_os = "hurd",
207                    target_env = "newlib",
208                    target_os = "cygwin",
209                    target_env = "uclibc",
210                ),
211                not(target_env = "ohos")
212            ),
213            link_name = "__xpg_strerror_r"
214        )]
215        fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: libc::size_t) -> c_int;
216    }
217
218    let mut buf = [0 as c_char; TMPBUF_SZ];
219
220    let p = buf.as_mut_ptr();
221    unsafe {
222        if strerror_r(errno as c_int, p, buf.len()) < 0 {
223            { ::core::panicking::panic_fmt(format_args!("strerror_r failure")); };panic!("strerror_r failure");
224        }
225
226        let p = p as *const _;
227        // We can't always expect a UTF-8 environment. When we don't get that luxury,
228        // it's better to give a low-quality error message than none at all.
229        f.write_fmt(format_args!("{0}", CStr::from_ptr(p).display()))write!(f, "{}", CStr::from_ptr(p).display())
230    }
231}
232
233#[cfg(target_os = "teeos")]
234pub fn format_error(_errno: i32, f: &mut fmt::Formatter<'_>) -> fmt::Result {
235    f.write_str("error string unimplemented")
236}