vmm_sys_util/
errno.rs

1// Copyright 2019 Intel Corporation. All Rights Reserved.
2//
3// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
4//
5// Portions Copyright 2017 The Chromium OS Authors. All rights reserved.
6//
7// SPDX-License-Identifier: BSD-3-Clause
8
9//! Structures, helpers, and type definitions for working with
10//! [`errno`](http://man7.org/linux/man-pages/man3/errno.3.html).
11
12use std::fmt::{Display, Formatter};
13use std::io;
14use std::result;
15
16/// Wrapper over [`errno`](http://man7.org/linux/man-pages/man3/errno.3.html).
17///
18/// The error number is an integer number set by system calls and some libc
19/// functions in case of error.
20#[derive(Clone, Copy, Debug, PartialEq, Eq)]
21pub struct Error(i32);
22
23/// A specialized [Result](https://doc.rust-lang.org/std/result/enum.Result.html) type
24/// for operations that can return `errno`.
25///
26/// This typedef is generally used to avoid writing out `errno::Error` directly and is
27/// otherwise a direct mapping to `Result`.
28pub type Result<T> = result::Result<T, Error>;
29
30impl Error {
31    /// Creates a new error from the given error number.
32    ///
33    /// # Arguments
34    ///
35    /// * `errno`: error number used for creating the `Error`.
36    ///
37    /// # Examples
38    ///
39    /// ```
40    /// # extern crate libc;
41    /// extern crate vmm_sys_util;
42    /// #
43    /// # use libc;
44    /// use vmm_sys_util::errno::Error;
45    ///
46    /// let err = Error::new(libc::EIO);
47    /// ```
48    pub fn new(errno: i32) -> Error {
49        Error(errno)
50    }
51
52    /// Returns the last occurred `errno` wrapped in an `Error`.
53    ///
54    /// Calling `Error::last()` is the equivalent of using
55    /// [`errno`](http://man7.org/linux/man-pages/man3/errno.3.html) in C/C++.
56    /// The result of this function only has meaning after a libc call or syscall
57    /// where `errno` was set.
58    ///
59    /// # Examples
60    ///
61    /// ```
62    /// # extern crate libc;
63    /// extern crate vmm_sys_util;
64    /// #
65    /// # use libc;
66    /// # use std::fs::File;
67    /// # use std::io::{self, Read};
68    /// # use std::env::temp_dir;
69    /// use vmm_sys_util::errno::Error;
70    /// #
71    /// // Reading from a file without permissions returns an error.
72    /// let mut path = temp_dir();
73    /// path.push("test");
74    /// let mut file = File::create(path).unwrap();
75    /// let mut buf: Vec<u8> = Vec::new();
76    /// assert!(file.read_to_end(&mut buf).is_err());
77    ///
78    /// // Retrieve the error number of the previous operation using `Error::last()`:
79    /// let read_err = Error::last();
80    /// #[cfg(unix)]
81    /// assert_eq!(read_err, Error::new(libc::EBADF));
82    /// #[cfg(not(unix))]
83    /// assert_eq!(read_err, Error::new(libc::EIO));
84    /// ```
85    pub fn last() -> Error {
86        // It's safe to unwrap because this `Error` was constructed via `last_os_error`.
87        Error(io::Error::last_os_error().raw_os_error().unwrap())
88    }
89
90    /// Returns the raw integer value (`errno`) corresponding to this Error.
91    ///
92    /// # Examples
93    /// ```
94    /// extern crate vmm_sys_util;
95    /// use vmm_sys_util::errno::Error;
96    ///
97    /// let err = Error::new(13);
98    /// assert_eq!(err.errno(), 13);
99    /// ```
100    pub fn errno(self) -> i32 {
101        self.0
102    }
103}
104
105impl Display for Error {
106    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
107        io::Error::from_raw_os_error(self.0).fmt(f)
108    }
109}
110
111impl std::error::Error for Error {}
112
113impl From<io::Error> for Error {
114    fn from(e: io::Error) -> Self {
115        Error::new(e.raw_os_error().unwrap_or_default())
116    }
117}
118
119impl From<Error> for io::Error {
120    fn from(err: Error) -> io::Error {
121        io::Error::from_raw_os_error(err.0)
122    }
123}
124
125/// Returns the last `errno` as a [`Result`] that is always an error.
126///
127/// [`Result`]: type.Result.html
128pub fn errno_result<T>() -> Result<T> {
129    Err(Error::last())
130}
131
132#[cfg(test)]
133mod tests {
134    use super::*;
135    use std::env::temp_dir;
136    use std::error::Error as _;
137    use std::fs::OpenOptions;
138    use std::io::{self, Read};
139
140    #[test]
141    pub fn test_errno() {
142        #[cfg(unix)]
143        let expected_errno = libc::EBADF;
144        #[cfg(not(unix))]
145        let expected_errno = libc::EIO;
146
147        // try to read from a file without read permissions
148        let mut path = temp_dir();
149        path.push("test");
150        let mut file = OpenOptions::new()
151            .read(false)
152            .write(true)
153            .create(true)
154            .truncate(true)
155            .open(path)
156            .unwrap();
157        let mut buf: Vec<u8> = Vec::new();
158        assert!(file.read_to_end(&mut buf).is_err());
159
160        // Test that errno_result returns Err and the error is the expected one.
161        let last_err = errno_result::<i32>().unwrap_err();
162        assert_eq!(last_err, Error::new(expected_errno));
163
164        // Test that the inner value of `Error` corresponds to expected_errno.
165        assert_eq!(last_err.errno(), expected_errno);
166        assert!(last_err.source().is_none());
167
168        // Test creating an `Error` from a `std::io::Error`.
169        assert_eq!(last_err, Error::from(io::Error::last_os_error()));
170
171        // Test that calling `last()` returns the same error as `errno_result()`.
172        assert_eq!(last_err, Error::last());
173
174        let last_err: io::Error = last_err.into();
175        // Test creating a `std::io::Error` from an `Error`
176        assert_eq!(io::Error::last_os_error().kind(), last_err.kind());
177    }
178
179    #[test]
180    pub fn test_display() {
181        // Test the display implementation.
182        #[cfg(target_os = "linux")]
183        assert_eq!(
184            format!("{}", Error::new(libc::EBADF)),
185            "Bad file descriptor (os error 9)"
186        );
187        #[cfg(not(unix))]
188        assert_eq!(
189            format!("{}", Error::new(libc::EIO)),
190            "Access is denied. (os error 5)"
191        );
192    }
193}