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) => valid, |
23 | Err(error) => 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 = [0u8; 1024]; |
32 | let c_str = unsafe { |
33 | let rc = strerror_r(err.0, buf.as_mut_ptr() as *mut _, buf.len() as size_t); |
34 | if rc != 0 { |
35 | // Handle negative return codes for compatibility with glibc < 2.13 |
36 | let fm_err = 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 = strlen(buf.as_ptr() as *const _); |
45 | &buf[..c_str_len] |
46 | }; |
47 | callback(Ok(from_utf8_lossy(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): Errno) { |
57 | unsafe { |
58 | *errno_location() = errno; |
59 | } |
60 | } |
61 | |
62 | extern "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 = "freebsd" |
70 | ), |
71 | link_name = "__error" |
72 | )] |
73 | #[cfg_attr ( |
74 | any( |
75 | target_os = "openbsd" , |
76 | target_os = "netbsd" , |
77 | target_os = "bitrig" , |
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 | ), |
96 | link_name = "__errno_location" |
97 | )] |
98 | #[cfg_attr (target_os = "aix" , link_name = "_Errno" )] |
99 | #[cfg_attr (target_os = "nto" , link_name = "__get_errno_ptr" )] |
100 | fn errno_location() -> *mut c_int; |
101 | } |
102 | |