1const TMP_BUF_SZ: usize = 128;
6
7extern "C" {
8 #[cfg_attr(
9 any(
10 target_os = "linux",
11 target_os = "emscripten",
12 target_os = "fuchsia",
13 target_os = "l4re"
14 ),
15 link_name = "__errno_location"
16 )]
17 #[cfg_attr(
18 any(
19 target_os = "netbsd",
20 target_os = "openbsd",
21 target_os = "android",
22 target_os = "redox",
23 target_env = "newlib"
24 ),
25 link_name = "__errno"
26 )]
27 #[cfg_attr(
28 any(target_os = "solaris", target_os = "illumos"),
29 link_name = "___errno"
30 )]
31 #[cfg_attr(
32 any(target_os = "macos", target_os = "ios", target_os = "freebsd"),
33 link_name = "__error"
34 )]
35 #[cfg_attr(target_os = "haiku", link_name = "_errnop")]
36 fn errno_location() -> *mut libc::c_int;
37
38 #[cfg_attr(
39 any(target_os = "linux", target_env = "newlib"),
40 link_name = "__xpg_strerror_r"
41 )]
42 fn strerror_r(errnum: libc::c_int, buf: *mut libc::c_char, buflen: libc::size_t)
43 -> libc::c_int;
44}
45
46#[allow(private_doc_tests)]
47#[inline]
56pub fn get_errno() -> i32 { unsafe { *errno_location() } }
57
58#[allow(private_doc_tests)]
59#[inline]
68pub fn set_errno(errno: i32) { unsafe { *errno_location() = errno } }
69
70#[allow(private_doc_tests)]
71#[inline]
80pub fn clear_errno() { set_errno(0); }
81
82#[allow(private_doc_tests)]
83#[inline]
97pub fn describe_errno(errno: i32) -> std::io::Result<String> {
98 let mut buf: [libc::c_char; TMP_BUF_SZ] = [0; TMP_BUF_SZ];
99
100 unsafe {
101 if strerror_r(errno, buf.as_mut_ptr(), buf.len()) < 0 {
102 let e = get_errno();
103 if e != libc::ERANGE {
104 return Err(std::io::Error::from_raw_os_error(e));
105 }
106 }
107 Ok(
108 std::str::from_utf8(std::ffi::CStr::from_ptr(buf.as_ptr()).to_bytes())
109 .unwrap()
110 .to_owned(),
111 )
112 }
113}
114
115#[cfg(test)]
116mod test {
117 use super::*;
118
119 #[test]
121 fn set_get_errno() {
122 (-1..134).for_each(|err_code| {
123 set_errno(err_code);
124 assert_eq!(err_code, get_errno());
125 });
126 clear_errno();
127 }
128
129 #[test]
131 fn error_string() {
132 (1..134).for_each(|err_code| {
133 let err_string = describe_errno(err_code).unwrap();
134 let os_err = std::io::Error::from_raw_os_error(err_code);
135 assert_eq!(
136 format!("{} (os error {})", err_string, err_code),
137 format!("{}", os_err)
138 );
139 })
140 }
141}