serial_unix/
error.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
use core;

use std::error::Error;
use std::ffi::CStr;
use std::io;
use std::str;

use libc::{c_int, c_char, size_t};

pub fn last_os_error() -> core::Error {
    from_raw_os_error(errno())
}

pub fn from_raw_os_error(errno: i32) -> core::Error {
    use libc::{EBUSY, EISDIR, ELOOP, ENOTDIR, ENOENT, ENODEV, ENXIO, EACCES, EINVAL, ENAMETOOLONG, EINTR, EWOULDBLOCK};

    let kind = match errno {
        EBUSY | EISDIR | ELOOP | ENOTDIR | ENOENT | ENODEV | ENXIO | EACCES => core::ErrorKind::NoDevice,
        EINVAL | ENAMETOOLONG => core::ErrorKind::InvalidInput,

        EINTR       => core::ErrorKind::Io(io::ErrorKind::Interrupted),
        EWOULDBLOCK => core::ErrorKind::Io(io::ErrorKind::WouldBlock),
        _           => core::ErrorKind::Io(io::ErrorKind::Other),
    };

    core::Error::new(kind, error_string(errno))
}

pub fn from_io_error(io_error: io::Error) -> core::Error {
    match io_error.raw_os_error() {
        Some(errno) => from_raw_os_error(errno),
        None => {
            let description = io_error.description().to_string();

            core::Error::new(core::ErrorKind::Io(io_error.kind()), description)
        }
    }
}

// the rest of this module is borrowed from libstd

const TMPBUF_SZ: usize = 128;

pub fn errno() -> i32 {
    #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))]
    unsafe fn errno_location() -> *const c_int {
        extern { fn __error() -> *const c_int; }
        __error()
    }

    #[cfg(target_os = "bitrig")]
    fn errno_location() -> *const c_int {
        extern {
            fn __errno() -> *const c_int;
        }
        unsafe {
            __errno()
        }
    }

    #[cfg(target_os = "dragonfly")]
    unsafe fn errno_location() -> *const c_int {
        extern { fn __dfly_error() -> *const c_int; }
        __dfly_error()
    }

    #[cfg(target_os = "openbsd")]
    unsafe fn errno_location() -> *const c_int {
        extern { fn __errno() -> *const c_int; }
        __errno()
    }

    #[cfg(any(target_os = "linux", target_os = "android"))]
    unsafe fn errno_location() -> *const c_int {
        extern { fn __errno_location() -> *const c_int; }
        __errno_location()
    }

    unsafe {
        (*errno_location()) as i32
    }
}

pub fn error_string(errno: i32) -> String {
    #[cfg(target_os = "linux")]
    extern {
        #[link_name = "__xpg_strerror_r"]
        fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: size_t) -> c_int;
    }
    #[cfg(not(target_os = "linux"))]
    extern {
        fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: size_t) -> c_int;
    }

    let mut buf = [0 as c_char; TMPBUF_SZ];

    let p = buf.as_mut_ptr();
    unsafe {
        if strerror_r(errno as c_int, p, buf.len() as size_t) < 0 {
            panic!("strerror_r failure");
        }

        let p = p as *const _;
        str::from_utf8(CStr::from_ptr(p).to_bytes()).unwrap().to_string()
    }
}