1 | //! Implementation of `errno` functionality for Unix systems. |
2 | //! |
3 | //! Adapted from `src/libstd/sys/unix/os.rs` in the Rust distribution. |
4 | |
5 | // Copyright 2015 The Rust Project Developers. See the COPYRIGHT |
6 | // file at the top-level directory of this distribution and at |
7 | // http://rust-lang.org/COPYRIGHT. |
8 | // |
9 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or |
10 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license |
11 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your |
12 | // option. This file may not be copied, modified, or distributed |
13 | // except according to those terms. |
14 | |
15 | use core::str; |
16 | use libc::{self, c_int, size_t, strerror_r, strlen}; |
17 | |
18 | use crate::Errno; |
19 | |
20 | fn from_utf8_lossy(input: &[u8]) -> &str { |
21 | match str::from_utf8(input) { |
22 | Ok(valid: &str) => valid, |
23 | Err(error: Utf8Error) => unsafe { str::from_utf8_unchecked(&input[..error.valid_up_to()]) }, |
24 | } |
25 | } |
26 | |
27 | pub fn with_description<F, T>(err: Errno, callback: F) -> T |
28 | where |
29 | F: FnOnce(Result<&str, Errno>) -> T, |
30 | { |
31 | let mut buf: [u8; 1024] = [0u8; 1024]; |
32 | let c_str: &[u8] = unsafe { |
33 | let rc: i32 = strerror_r(errnum:err.0, buf.as_mut_ptr() as *mut _, buflen:buf.len() as size_t); |
34 | if rc != 0 { |
35 | // Handle negative return codes for compatibility with glibc < 2.13 |
36 | let fm_err: Errno = match rc < 0 { |
37 | true => errno(), |
38 | false => Errno(rc), |
39 | }; |
40 | if fm_err != Errno(libc::ERANGE) { |
41 | return callback(Err(fm_err)); |
42 | } |
43 | } |
44 | let c_str_len: usize = strlen(cs:buf.as_ptr() as *const _); |
45 | &buf[..c_str_len] |
46 | }; |
47 | callback(Ok(from_utf8_lossy(input:c_str))) |
48 | } |
49 | |
50 | pub const STRERROR_NAME: &str = "strerror_r" ; |
51 | |
52 | pub fn errno() -> Errno { |
53 | unsafe { Errno(*errno_location()) } |
54 | } |
55 | |
56 | pub fn set_errno(Errno(errno: i32): Errno) { |
57 | unsafe { |
58 | *errno_location() = errno; |
59 | } |
60 | } |
61 | |
62 | unsafeextern "C" { |
63 | #[cfg_attr ( |
64 | any( |
65 | target_os = "macos" , |
66 | target_os = "ios" , |
67 | target_os = "tvos" , |
68 | target_os = "watchos" , |
69 | target_os = "visionos" , |
70 | target_os = "freebsd" |
71 | ), |
72 | link_name = "__error" |
73 | )] |
74 | #[cfg_attr ( |
75 | any( |
76 | target_os = "openbsd" , |
77 | target_os = "netbsd" , |
78 | target_os = "android" , |
79 | target_os = "espidf" , |
80 | target_os = "vxworks" , |
81 | target_os = "cygwin" , |
82 | target_env = "newlib" |
83 | ), |
84 | link_name = "__errno" |
85 | )] |
86 | #[cfg_attr ( |
87 | any(target_os = "solaris" , target_os = "illumos" ), |
88 | link_name = "___errno" |
89 | )] |
90 | #[cfg_attr (target_os = "haiku" , link_name = "_errnop" )] |
91 | #[cfg_attr ( |
92 | any( |
93 | target_os = "linux" , |
94 | target_os = "hurd" , |
95 | target_os = "redox" , |
96 | target_os = "dragonfly" , |
97 | target_os = "emscripten" , |
98 | ), |
99 | link_name = "__errno_location" |
100 | )] |
101 | #[cfg_attr (target_os = "aix" , link_name = "_Errno" )] |
102 | #[cfg_attr (target_os = "nto" , link_name = "__get_errno_ptr" )] |
103 | unsafefn errno_location() -> *mut c_int; |
104 | } |
105 | |