errno/
unix.rs

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
15use core::str;
16use libc::{self, c_int, size_t, strerror_r, strlen};
17
18use crate::Errno;
19
20fn 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
27pub fn with_description<F, T>(err: Errno, callback: F) -> T
28where
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
50pub const STRERROR_NAME: &str = "strerror_r";
51
52pub fn errno() -> Errno {
53    unsafe { Errno(*errno_location()) }
54}
55
56pub fn set_errno(Errno(errno): Errno) {
57    unsafe {
58        *errno_location() = errno;
59    }
60}
61
62extern "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    fn errno_location() -> *mut c_int;
102}