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 
12 use std::fmt::{Display, Formatter};
13 use std::io;
14 use 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)]
21 pub 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`.
28 pub type Result<T> = result::Result<T, Error>;
29 
30 impl 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     /// ```
new(errno: i32) -> Error48     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     /// ```
last() -> Error85     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     /// ```
errno(self) -> i32100     pub fn errno(self) -> i32 {
101         self.0
102     }
103 }
104 
105 impl Display for Error {
fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result106     fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
107         io::Error::from_raw_os_error(self.0).fmt(f)
108     }
109 }
110 
111 impl std::error::Error for Error {}
112 
113 impl From<io::Error> for Error {
from(e: io::Error) -> Self114     fn from(e: io::Error) -> Self {
115         Error::new(e.raw_os_error().unwrap_or_default())
116     }
117 }
118 
119 impl From<Error> for io::Error {
from(err: Error) -> io::Error120     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
errno_result<T>() -> Result<T>128 pub fn errno_result<T>() -> Result<T> {
129     Err(Error::last())
130 }
131 
132 #[cfg(test)]
133 mod tests {
134     use super::*;
135     use crate::tempfile::TempFile;
136     use std::error::Error as _;
137     use std::fs::OpenOptions;
138     use std::io::{self, Read};
139 
140     #[test]
test_errno()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 temp_file = TempFile::new().unwrap();
149         let path = temp_file.as_path().to_owned();
150         // Drop temp_file so we can cleanly reuse path below.
151         std::mem::drop(temp_file);
152         let mut file = OpenOptions::new()
153             .read(false)
154             .write(true)
155             .create(true)
156             .truncate(true)
157             .open(&path)
158             .unwrap();
159         let mut buf: Vec<u8> = Vec::new();
160         assert!(file.read_to_end(&mut buf).is_err());
161 
162         // Test that errno_result returns Err and the error is the expected one.
163         let last_err = errno_result::<i32>().unwrap_err();
164         assert_eq!(last_err, Error::new(expected_errno));
165 
166         // Test that the inner value of `Error` corresponds to expected_errno.
167         assert_eq!(last_err.errno(), expected_errno);
168         assert!(last_err.source().is_none());
169 
170         // Test creating an `Error` from a `std::io::Error`.
171         assert_eq!(last_err, Error::from(io::Error::last_os_error()));
172 
173         // Test that calling `last()` returns the same error as `errno_result()`.
174         assert_eq!(last_err, Error::last());
175 
176         let last_err: io::Error = last_err.into();
177         // Test creating a `std::io::Error` from an `Error`
178         assert_eq!(io::Error::last_os_error().kind(), last_err.kind());
179 
180         assert!(std::fs::remove_file(&path).is_ok());
181     }
182 
183     #[test]
test_display()184     pub fn test_display() {
185         // Test the display implementation.
186         #[cfg(target_os = "linux")]
187         assert_eq!(
188             format!("{}", Error::new(libc::EBADF)),
189             "Bad file descriptor (os error 9)"
190         );
191         #[cfg(not(unix))]
192         assert_eq!(
193             format!("{}", Error::new(libc::EIO)),
194             "Access is denied. (os error 5)"
195         );
196     }
197 }
198