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::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 = "vxworks",
64    target_os = "rtems",
65    target_os = "wasi",
66)))]
67#[allow(dead_code)] // but not all target cfgs actually end up using it
68#[inline]
69pub fn set_errno(e: i32) {
70    unsafe { *errno_location() = e as c_int }
71}
72
73#[cfg(target_os = "vxworks")]
74#[inline]
75pub fn errno() -> i32 {
76    unsafe { libc::errnoGet() }
77}
78
79#[cfg(target_os = "rtems")]
80#[inline]
81pub fn errno() -> i32 {
82    unsafe extern "C" {
83        #[thread_local]
84        static _tls_errno: c_int;
85    }
86
87    unsafe { _tls_errno as i32 }
88}
89
90#[cfg(target_os = "dragonfly")]
91#[inline]
92pub fn errno() -> i32 {
93    unsafe extern "C" {
94        #[thread_local]
95        static errno: c_int;
96    }
97
98    unsafe { errno as i32 }
99}
100
101#[cfg(target_os = "dragonfly")]
102#[allow(dead_code)]
103#[inline]
104pub fn set_errno(e: i32) {
105    unsafe extern "C" {
106        #[thread_local]
107        static mut errno: c_int;
108    }
109
110    unsafe {
111        errno = e;
112    }
113}
114
115#[cfg(target_os = "wasi")]
116unsafe extern "C" {
117    #[thread_local]
118    #[link_name = "errno"]
119    static mut libc_errno: libc::c_int;
120}
121
122#[cfg(target_os = "wasi")]
123pub fn errno() -> i32 {
124    unsafe { libc_errno as i32 }
125}
126
127#[cfg(target_os = "wasi")]
128pub fn set_errno(val: i32) {
129    unsafe {
130        libc_errno = val;
131    }
132}
133
134#[inline]
135pub fn is_interrupted(errno: i32) -> bool {
136    errno == libc::EINTR
137}
138
139pub fn decode_error_kind(errno: i32) -> io::ErrorKind {
140    use io::ErrorKind::*;
141    match errno as libc::c_int {
142        libc::E2BIG => ArgumentListTooLong,
143        libc::EADDRINUSE => AddrInUse,
144        libc::EADDRNOTAVAIL => AddrNotAvailable,
145        libc::EBUSY => ResourceBusy,
146        libc::ECONNABORTED => ConnectionAborted,
147        libc::ECONNREFUSED => ConnectionRefused,
148        libc::ECONNRESET => ConnectionReset,
149        libc::EDEADLK => Deadlock,
150        libc::EDQUOT => QuotaExceeded,
151        libc::EEXIST => AlreadyExists,
152        libc::EFBIG => FileTooLarge,
153        libc::EHOSTUNREACH => HostUnreachable,
154        libc::EINTR => Interrupted,
155        libc::EINVAL => InvalidInput,
156        libc::EISDIR => IsADirectory,
157        libc::ELOOP => FilesystemLoop,
158        libc::ENOENT => NotFound,
159        libc::ENOMEM => OutOfMemory,
160        libc::ENOSPC => StorageFull,
161        libc::ENOSYS => Unsupported,
162        libc::EMLINK => TooManyLinks,
163        libc::ENAMETOOLONG => InvalidFilename,
164        libc::ENETDOWN => NetworkDown,
165        libc::ENETUNREACH => NetworkUnreachable,
166        libc::ENOTCONN => NotConnected,
167        libc::ENOTDIR => NotADirectory,
168        #[cfg(not(target_os = "aix"))]
169        libc::ENOTEMPTY => DirectoryNotEmpty,
170        libc::EPIPE => BrokenPipe,
171        libc::EROFS => ReadOnlyFilesystem,
172        libc::ESPIPE => NotSeekable,
173        libc::ESTALE => StaleNetworkFileHandle,
174        libc::ETIMEDOUT => TimedOut,
175        libc::ETXTBSY => ExecutableFileBusy,
176        libc::EXDEV => CrossesDevices,
177        libc::EINPROGRESS => InProgress,
178        libc::EMFILE | libc::ENFILE => TooManyOpenFiles,
179        libc::EOPNOTSUPP => Unsupported,
180        libc::EIO => InputOutputError,
181
182        libc::EACCES | libc::EPERM => PermissionDenied,
183
184        // These two constants can have the same value on some systems,
185        // but different values on others, so we can't use a match
186        // clause
187        x if x == libc::EAGAIN || x == libc::EWOULDBLOCK => WouldBlock,
188
189        _ => Uncategorized,
190    }
191}
192
193/// Gets a detailed string description for the given error number.
194#[cfg(any(target_family = "unix", target_os = "wasi"))]
195pub fn error_string(errno: i32) -> String {
196    const TMPBUF_SZ: usize = if falsecfg!(target_os = "wasi") { 1024 } else { 128 };
197
198    unsafe extern "C" {
199        #[cfg_attr(
200            all(
201                any(
202                    target_os = "linux",
203                    target_os = "hurd",
204                    target_env = "newlib",
205                    target_os = "cygwin"
206                ),
207                not(target_env = "ohos")
208            ),
209            link_name = "__xpg_strerror_r"
210        )]
211        fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: libc::size_t) -> c_int;
212    }
213
214    let mut buf = [0 as c_char; TMPBUF_SZ];
215
216    let p = buf.as_mut_ptr();
217    unsafe {
218        if strerror_r(errno as c_int, p, buf.len()) < 0 {
219            { ::core::panicking::panic_fmt(format_args!("strerror_r failure")); };panic!("strerror_r failure");
220        }
221
222        let p = p as *const _;
223        // We can't always expect a UTF-8 environment. When we don't get that luxury,
224        // it's better to give a low-quality error message than none at all.
225        String::from_utf8_lossy(CStr::from_ptr(p).to_bytes()).into()
226    }
227}
228
229#[cfg(target_os = "teeos")]
230pub fn error_string(_errno: i32) -> String {
231    "error string unimplemented".to_string()
232}