| 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_env = "newlib" |
| 81 | ), |
| 82 | link_name = "__errno" |
| 83 | )] |
| 84 | #[cfg_attr ( |
| 85 | any(target_os = "solaris" , target_os = "illumos" ), |
| 86 | link_name = "___errno" |
| 87 | )] |
| 88 | #[cfg_attr (target_os = "haiku" , link_name = "_errnop" )] |
| 89 | #[cfg_attr ( |
| 90 | any( |
| 91 | target_os = "linux" , |
| 92 | target_os = "hurd" , |
| 93 | target_os = "redox" , |
| 94 | target_os = "dragonfly" , |
| 95 | target_os = "emscripten" , |
| 96 | ), |
| 97 | link_name = "__errno_location" |
| 98 | )] |
| 99 | #[cfg_attr (target_os = "aix" , link_name = "_Errno" )] |
| 100 | #[cfg_attr (target_os = "nto" , link_name = "__get_errno_ptr" )] |
| 101 | unsafefn errno_location() -> *mut c_int; |
| 102 | } |
| 103 | |