const TMP_BUF_SZ: usize = 1024;
extern "C" {
#[thread_local]
#[link_name = "errno"]
static mut libc_errno: libc::c_int;
fn strerror_r(errnum: libc::c_int, buf: *mut libc::c_char, buflen: libc::size_t) -> c_int;
}
#[allow(private_doc_tests)]
#[inline]
pub fn get_errno() -> i32 { unsafe { libc_errno } }
#[allow(private_doc_tests)]
#[inline]
pub fn set_errno(errno: i32) {
unsafe {
libc_errno = errno;
}
}
#[allow(private_doc_tests)]
#[inline]
pub fn clear_errno() { set_errno(0); }
#[allow(private_doc_tests)]
#[inline]
pub fn describe_errno(errno: i32) -> std::io::Result<String> {
let mut buf: [libc::c_char; TMP_BUF_SZ] = [0; TMP_BUF_SZ];
unsafe {
if strerror_r(errno, buf.as_mut_ptr(), buf.len()) < 0 {
let e = get_errno();
if e != libc::ERANGE {
return Err(std::io::Error::from_raw_os_error(e));
}
}
Ok(
std::str::from_utf8(std::ffi::CStr::from_ptr(buf.as_ptr()).to_bytes())
.unwrap()
.to_owned(),
)
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn set_get_errno() {
(-1..134).for_each(|err_code| {
set_errno(err_code);
assert_eq!(err_code, get_errno());
});
clear_errno();
}
#[test]
fn error_string() {
(1..134).for_each(|err_code| {
let err_string = describe_errno(err_code).unwrap();
let os_err = std::io::Error::from_raw_os_error(err_code);
assert_eq!(
format!("{} (os error {})", err_string, err_code),
format!("{}", os_err)
);
})
}
}