1566 lines
57 KiB
Diff
1566 lines
57 KiB
Diff
|
|
From 0bae5d9fad3196c79f88a9d47eba38e89d5f291f Mon Sep 17 00:00:00 2001
|
||
|
|
From: chenjiayi <chenjiayi22@huawei.com>
|
||
|
|
Date: Wed, 8 Nov 2023 05:18:36 +0800
|
||
|
|
Subject: [PATCH 049/103] test(device): compress closures and add some unit
|
||
|
|
cases
|
||
|
|
|
||
|
|
Some unnecessary closures may decrease line coverage, thus compress
|
||
|
|
them.
|
||
|
|
|
||
|
|
Also drop Clone trait implementation for Device as it is not necessary.
|
||
|
|
---
|
||
|
|
.../src/bin/devctl/subcmds/devctl_info.rs | 4 +-
|
||
|
|
exts/devmaster/src/lib/builtin/hwdb.rs | 12 +-
|
||
|
|
exts/devmaster/src/lib/framework/devmaster.rs | 1 -
|
||
|
|
exts/devmaster/src/lib/framework/job_queue.rs | 2 -
|
||
|
|
.../src/lib/framework/uevent_monitor.rs | 1 -
|
||
|
|
libs/device/examples/device_from.rs | 4 +-
|
||
|
|
libs/device/src/device.rs | 689 +++++++-----------
|
||
|
|
libs/device/src/device_enumerator.rs | 10 +-
|
||
|
|
libs/device/src/device_monitor.rs | 2 +-
|
||
|
|
libs/device/src/error.rs | 65 +-
|
||
|
|
10 files changed, 324 insertions(+), 466 deletions(-)
|
||
|
|
|
||
|
|
diff --git a/exts/devmaster/src/bin/devctl/subcmds/devctl_info.rs b/exts/devmaster/src/bin/devctl/subcmds/devctl_info.rs
|
||
|
|
index 71c9254d..d4fcb6c4 100644
|
||
|
|
--- a/exts/devmaster/src/bin/devctl/subcmds/devctl_info.rs
|
||
|
|
+++ b/exts/devmaster/src/bin/devctl/subcmds/devctl_info.rs
|
||
|
|
@@ -286,7 +286,7 @@ fn print_device_chain(device: Device) -> Result<()> {
|
||
|
|
while let Ok(parent) = child.get_parent() {
|
||
|
|
print_all_attributes(&parent.borrow(), true)?;
|
||
|
|
|
||
|
|
- child = parent.borrow().clone();
|
||
|
|
+ child = parent.borrow().shallow_clone().unwrap();
|
||
|
|
}
|
||
|
|
|
||
|
|
Ok(())
|
||
|
|
@@ -489,7 +489,7 @@ fn export_devices() -> Result<()> {
|
||
|
|
}
|
||
|
|
|
||
|
|
for device in e.iter() {
|
||
|
|
- print_record(device.borrow().clone(), "");
|
||
|
|
+ print_record(device.borrow().shallow_clone().unwrap(), "");
|
||
|
|
}
|
||
|
|
|
||
|
|
Ok(())
|
||
|
|
diff --git a/exts/devmaster/src/lib/builtin/hwdb.rs b/exts/devmaster/src/lib/builtin/hwdb.rs
|
||
|
|
index 63308e37..0b797874 100644
|
||
|
|
--- a/exts/devmaster/src/lib/builtin/hwdb.rs
|
||
|
|
+++ b/exts/devmaster/src/lib/builtin/hwdb.rs
|
||
|
|
@@ -123,7 +123,7 @@ impl Hwdb {
|
||
|
|
let mut last = false;
|
||
|
|
let mut src_dev = match srcdev {
|
||
|
|
Some(d) => d,
|
||
|
|
- None => dev.borrow_mut().clone(),
|
||
|
|
+ None => dev.borrow_mut().shallow_clone().unwrap(),
|
||
|
|
};
|
||
|
|
|
||
|
|
loop {
|
||
|
|
@@ -131,7 +131,7 @@ impl Hwdb {
|
||
|
|
Ok(str_subsystem) => str_subsystem,
|
||
|
|
Err(_) => {
|
||
|
|
src_dev = match src_dev.get_parent() {
|
||
|
|
- Ok(d) => d.borrow_mut().clone(),
|
||
|
|
+ Ok(d) => d.borrow_mut().shallow_clone().unwrap(),
|
||
|
|
Err(_) => break,
|
||
|
|
};
|
||
|
|
continue;
|
||
|
|
@@ -142,7 +142,7 @@ impl Hwdb {
|
||
|
|
if let Some(str_subsystem) = subsystem {
|
||
|
|
if &dsubsys != str_subsystem {
|
||
|
|
src_dev = match src_dev.get_parent() {
|
||
|
|
- Ok(d) => d.borrow_mut().clone(),
|
||
|
|
+ Ok(d) => d.borrow_mut().shallow_clone().unwrap(),
|
||
|
|
Err(_) => break,
|
||
|
|
};
|
||
|
|
continue;
|
||
|
|
@@ -170,7 +170,7 @@ impl Hwdb {
|
||
|
|
|
||
|
|
if modalias.is_empty() {
|
||
|
|
src_dev = match src_dev.get_parent() {
|
||
|
|
- Ok(d) => d.borrow_mut().clone(),
|
||
|
|
+ Ok(d) => d.borrow_mut().shallow_clone().unwrap(),
|
||
|
|
Err(_) => break,
|
||
|
|
};
|
||
|
|
continue;
|
||
|
|
@@ -189,7 +189,7 @@ impl Hwdb {
|
||
|
|
}
|
||
|
|
|
||
|
|
src_dev = match src_dev.get_parent() {
|
||
|
|
- Ok(d) => d.borrow_mut().clone(),
|
||
|
|
+ Ok(d) => d.borrow_mut().shallow_clone().unwrap(),
|
||
|
|
Err(_) => break,
|
||
|
|
};
|
||
|
|
}
|
||
|
|
@@ -258,7 +258,7 @@ impl Builtin for Hwdb {
|
||
|
|
Ok(srcdev) => Some(srcdev),
|
||
|
|
Err(e) => {
|
||
|
|
return Err(Error::Other {
|
||
|
|
- msg: format!("Failed to create sd_device object '{:?}'", dev),
|
||
|
|
+ msg: format!("Failed to create device object '{}'", device_id),
|
||
|
|
errno: e.get_errno(),
|
||
|
|
});
|
||
|
|
}
|
||
|
|
diff --git a/exts/devmaster/src/lib/framework/devmaster.rs b/exts/devmaster/src/lib/framework/devmaster.rs
|
||
|
|
index 370f4e84..94b93ca0 100644
|
||
|
|
--- a/exts/devmaster/src/lib/framework/devmaster.rs
|
||
|
|
+++ b/exts/devmaster/src/lib/framework/devmaster.rs
|
||
|
|
@@ -24,7 +24,6 @@ use std::{
|
||
|
|
};
|
||
|
|
|
||
|
|
/// encapsulate all submanagers
|
||
|
|
-#[derive(Debug)]
|
||
|
|
pub struct Devmaster {
|
||
|
|
/// reference to events
|
||
|
|
pub(crate) events: Rc<Events>,
|
||
|
|
diff --git a/exts/devmaster/src/lib/framework/job_queue.rs b/exts/devmaster/src/lib/framework/job_queue.rs
|
||
|
|
index e3e6e90b..7c6d6a8d 100644
|
||
|
|
--- a/exts/devmaster/src/lib/framework/job_queue.rs
|
||
|
|
+++ b/exts/devmaster/src/lib/framework/job_queue.rs
|
||
|
|
@@ -51,7 +51,6 @@ impl Display for JobState {
|
||
|
|
}
|
||
|
|
|
||
|
|
/// device job
|
||
|
|
-#[derive(Debug)]
|
||
|
|
pub struct DeviceJob {
|
||
|
|
/// internal device
|
||
|
|
pub device: Device,
|
||
|
|
@@ -132,7 +131,6 @@ impl PartialEq for DeviceJob {
|
||
|
|
}
|
||
|
|
|
||
|
|
/// job queue
|
||
|
|
-#[derive(Debug)]
|
||
|
|
pub struct JobQueue {
|
||
|
|
/// internal container of jobs
|
||
|
|
pub(crate) jobs: RefCell<VecDeque<Rc<DeviceJob>>>,
|
||
|
|
diff --git a/exts/devmaster/src/lib/framework/uevent_monitor.rs b/exts/devmaster/src/lib/framework/uevent_monitor.rs
|
||
|
|
index fe7d19c3..809071d1 100644
|
||
|
|
--- a/exts/devmaster/src/lib/framework/uevent_monitor.rs
|
||
|
|
+++ b/exts/devmaster/src/lib/framework/uevent_monitor.rs
|
||
|
|
@@ -22,7 +22,6 @@ use std::os::unix::io::RawFd;
|
||
|
|
use std::rc::Rc;
|
||
|
|
|
||
|
|
/// uevent monitor
|
||
|
|
-#[derive(Debug)]
|
||
|
|
pub struct UeventMonitor {
|
||
|
|
/// receive uevent from netlink socket
|
||
|
|
device_monitor: DeviceMonitor,
|
||
|
|
diff --git a/libs/device/examples/device_from.rs b/libs/device/examples/device_from.rs
|
||
|
|
index 29e24bbc..146543ee 100644
|
||
|
|
--- a/libs/device/examples/device_from.rs
|
||
|
|
+++ b/libs/device/examples/device_from.rs
|
||
|
|
@@ -30,11 +30,11 @@ fn main() {
|
||
|
|
let dev = Device::from_subsystem_sysname("drivers", "usb:hub").unwrap();
|
||
|
|
println!("{}", dev.get_sysname().unwrap());
|
||
|
|
println!("{}", dev.get_subsystem().unwrap());
|
||
|
|
- println!("{:?}", dev);
|
||
|
|
+ println!("{}", dev.get_device_id().unwrap());
|
||
|
|
}
|
||
|
|
|
||
|
|
{
|
||
|
|
let dev = Device::from_ifindex(2).unwrap();
|
||
|
|
- println!("{:?}", dev);
|
||
|
|
+ println!("{}", dev.get_device_id().unwrap());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
diff --git a/libs/device/src/device.rs b/libs/device/src/device.rs
|
||
|
|
index 6673d823..284cd6e9 100644
|
||
|
|
--- a/libs/device/src/device.rs
|
||
|
|
+++ b/libs/device/src/device.rs
|
||
|
|
@@ -12,7 +12,6 @@
|
||
|
|
|
||
|
|
//! struct Device
|
||
|
|
//!
|
||
|
|
-use crate::err_wrapper;
|
||
|
|
use crate::utils::readlink_value;
|
||
|
|
use crate::{error::*, DeviceAction};
|
||
|
|
use basic::fs_util::{chmod, open_temporary, touch_file};
|
||
|
|
@@ -49,7 +48,7 @@ pub const DB_BASE_DIR: &str = "data";
|
||
|
|
pub const TAGS_BASE_DIR: &str = "tags";
|
||
|
|
|
||
|
|
/// Device
|
||
|
|
-#[derive(Debug, Clone)]
|
||
|
|
+#[derive(Debug)]
|
||
|
|
pub struct Device {
|
||
|
|
/// inotify handler
|
||
|
|
pub watch_handle: RefCell<i32>,
|
||
|
|
@@ -355,33 +354,16 @@ impl Device {
|
||
|
|
|
||
|
|
let buf_trans: &[u8] = unsafe { std::slice::from_raw_parts(buf.as_ptr() as *const _, 16) };
|
||
|
|
|
||
|
|
- let ifname = String::from_utf8(buf_trans.to_vec()).map_err(|e| Error::Nix {
|
||
|
|
- msg: format!("from_ifindex failed: from_utf8 {:?} ({})", buf_trans, e),
|
||
|
|
- source: Errno::EINVAL,
|
||
|
|
+ let ifname = String::from_utf8(buf_trans.to_vec()).context(FromUtf8 {
|
||
|
|
+ msg: format!("invalid utf-8 string {:?}", buf_trans),
|
||
|
|
})?;
|
||
|
|
|
||
|
|
let syspath = format!("/sys/class/net/{}", ifname.trim_matches(char::from(0)));
|
||
|
|
- let dev = Self::from_syspath(&syspath, true).map_err(|e| Error::Nix {
|
||
|
|
- msg: format!("from_ifindex failed: {}", e),
|
||
|
|
- source: e.get_errno(),
|
||
|
|
- })?;
|
||
|
|
+ let dev = Self::from_syspath(&syspath, true)?;
|
||
|
|
|
||
|
|
- let i = match dev.get_ifindex() {
|
||
|
|
- Ok(i) => i,
|
||
|
|
- Err(e) => {
|
||
|
|
- if e.get_errno() == Errno::ENOENT {
|
||
|
|
- return Err(Error::Nix {
|
||
|
|
- msg: format!("from_ifindex failed: {}", e),
|
||
|
|
- source: Errno::ENXIO,
|
||
|
|
- });
|
||
|
|
- }
|
||
|
|
-
|
||
|
|
- return Err(Error::Nix {
|
||
|
|
- msg: format!("from_ifindex failed: {}", e),
|
||
|
|
- source: e.get_errno(),
|
||
|
|
- });
|
||
|
|
- }
|
||
|
|
- };
|
||
|
|
+ let i = dev
|
||
|
|
+ .get_ifindex()
|
||
|
|
+ .map_err(|e| e.replace_errno(Errno::ENOENT, Errno::ENXIO))?;
|
||
|
|
|
||
|
|
if i != ifindex {
|
||
|
|
return Err(Error::Nix {
|
||
|
|
@@ -393,8 +375,9 @@ impl Device {
|
||
|
|
Ok(dev)
|
||
|
|
}
|
||
|
|
|
||
|
|
- /// create a Device instance from subsystem and sysname
|
||
|
|
- /// if subsystem is 'drivers', sysname should be like 'xxx:yyy'
|
||
|
|
+ /// Create a Device instance from subsystem and sysname.
|
||
|
|
+ ///
|
||
|
|
+ /// If subsystem is 'drivers', sysname should be like 'xxx:yyy'
|
||
|
|
pub fn from_subsystem_sysname(subsystem: &str, sysname: &str) -> Result<Device, Error> {
|
||
|
|
let sysname = sysname.replace('/', "!");
|
||
|
|
if subsystem == "subsystem" {
|
||
|
|
@@ -506,10 +489,12 @@ impl Device {
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
- /// set sysattr value
|
||
|
|
+ /// Set sysattr value.
|
||
|
|
+ ///
|
||
|
|
+ /// If the sysattr is not 'uevent', the value will be cached.
|
||
|
|
pub fn set_sysattr_value(&self, sysattr: &str, value: Option<&str>) -> Result<(), Error> {
|
||
|
|
if value.is_none() {
|
||
|
|
- self.remove_cached_sysattr_value(sysattr)?;
|
||
|
|
+ self.remove_cached_sysattr_value(sysattr);
|
||
|
|
return Ok(());
|
||
|
|
}
|
||
|
|
|
||
|
|
@@ -529,7 +514,7 @@ impl Device {
|
||
|
|
};
|
||
|
|
|
||
|
|
if let Err(e) = file.write(value.unwrap().as_bytes()) {
|
||
|
|
- self.remove_cached_sysattr_value(sysattr)?;
|
||
|
|
+ self.remove_cached_sysattr_value(sysattr);
|
||
|
|
return Err(Error::Nix {
|
||
|
|
msg: format!(
|
||
|
|
"set_sysattr_value failed: can't write sysattr '{}'",
|
||
|
|
@@ -559,28 +544,18 @@ impl Device {
|
||
|
|
|
||
|
|
match id.chars().next() {
|
||
|
|
Some('b') | Some('c') => {
|
||
|
|
- let devnum = parse_devnum(&id[1..]).map_err(|_| Error::Nix {
|
||
|
|
+ let devnum = parse_devnum(&id[1..]).context(Basic {
|
||
|
|
msg: format!("from_device_id failed: parse_devnum '{}' failed", id),
|
||
|
|
- source: Errno::EINVAL,
|
||
|
|
})?;
|
||
|
|
|
||
|
|
- return Device::from_devnum(id.chars().next().unwrap(), devnum).map_err(|e| {
|
||
|
|
- Error::Nix {
|
||
|
|
- msg: format!("from_device_id failed: {}", e),
|
||
|
|
- source: e.get_errno(),
|
||
|
|
- }
|
||
|
|
- });
|
||
|
|
+ Device::from_devnum(id.chars().next().unwrap(), devnum)
|
||
|
|
}
|
||
|
|
Some('n') => {
|
||
|
|
- let ifindex = parse_ifindex(&id[1..]).map_err(|_| Error::Nix {
|
||
|
|
+ let ifindex = parse_ifindex(&id[1..]).context(Basic {
|
||
|
|
msg: format!("from_device_id failed: parse_ifindex '{}' failed", id),
|
||
|
|
- source: Errno::EINVAL,
|
||
|
|
})?;
|
||
|
|
|
||
|
|
- Device::from_ifindex(ifindex).map_err(|e| Error::Nix {
|
||
|
|
- msg: format!("from_device_id failed: {}", e),
|
||
|
|
- source: e.get_errno(),
|
||
|
|
- })
|
||
|
|
+ Device::from_ifindex(ifindex)
|
||
|
|
}
|
||
|
|
Some('+') => {
|
||
|
|
let sep = match id.find(':') {
|
||
|
|
@@ -604,10 +579,7 @@ impl Device {
|
||
|
|
|
||
|
|
let subsystem = id[1..sep].to_string();
|
||
|
|
let sysname = id[sep + 1..].to_string();
|
||
|
|
- Device::from_subsystem_sysname(&subsystem, &sysname).map_err(|e| Error::Nix {
|
||
|
|
- msg: format!("from_device_id failed: {}", e),
|
||
|
|
- source: e.get_errno(),
|
||
|
|
- })
|
||
|
|
+ Device::from_subsystem_sysname(&subsystem, &sysname)
|
||
|
|
}
|
||
|
|
_ => Err(Error::Nix {
|
||
|
|
msg: format!("from_device_id failed: invalid id '{}'", id),
|
||
|
|
@@ -648,7 +620,7 @@ impl Device {
|
||
|
|
/// get the sysname of the device
|
||
|
|
pub fn get_sysname(&self) -> Result<String, Error> {
|
||
|
|
if self.sysname.borrow().is_empty() {
|
||
|
|
- err_wrapper!(self.set_sysname_and_sysnum(), "get_sysname")?;
|
||
|
|
+ self.set_sysname_and_sysnum()?;
|
||
|
|
}
|
||
|
|
|
||
|
|
Ok(self.sysname.borrow().clone())
|
||
|
|
@@ -729,10 +701,7 @@ impl Device {
|
||
|
|
// e.g. /sys/devices/pci0000:00/0000:00:10.0/host2/target2:0:1/2:0:1:0/block/sda/subsystem -> ../../../../../../../../class/block
|
||
|
|
// get `block`
|
||
|
|
let filename = if Path::exists(Path::new(subsystem_path)) {
|
||
|
|
- readlink_value(subsystem_path).map_err(|e| Error::Nix {
|
||
|
|
- msg: format!("get_subsystem failed: {}", e),
|
||
|
|
- source: e.get_errno(),
|
||
|
|
- })?
|
||
|
|
+ readlink_value(subsystem_path)?
|
||
|
|
} else {
|
||
|
|
"".to_string()
|
||
|
|
};
|
||
|
|
@@ -766,10 +735,7 @@ impl Device {
|
||
|
|
|
||
|
|
/// get the ifindex of device
|
||
|
|
pub fn get_ifindex(&self) -> Result<u32, Error> {
|
||
|
|
- self.read_uevent_file().map_err(|e| Error::Nix {
|
||
|
|
- msg: format!("get_ifindex failed: {}", e),
|
||
|
|
- source: e.get_errno(),
|
||
|
|
- })?;
|
||
|
|
+ self.read_uevent_file()?;
|
||
|
|
|
||
|
|
if *self.ifindex.borrow() == 0 {
|
||
|
|
return Err(Error::Nix {
|
||
|
|
@@ -802,12 +768,7 @@ impl Device {
|
||
|
|
|
||
|
|
/// get devnum
|
||
|
|
pub fn get_devnum(&self) -> Result<u64, Error> {
|
||
|
|
- match self.read_uevent_file() {
|
||
|
|
- Ok(_) => {}
|
||
|
|
- Err(e) => {
|
||
|
|
- return Err(e);
|
||
|
|
- }
|
||
|
|
- }
|
||
|
|
+ self.read_uevent_file()?;
|
||
|
|
|
||
|
|
if major(*self.devnum.borrow()) == 0 {
|
||
|
|
return Err(Error::Nix {
|
||
|
|
@@ -870,10 +831,7 @@ impl Device {
|
||
|
|
/// get device sysnum
|
||
|
|
pub fn get_sysnum(&self) -> Result<String, Error> {
|
||
|
|
if self.sysname.borrow().is_empty() {
|
||
|
|
- self.set_sysname_and_sysnum().map_err(|e| Error::Nix {
|
||
|
|
- msg: format!("get_sysnum failed: {}", e),
|
||
|
|
- source: e.get_errno(),
|
||
|
|
- })?;
|
||
|
|
+ self.set_sysname_and_sysnum()?;
|
||
|
|
}
|
||
|
|
|
||
|
|
if self.sysnum.borrow().is_empty() {
|
||
|
|
@@ -915,10 +873,7 @@ impl Device {
|
||
|
|
|
||
|
|
/// get device diskseq
|
||
|
|
pub fn get_diskseq(&self) -> Result<u64, Error> {
|
||
|
|
- self.read_uevent_file().map_err(|e| Error::Nix {
|
||
|
|
- msg: format!("get_diskseq failed: {}", e),
|
||
|
|
- source: e.get_errno(),
|
||
|
|
- })?;
|
||
|
|
+ self.read_uevent_file()?;
|
||
|
|
|
||
|
|
if *self.diskseq.borrow() == 0 {
|
||
|
|
return Err(Error::Nix {
|
||
|
|
@@ -935,7 +890,6 @@ impl Device {
|
||
|
|
|
||
|
|
/// get is initialized
|
||
|
|
pub fn get_is_initialized(&self) -> Result<bool, Error> {
|
||
|
|
- // match self.read_db
|
||
|
|
match self.read_db() {
|
||
|
|
Ok(_) => {}
|
||
|
|
Err(e) => {
|
||
|
|
@@ -979,30 +933,21 @@ impl Device {
|
||
|
|
|
||
|
|
/// check whether the device has the tag
|
||
|
|
pub fn has_tag(&self, tag: &str) -> Result<bool, Error> {
|
||
|
|
- self.read_db().map_err(|e| Error::Nix {
|
||
|
|
- msg: format!("has_tag failed: {}", e),
|
||
|
|
- source: e.get_errno(),
|
||
|
|
- })?;
|
||
|
|
+ self.read_db()?;
|
||
|
|
|
||
|
|
Ok(self.all_tags.borrow().contains(tag))
|
||
|
|
}
|
||
|
|
|
||
|
|
/// check whether the device has the current tag
|
||
|
|
pub fn has_current_tag(&self, tag: &str) -> Result<bool, Error> {
|
||
|
|
- self.read_db().map_err(|e| Error::Nix {
|
||
|
|
- msg: format!("has_tag failed: {}", e),
|
||
|
|
- source: e.get_errno(),
|
||
|
|
- })?;
|
||
|
|
+ self.read_db()?;
|
||
|
|
|
||
|
|
Ok(self.current_tags.borrow().contains(tag))
|
||
|
|
}
|
||
|
|
|
||
|
|
/// get the value of specific device property
|
||
|
|
pub fn get_property_value(&self, key: &str) -> Result<String, Error> {
|
||
|
|
- self.properties_prepare().map_err(|e| Error::Nix {
|
||
|
|
- msg: format!("get_property_value failed: {}", e),
|
||
|
|
- source: e.get_errno(),
|
||
|
|
- })?;
|
||
|
|
+ self.properties_prepare()?;
|
||
|
|
|
||
|
|
match self.properties.borrow().get(key) {
|
||
|
|
Some(v) => Ok(v.clone()),
|
||
|
|
@@ -1083,27 +1028,22 @@ impl Device {
|
||
|
|
let mut file = std::fs::OpenOptions::new()
|
||
|
|
.read(true)
|
||
|
|
.open(&sysattr_path)
|
||
|
|
- .map_err(|e| Error::Nix {
|
||
|
|
+ .context(Io {
|
||
|
|
msg: format!(
|
||
|
|
- "get_sysattr_value failed: can't open sysattr '{}': {}",
|
||
|
|
- sysattr, e
|
||
|
|
+ "get_sysattr_value failed: can't open sysattr '{}'",
|
||
|
|
+ sysattr
|
||
|
|
),
|
||
|
|
- source: Errno::from_i32(e.raw_os_error().unwrap_or_default()),
|
||
|
|
})?;
|
||
|
|
let mut value = String::new();
|
||
|
|
- file.read_to_string(&mut value).map_err(|e| Error::Nix {
|
||
|
|
- msg: format!(
|
||
|
|
- "get_sysattr_value failed: can't read sysattr '{}': {}",
|
||
|
|
- sysattr, e
|
||
|
|
- ),
|
||
|
|
- source: Errno::from_i32(e.raw_os_error().unwrap_or_default()),
|
||
|
|
+ file.read_to_string(&mut value).context(Io {
|
||
|
|
+ msg: format!("get_sysattr_value failed: can't read sysattr '{}'", sysattr),
|
||
|
|
})?;
|
||
|
|
value.trim_end().to_string()
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
Err(e) => {
|
||
|
|
- self.remove_cached_sysattr_value(sysattr).unwrap();
|
||
|
|
+ self.remove_cached_sysattr_value(sysattr);
|
||
|
|
return Err(Error::Nix {
|
||
|
|
msg: format!("get_sysattr_value failed: can't lstat '{}'", sysattr_path),
|
||
|
|
source: e,
|
||
|
|
@@ -1111,11 +1051,7 @@ impl Device {
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
- self.cache_sysattr_value(sysattr, &value)
|
||
|
|
- .map_err(|e| Error::Nix {
|
||
|
|
- msg: format!("get_sysattr_value failed: {}", e),
|
||
|
|
- source: e.get_errno(),
|
||
|
|
- })?;
|
||
|
|
+ self.cache_sysattr_value(sysattr, &value)?;
|
||
|
|
|
||
|
|
Ok(value)
|
||
|
|
}
|
||
|
|
@@ -1133,15 +1069,9 @@ impl Device {
|
||
|
|
|
||
|
|
let s = format!("{}", action);
|
||
|
|
|
||
|
|
- let id = match randomize() {
|
||
|
|
- Ok(id) => id,
|
||
|
|
- Err(e) => {
|
||
|
|
- return Err(Error::Nix {
|
||
|
|
- msg: "Failed to randomize".to_string(),
|
||
|
|
- source: e,
|
||
|
|
- })
|
||
|
|
- }
|
||
|
|
- };
|
||
|
|
+ let id = randomize().context(Nix {
|
||
|
|
+ msg: "Failed to randomize".to_string(),
|
||
|
|
+ })?;
|
||
|
|
|
||
|
|
let j = s + " " + &id.to_string();
|
||
|
|
|
||
|
|
@@ -1152,33 +1082,12 @@ impl Device {
|
||
|
|
|
||
|
|
/// open device
|
||
|
|
pub fn open(&self, oflags: OFlag) -> Result<File, Error> {
|
||
|
|
- let devname = self.get_devname().map_err(|e| {
|
||
|
|
- if e.get_errno() == Errno::ENOENT {
|
||
|
|
- Error::Nix {
|
||
|
|
- msg: format!("open failed: {}", e),
|
||
|
|
- source: Errno::ENOEXEC,
|
||
|
|
- }
|
||
|
|
- } else {
|
||
|
|
- Error::Nix {
|
||
|
|
- msg: format!("open failed: {}", e),
|
||
|
|
- source: e.get_errno(),
|
||
|
|
- }
|
||
|
|
- }
|
||
|
|
- })?;
|
||
|
|
-
|
||
|
|
- let devnum = self.get_devnum().map_err(|e| {
|
||
|
|
- if e.get_errno() == Errno::ENOENT {
|
||
|
|
- Error::Nix {
|
||
|
|
- msg: format!("open failed: {}", e),
|
||
|
|
- source: Errno::ENOEXEC,
|
||
|
|
- }
|
||
|
|
- } else {
|
||
|
|
- Error::Nix {
|
||
|
|
- msg: format!("open failed: {}", e),
|
||
|
|
- source: e.get_errno(),
|
||
|
|
- }
|
||
|
|
- }
|
||
|
|
- })?;
|
||
|
|
+ let devname = self
|
||
|
|
+ .get_devname()
|
||
|
|
+ .map_err(|e| e.replace_errno(Errno::ENOENT, Errno::ENOEXEC))?;
|
||
|
|
+ let devnum = self
|
||
|
|
+ .get_devnum()
|
||
|
|
+ .map_err(|e| e.replace_errno(Errno::ENOENT, Errno::ENOEXEC))?;
|
||
|
|
|
||
|
|
let subsystem = match self.get_subsystem() {
|
||
|
|
Ok(s) => s,
|
||
|
|
@@ -1212,19 +1121,13 @@ impl Device {
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
- let stat = match nix::sys::stat::fstat(file.as_raw_fd()) {
|
||
|
|
- Ok(s) => s,
|
||
|
|
- Err(e) => {
|
||
|
|
- return Err(Error::Nix {
|
||
|
|
- msg: format!(
|
||
|
|
- "open failed: can't fstat fd {} for '{}'",
|
||
|
|
- file.as_raw_fd(),
|
||
|
|
- devname
|
||
|
|
- ),
|
||
|
|
- source: e,
|
||
|
|
- })
|
||
|
|
- }
|
||
|
|
- };
|
||
|
|
+ let stat = nix::sys::stat::fstat(file.as_raw_fd()).context(Nix {
|
||
|
|
+ msg: format!(
|
||
|
|
+ "open failed: can't fstat fd {} for '{}'",
|
||
|
|
+ file.as_raw_fd(),
|
||
|
|
+ devname
|
||
|
|
+ ),
|
||
|
|
+ })?;
|
||
|
|
|
||
|
|
if stat.st_rdev != devnum {
|
||
|
|
return Err(Error::Nix {
|
||
|
|
@@ -1265,18 +1168,11 @@ impl Device {
|
||
|
|
|
||
|
|
let mut diskseq: u64 = 0;
|
||
|
|
|
||
|
|
- if self.get_is_initialized().map_err(|e| Error::Nix {
|
||
|
|
- msg: format!("open failed: {}", e),
|
||
|
|
- source: e.get_errno(),
|
||
|
|
- })? {
|
||
|
|
+ if self.get_is_initialized()? {
|
||
|
|
match self.get_property_value("ID_IGNORE_DISKSEQ") {
|
||
|
|
Ok(value) => {
|
||
|
|
- if !value.parse::<bool>().map_err(|e| Error::Nix {
|
||
|
|
- msg: format!(
|
||
|
|
- "open failed: failed to parse value '{}' to boolean: {}",
|
||
|
|
- value, e
|
||
|
|
- ),
|
||
|
|
- source: Errno::EINVAL,
|
||
|
|
+ if !value.parse::<bool>().context(ParseBool {
|
||
|
|
+ msg: format!("invalid value '{}'", value),
|
||
|
|
})? {
|
||
|
|
match self.get_diskseq() {
|
||
|
|
Ok(n) => diskseq = n,
|
||
|
|
@@ -1302,28 +1198,16 @@ impl Device {
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
- let file2 =
|
||
|
|
- basic::fd_util::fd_reopen(file.as_raw_fd(), oflags).map_err(|e| Error::Nix {
|
||
|
|
- msg: format!("open failed: {}", e),
|
||
|
|
- source: match e {
|
||
|
|
- basic::Error::Nix { source } => source,
|
||
|
|
- _ => Errno::EINVAL,
|
||
|
|
- },
|
||
|
|
- })?;
|
||
|
|
+ let file2 = basic::fd_util::fd_reopen(file.as_raw_fd(), oflags).context(Basic {
|
||
|
|
+ msg: format!("failed to open {}", file.as_raw_fd()),
|
||
|
|
+ })?;
|
||
|
|
|
||
|
|
if diskseq == 0 {
|
||
|
|
return Ok(file2);
|
||
|
|
}
|
||
|
|
|
||
|
|
- let q = basic::fd_util::fd_get_diskseq(file2.as_raw_fd()).map_err(|e| Error::Nix {
|
||
|
|
- msg: format!(
|
||
|
|
- "open failed: failed to get diskseq on fd {}",
|
||
|
|
- file2.as_raw_fd()
|
||
|
|
- ),
|
||
|
|
- source: match e {
|
||
|
|
- basic::Error::Nix { source } => source,
|
||
|
|
- _ => Errno::EINVAL,
|
||
|
|
- },
|
||
|
|
+ let q = basic::fd_util::fd_get_diskseq(file2.as_raw_fd()).context(Basic {
|
||
|
|
+ msg: format!("failed to get diskseq on fd {}", file2.as_raw_fd()),
|
||
|
|
})?;
|
||
|
|
|
||
|
|
if q != diskseq {
|
||
|
|
@@ -1352,18 +1236,9 @@ impl Device {
|
||
|
|
|
||
|
|
/// shadow clone a device object and import properties from db
|
||
|
|
pub fn clone_with_db(&self) -> Result<Device, Error> {
|
||
|
|
- let device = self.shallow_clone().map_err(|e| Error::Nix {
|
||
|
|
- msg: format!("clone_with_db failed: {}", e),
|
||
|
|
- source: e.get_errno(),
|
||
|
|
- })?;
|
||
|
|
-
|
||
|
|
- device.read_db().map_err(|e| Error::Nix {
|
||
|
|
- msg: format!("clone_with_db failed: {}", e),
|
||
|
|
- source: e.get_errno(),
|
||
|
|
- })?;
|
||
|
|
-
|
||
|
|
+ let device = self.shallow_clone()?;
|
||
|
|
+ device.read_db()?;
|
||
|
|
device.sealed.replace(true);
|
||
|
|
-
|
||
|
|
Ok(device)
|
||
|
|
}
|
||
|
|
|
||
|
|
@@ -1427,22 +1302,14 @@ impl Device {
|
||
|
|
///
|
||
|
|
/// The format is like:
|
||
|
|
///
|
||
|
|
- /// character device: c<major>:<minor>
|
||
|
|
- ///
|
||
|
|
- /// block device: b<major>:<minor>
|
||
|
|
- ///
|
||
|
|
- /// network interface: n<ifindex>
|
||
|
|
- ///
|
||
|
|
- /// drivers: +drivers:<driver subsystem>:<sysname>
|
||
|
|
- ///
|
||
|
|
- /// other subsystems: +<subsystem>:<sysname>
|
||
|
|
- ///
|
||
|
|
+ /// - character device: c<major>:<minor>
|
||
|
|
+ /// - block device: b<major>:<minor>
|
||
|
|
+ /// - network interface: n<ifindex>
|
||
|
|
+ /// - drivers: +drivers:<driver subsystem>:<sysname>
|
||
|
|
+ /// - other subsystems: +<subsystem>:<sysname>
|
||
|
|
pub fn get_device_id(&self) -> Result<String, Error> {
|
||
|
|
if self.device_id.borrow().is_empty() {
|
||
|
|
- let subsystem = self.get_subsystem().map_err(|e| Error::Nix {
|
||
|
|
- msg: format!("get_device_id failed: {}", e),
|
||
|
|
- source: e.get_errno(),
|
||
|
|
- })?;
|
||
|
|
+ let subsystem = self.get_subsystem()?;
|
||
|
|
|
||
|
|
let id: String;
|
||
|
|
if let Ok(devnum) = self.get_devnum() {
|
||
|
|
@@ -1455,10 +1322,7 @@ impl Device {
|
||
|
|
} else if let Ok(ifindex) = self.get_ifindex() {
|
||
|
|
id = format!("n{}", ifindex);
|
||
|
|
} else {
|
||
|
|
- let sysname = self.get_sysname().map_err(|e| Error::Nix {
|
||
|
|
- msg: format!("get_device_id failed: {}", e),
|
||
|
|
- source: e.get_errno(),
|
||
|
|
- })?;
|
||
|
|
+ let sysname = self.get_sysname()?;
|
||
|
|
|
||
|
|
if subsystem == "drivers" {
|
||
|
|
id = format!("+drivers:{}:{}", self.driver_subsystem.borrow(), sysname);
|
||
|
|
@@ -1571,21 +1435,14 @@ impl Device {
|
||
|
|
let db_path = format!("{}/{}/{}", self.base_path.borrow(), DB_BASE_DIR, id);
|
||
|
|
|
||
|
|
if !has_info && *self.devnum.borrow() == 0 && *self.ifindex.borrow() == 0 {
|
||
|
|
- unlink(db_path.as_str()).map_err(|e| Error::Nix {
|
||
|
|
+ unlink(db_path.as_str()).context(Nix {
|
||
|
|
msg: format!("update_db failed: can't unlink db '{}'", db_path),
|
||
|
|
- source: e,
|
||
|
|
})?;
|
||
|
|
-
|
||
|
|
return Ok(());
|
||
|
|
}
|
||
|
|
|
||
|
|
- create_dir_all(&format!("{}/{}", self.base_path.borrow(), DB_BASE_DIR)).map_err(|e| {
|
||
|
|
- Error::Nix {
|
||
|
|
- msg: "update_db failed: can't create db directory".to_string(),
|
||
|
|
- source: e
|
||
|
|
- .raw_os_error()
|
||
|
|
- .map_or_else(|| nix::Error::EIO, nix::Error::from_i32),
|
||
|
|
- }
|
||
|
|
+ create_dir_all(&format!("{}/{}", self.base_path.borrow(), DB_BASE_DIR)).context(Io {
|
||
|
|
+ msg: "failed to create db directory".to_string(),
|
||
|
|
})?;
|
||
|
|
|
||
|
|
if let Err(e) = chmod(
|
||
|
|
@@ -1595,22 +1452,14 @@ impl Device {
|
||
|
|
log::error!("Failed to set permission for /run/devmaster/data/: {}", e);
|
||
|
|
}
|
||
|
|
|
||
|
|
- let (mut file, tmp_file) = open_temporary(&db_path).map_err(|e| {
|
||
|
|
- let errno = match e {
|
||
|
|
- basic::error::Error::Nix { source } => source,
|
||
|
|
- _ => nix::Error::EINVAL,
|
||
|
|
- };
|
||
|
|
- Error::Nix {
|
||
|
|
- msg: "update_db failed: can't open temporary file".to_string(),
|
||
|
|
- source: errno,
|
||
|
|
- }
|
||
|
|
+ let (mut file, tmp_file) = open_temporary(&db_path).context(Basic {
|
||
|
|
+ msg: "can't open temporary file".to_string(),
|
||
|
|
})?;
|
||
|
|
|
||
|
|
- self.atomic_create_db(&mut file, tmp_file.as_str(), db_path.as_str())
|
||
|
|
- .map_err(|e| {
|
||
|
|
- Self::cleanup(&db_path, &tmp_file);
|
||
|
|
- e
|
||
|
|
- })?;
|
||
|
|
+ if let Err(e) = self.atomic_create_db(&mut file, tmp_file.as_str(), db_path.as_str()) {
|
||
|
|
+ Self::cleanup(&db_path, &tmp_file);
|
||
|
|
+ return Err(e);
|
||
|
|
+ }
|
||
|
|
|
||
|
|
Ok(())
|
||
|
|
}
|
||
|
|
@@ -1713,9 +1562,8 @@ impl Device {
|
||
|
|
);
|
||
|
|
|
||
|
|
if add {
|
||
|
|
- touch_file(&tag_path, true, Some(0o444), None, None).map_err(|e| Error::Nix {
|
||
|
|
- msg: format!("tag_persist failed: can't touch file '{}': {}", tag_path, e),
|
||
|
|
- source: nix::Error::EINVAL,
|
||
|
|
+ touch_file(&tag_path, true, Some(0o444), None, None).context(Basic {
|
||
|
|
+ msg: format!("can't touch file '{}'", tag_path),
|
||
|
|
})?;
|
||
|
|
|
||
|
|
if let Err(e) = chmod(
|
||
|
|
@@ -1765,10 +1613,7 @@ impl Device {
|
||
|
|
|
||
|
|
/// read database
|
||
|
|
pub fn read_db(&self) -> Result<(), Error> {
|
||
|
|
- self.read_db_internal(false).map_err(|e| Error::Nix {
|
||
|
|
- msg: format!("read_db failed: {}", e),
|
||
|
|
- source: e.get_errno(),
|
||
|
|
- })
|
||
|
|
+ self.read_db_internal(false)
|
||
|
|
}
|
||
|
|
|
||
|
|
/// read database internally
|
||
|
|
@@ -1777,18 +1622,11 @@ impl Device {
|
||
|
|
return Ok(());
|
||
|
|
}
|
||
|
|
|
||
|
|
- let id = self.get_device_id().map_err(|e| Error::Nix {
|
||
|
|
- msg: format!("read_db_internal failed: {}", e),
|
||
|
|
- source: e.get_errno(),
|
||
|
|
- })?;
|
||
|
|
+ let id = self.get_device_id()?;
|
||
|
|
|
||
|
|
let path = format!("{}/{}/{}", self.base_path.borrow(), DB_BASE_DIR, id);
|
||
|
|
|
||
|
|
self.read_db_internal_filename(&path)
|
||
|
|
- .map_err(|e| Error::Nix {
|
||
|
|
- msg: format!("read_db_internal failed: {}", e),
|
||
|
|
- source: e.get_errno(),
|
||
|
|
- })
|
||
|
|
}
|
||
|
|
|
||
|
|
/// get properties nulstr, if it is out of date, update it
|
||
|
|
@@ -1836,10 +1674,7 @@ impl Device {
|
||
|
|
}
|
||
|
|
|
||
|
|
// verify subsystem
|
||
|
|
- let subsystem_ret = device.get_subsystem().map_err(|e| Error::Nix {
|
||
|
|
- msg: format!("from_mode_and_devnum failed: {}", e),
|
||
|
|
- source: e.get_errno(),
|
||
|
|
- })?;
|
||
|
|
+ let subsystem_ret = device.get_subsystem()?;
|
||
|
|
if (subsystem_ret == "block") != ((mode & S_IFMT) == S_IFBLK) {
|
||
|
|
return Err(Error::Nix {
|
||
|
|
msg: "from_mode_and_devnum failed: inconsistent subsystem".to_string(),
|
||
|
|
@@ -1942,19 +1777,9 @@ impl Device {
|
||
|
|
|
||
|
|
/// set the sysname and sysnum of device object
|
||
|
|
pub fn set_sysname_and_sysnum(&self) -> Result<(), Error> {
|
||
|
|
- let sysname = match self.devpath.borrow().rfind('/') {
|
||
|
|
- Some(i) => String::from(&self.devpath.borrow()[i + 1..]),
|
||
|
|
- None => {
|
||
|
|
- return Err(Error::Nix {
|
||
|
|
- msg: format!(
|
||
|
|
- "set_sysname_and_sysnum failed: invalid devpath '{}'",
|
||
|
|
- self.devpath.borrow()
|
||
|
|
- ),
|
||
|
|
- source: Errno::EINVAL,
|
||
|
|
- });
|
||
|
|
- }
|
||
|
|
- };
|
||
|
|
-
|
||
|
|
+ /* The devpath is validated to begin with '/' when setting syspath. */
|
||
|
|
+ let idx = self.devpath.borrow().rfind('/').unwrap();
|
||
|
|
+ let sysname = String::from(&self.devpath.borrow()[idx + 1..]);
|
||
|
|
let sysname = sysname.replace('!', "/");
|
||
|
|
|
||
|
|
let mut ridx = sysname.len();
|
||
|
|
@@ -2146,15 +1971,10 @@ impl Device {
|
||
|
|
/// set ifindex
|
||
|
|
pub fn set_ifindex(&self, ifindex: &str) -> Result<(), Error> {
|
||
|
|
self.add_property_internal("IFINDEX", ifindex).unwrap();
|
||
|
|
- self.ifindex.replace(match ifindex.parse::<u32>() {
|
||
|
|
- Ok(idx) => idx,
|
||
|
|
- Err(e) => {
|
||
|
|
- return Err(Error::Nix {
|
||
|
|
- msg: format!("set_ifindex failed: {}", e),
|
||
|
|
- source: Errno::EINVAL,
|
||
|
|
- });
|
||
|
|
- }
|
||
|
|
- });
|
||
|
|
+ self.ifindex
|
||
|
|
+ .replace(ifindex.parse::<u32>().context(ParseInt {
|
||
|
|
+ msg: format!("invalid integer '{}'", ifindex),
|
||
|
|
+ })?);
|
||
|
|
Ok(())
|
||
|
|
}
|
||
|
|
|
||
|
|
@@ -2172,12 +1992,8 @@ impl Device {
|
||
|
|
|
||
|
|
/// set devmode
|
||
|
|
pub fn set_devmode(&self, devmode: &str) -> Result<(), Error> {
|
||
|
|
- let m = Some(mode_t::from_str_radix(devmode, 8).map_err(|e| Error::Nix {
|
||
|
|
- msg: format!(
|
||
|
|
- "set_devmode failed: can't change '{}' to mode: {}",
|
||
|
|
- devmode, e
|
||
|
|
- ),
|
||
|
|
- source: Errno::EINVAL,
|
||
|
|
+ let m = Some(mode_t::from_str_radix(devmode, 8).context(ParseInt {
|
||
|
|
+ msg: format!("invalid octal mode '{}'", devmode),
|
||
|
|
})?);
|
||
|
|
|
||
|
|
self.devmode.replace(m);
|
||
|
|
@@ -2189,9 +2005,8 @@ impl Device {
|
||
|
|
|
||
|
|
/// set device uid
|
||
|
|
pub fn set_devuid(&self, devuid: &str) -> Result<(), Error> {
|
||
|
|
- let uid = devuid.parse::<uid_t>().map_err(|e| Error::Nix {
|
||
|
|
- msg: format!("set_devuid failed: can't change '{}' to uid: {}", devuid, e),
|
||
|
|
- source: Errno::EINVAL,
|
||
|
|
+ let uid = devuid.parse::<uid_t>().context(ParseInt {
|
||
|
|
+ msg: format!("invalid uid '{}'", devuid),
|
||
|
|
})?;
|
||
|
|
|
||
|
|
self.devuid.replace(Some(Uid::from_raw(uid)));
|
||
|
|
@@ -2203,9 +2018,8 @@ impl Device {
|
||
|
|
|
||
|
|
/// set device gid
|
||
|
|
pub fn set_devgid(&self, devgid: &str) -> Result<(), Error> {
|
||
|
|
- let gid = devgid.parse::<gid_t>().map_err(|e| Error::Nix {
|
||
|
|
- msg: format!("set_devgid failed: can't change '{}' to gid: {}", devgid, e),
|
||
|
|
- source: Errno::EINVAL,
|
||
|
|
+ let gid = devgid.parse::<gid_t>().context(ParseInt {
|
||
|
|
+ msg: format!("invalid gid '{}'", devgid),
|
||
|
|
})?;
|
||
|
|
|
||
|
|
self.devgid.replace(Some(Gid::from_raw(gid)));
|
||
|
|
@@ -2217,15 +2031,10 @@ impl Device {
|
||
|
|
|
||
|
|
/// set devnum
|
||
|
|
pub fn set_devnum(&self, major: &str, minor: &str) -> Result<(), Error> {
|
||
|
|
- let major_num: u64 = match major.parse() {
|
||
|
|
- Ok(n) => n,
|
||
|
|
- Err(e) => {
|
||
|
|
- return Err(Error::Nix {
|
||
|
|
- msg: format!("set_devnum failed: invalid major number '{}': {}", major, e),
|
||
|
|
- source: Errno::EINVAL,
|
||
|
|
- });
|
||
|
|
- }
|
||
|
|
- };
|
||
|
|
+ let major_num: u64 = major.parse().context(ParseInt {
|
||
|
|
+ msg: format!("invalid major number '{}'", major),
|
||
|
|
+ })?;
|
||
|
|
+
|
||
|
|
let minor_num: u64 = match minor.parse() {
|
||
|
|
Ok(n) => n,
|
||
|
|
Err(e) => {
|
||
|
|
@@ -2247,15 +2056,9 @@ impl Device {
|
||
|
|
pub fn set_diskseq(&self, diskseq: &str) -> Result<(), Error> {
|
||
|
|
self.add_property_internal("DISKSEQ", diskseq).unwrap();
|
||
|
|
|
||
|
|
- let diskseq_num: u64 = match diskseq.parse() {
|
||
|
|
- Ok(n) => n,
|
||
|
|
- Err(e) => {
|
||
|
|
- return Err(Error::Nix {
|
||
|
|
- msg: format!("set_diskseq failed: invalid diskseq '{}': {}", diskseq, e),
|
||
|
|
- source: Errno::EINVAL,
|
||
|
|
- });
|
||
|
|
- }
|
||
|
|
- };
|
||
|
|
+ let diskseq_num: u64 = diskseq.parse().context(ParseInt {
|
||
|
|
+ msg: format!("invalid diskseq '{}'", diskseq),
|
||
|
|
+ })?;
|
||
|
|
|
||
|
|
self.diskseq.replace(diskseq_num);
|
||
|
|
|
||
|
|
@@ -2271,18 +2074,7 @@ impl Device {
|
||
|
|
|
||
|
|
/// set action from string
|
||
|
|
pub fn set_action_from_string(&self, action_s: &str) -> Result<(), Error> {
|
||
|
|
- let action = match action_s.parse::<DeviceAction>() {
|
||
|
|
- Ok(a) => a,
|
||
|
|
- Err(_) => {
|
||
|
|
- return Err(Error::Nix {
|
||
|
|
- msg: format!(
|
||
|
|
- "set_action_from_string failed: invalid action '{}'",
|
||
|
|
- action_s
|
||
|
|
- ),
|
||
|
|
- source: Errno::EINVAL,
|
||
|
|
- });
|
||
|
|
- }
|
||
|
|
- };
|
||
|
|
+ let action = action_s.parse::<DeviceAction>()?;
|
||
|
|
|
||
|
|
self.set_action(action);
|
||
|
|
|
||
|
|
@@ -2291,19 +2083,9 @@ impl Device {
|
||
|
|
|
||
|
|
/// set seqnum from string
|
||
|
|
pub fn set_seqnum_from_string(&self, seqnum_s: &str) -> Result<(), Error> {
|
||
|
|
- let seqnum: u64 = match seqnum_s.parse() {
|
||
|
|
- Ok(n) => n,
|
||
|
|
- Err(_) => {
|
||
|
|
- return Err(Error::Nix {
|
||
|
|
- msg: format!(
|
||
|
|
- "set_seqnum_from_string failed: invalid seqnum '{}'",
|
||
|
|
- seqnum_s
|
||
|
|
- ),
|
||
|
|
- source: Errno::EINVAL,
|
||
|
|
- });
|
||
|
|
- }
|
||
|
|
- };
|
||
|
|
-
|
||
|
|
+ let seqnum: u64 = seqnum_s.parse().context(ParseInt {
|
||
|
|
+ msg: format!("invalid seqnum '{}'", seqnum_s),
|
||
|
|
+ })?;
|
||
|
|
self.set_seqnum(seqnum);
|
||
|
|
Ok(())
|
||
|
|
}
|
||
|
|
@@ -2325,7 +2107,7 @@ impl Device {
|
||
|
|
/// cache sysattr value
|
||
|
|
pub fn cache_sysattr_value(&self, sysattr: &str, value: &str) -> Result<(), Error> {
|
||
|
|
if value.is_empty() {
|
||
|
|
- self.remove_cached_sysattr_value(sysattr)?;
|
||
|
|
+ self.remove_cached_sysattr_value(sysattr);
|
||
|
|
} else {
|
||
|
|
self.sysattr_values
|
||
|
|
.borrow_mut()
|
||
|
|
@@ -2336,34 +2118,27 @@ impl Device {
|
||
|
|
}
|
||
|
|
|
||
|
|
/// remove cached sysattr value
|
||
|
|
- pub fn remove_cached_sysattr_value(&self, sysattr: &str) -> Result<(), Error> {
|
||
|
|
+ pub fn remove_cached_sysattr_value(&self, sysattr: &str) {
|
||
|
|
self.sysattr_values.borrow_mut().remove(sysattr);
|
||
|
|
-
|
||
|
|
- Ok(())
|
||
|
|
}
|
||
|
|
|
||
|
|
/// get cached sysattr value
|
||
|
|
pub fn get_cached_sysattr_value(&self, sysattr: &str) -> Result<String, Error> {
|
||
|
|
if !self.sysattr_values.borrow().contains_key(sysattr) {
|
||
|
|
return Err(Error::Nix {
|
||
|
|
- msg: format!(
|
||
|
|
- "get_cached_sysattr_value failed: no cached sysattr '{}'",
|
||
|
|
- sysattr
|
||
|
|
- ),
|
||
|
|
+ msg: format!("no cached sysattr '{}'", sysattr),
|
||
|
|
source: Errno::ESTALE,
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
- match self.sysattr_values.borrow().get(sysattr) {
|
||
|
|
- Some(value) => Ok(value.clone()),
|
||
|
|
- None => Err(Error::Nix {
|
||
|
|
- msg: format!(
|
||
|
|
- "get_cached_sysattr_value failed: non-existing sysattr '{}'",
|
||
|
|
- sysattr
|
||
|
|
- ),
|
||
|
|
+ self.sysattr_values
|
||
|
|
+ .borrow()
|
||
|
|
+ .get(sysattr)
|
||
|
|
+ .cloned()
|
||
|
|
+ .ok_or(Error::Nix {
|
||
|
|
+ msg: format!("non-existing sysattr '{}'", sysattr),
|
||
|
|
source: Errno::ENOENT,
|
||
|
|
- }),
|
||
|
|
- }
|
||
|
|
+ })
|
||
|
|
}
|
||
|
|
|
||
|
|
/// new from child
|
||
|
|
@@ -2378,8 +2153,7 @@ impl Device {
|
||
|
|
Some(p) => {
|
||
|
|
if p == Path::new("/sys") {
|
||
|
|
return Err(Error::Nix {
|
||
|
|
- msg: "new_from_child failed: no available parent device until /sys"
|
||
|
|
- .to_string(),
|
||
|
|
+ msg: "no available parent device".to_string(),
|
||
|
|
source: Errno::ENODEV,
|
||
|
|
});
|
||
|
|
}
|
||
|
|
@@ -2387,7 +2161,7 @@ impl Device {
|
||
|
|
let path = p
|
||
|
|
.to_str()
|
||
|
|
.ok_or(Error::Nix {
|
||
|
|
- msg: format!("new_from_child failed: invalid path '{:?}'", p),
|
||
|
|
+ msg: format!("invalid path '{:?}'", p),
|
||
|
|
source: Errno::ENODEV,
|
||
|
|
})?
|
||
|
|
.to_string();
|
||
|
|
@@ -2444,15 +2218,9 @@ impl Device {
|
||
|
|
/// 3. if self devlinks are outdated, add to internal property
|
||
|
|
/// 4. if self tags are outdated ,add to internal property
|
||
|
|
pub fn properties_prepare(&self) -> Result<(), Error> {
|
||
|
|
- self.read_uevent_file().map_err(|e| Error::Nix {
|
||
|
|
- msg: format!("properties_prepare failed: {}", e),
|
||
|
|
- source: e.get_errno(),
|
||
|
|
- })?;
|
||
|
|
+ self.read_uevent_file()?;
|
||
|
|
|
||
|
|
- self.read_db().map_err(|e| Error::Nix {
|
||
|
|
- msg: format!("properties_prepare failed: {}", e),
|
||
|
|
- source: e.get_errno(),
|
||
|
|
- })?;
|
||
|
|
+ self.read_db()?;
|
||
|
|
|
||
|
|
let property_devlinks_outdated = *self.property_devlinks_outdated.borrow();
|
||
|
|
if property_devlinks_outdated {
|
||
|
|
@@ -2518,15 +2286,8 @@ impl Device {
|
||
|
|
};
|
||
|
|
|
||
|
|
let mut buf = String::new();
|
||
|
|
- file.read_to_string(&mut buf).map_err(|e| Error::Nix {
|
||
|
|
- msg: format!(
|
||
|
|
- "read_db_internal_filename failed: can't read db '{}': {}",
|
||
|
|
- filename, e
|
||
|
|
- ),
|
||
|
|
- source: e
|
||
|
|
- .raw_os_error()
|
||
|
|
- .map(nix::Error::from_i32)
|
||
|
|
- .unwrap_or(nix::Error::EIO),
|
||
|
|
+ file.read_to_string(&mut buf).context(Io {
|
||
|
|
+ msg: format!("can't read db '{}'", filename),
|
||
|
|
})?;
|
||
|
|
|
||
|
|
self.is_initialized.replace(true);
|
||
|
|
@@ -2540,10 +2301,7 @@ impl Device {
|
||
|
|
let key = &line[0..1];
|
||
|
|
let value = &line[2..];
|
||
|
|
|
||
|
|
- self.handle_db_line(key, value).map_err(|e| Error::Nix {
|
||
|
|
- msg: format!("read_db_internal_filename failed: {}", e),
|
||
|
|
- source: e.get_errno(),
|
||
|
|
- })?;
|
||
|
|
+ self.handle_db_line(key, value)?;
|
||
|
|
}
|
||
|
|
|
||
|
|
Ok(())
|
||
|
|
@@ -2572,29 +2330,18 @@ impl Device {
|
||
|
|
|
||
|
|
let (k, v) = (tokens[0], tokens[1]);
|
||
|
|
|
||
|
|
- self.add_property_internal(k, v).map_err(|e| Error::Nix {
|
||
|
|
- msg: format!("handle_db_line failed: {}", e),
|
||
|
|
- source: e.get_errno(),
|
||
|
|
- })?;
|
||
|
|
+ self.add_property_internal(k, v)?;
|
||
|
|
}
|
||
|
|
"I" => {
|
||
|
|
- let time = value.parse::<u64>().map_err(|e| Error::Nix {
|
||
|
|
- msg: format!(
|
||
|
|
- "handle_db_line failed: invalid initialized time '{}': {}",
|
||
|
|
- value, e
|
||
|
|
- ),
|
||
|
|
- source: Errno::EINVAL,
|
||
|
|
+ let time = value.parse::<u64>().context(ParseInt {
|
||
|
|
+ msg: format!("invalid usec integer '{}'", value),
|
||
|
|
})?;
|
||
|
|
|
||
|
|
self.set_usec_initialized(time);
|
||
|
|
}
|
||
|
|
"L" => {
|
||
|
|
- let priority = value.parse::<i32>().map_err(|e| Error::Nix {
|
||
|
|
- msg: format!(
|
||
|
|
- "handle_db_line failed: failed to parse devlink priority '{}': {}",
|
||
|
|
- value, e
|
||
|
|
- ),
|
||
|
|
- source: Errno::EINVAL,
|
||
|
|
+ let priority = value.parse::<i32>().context(ParseInt {
|
||
|
|
+ msg: format!("invalid link priority integer '{}'", value),
|
||
|
|
})?;
|
||
|
|
|
||
|
|
self.devlink_priority.replace(priority);
|
||
|
|
@@ -2603,12 +2350,8 @@ impl Device {
|
||
|
|
log::debug!("watch handle in database is deprecated.");
|
||
|
|
}
|
||
|
|
"V" => {
|
||
|
|
- let version = value.parse::<u32>().map_err(|e| Error::Nix {
|
||
|
|
- msg: format!(
|
||
|
|
- "handle_db_line failed: failed to parse database version '{}': {}",
|
||
|
|
- value, e
|
||
|
|
- ),
|
||
|
|
- source: Errno::EINVAL,
|
||
|
|
+ let version = value.parse::<u32>().context(ParseInt {
|
||
|
|
+ msg: format!("invalid db version integer '{}'", value),
|
||
|
|
})?;
|
||
|
|
|
||
|
|
self.database_version.replace(version);
|
||
|
|
@@ -2625,22 +2368,11 @@ impl Device {
|
||
|
|
pub fn shallow_clone(&self) -> Result<Device, Error> {
|
||
|
|
let device = Self::default();
|
||
|
|
|
||
|
|
- let syspath = self.get_syspath().map_err(|e| Error::Nix {
|
||
|
|
- msg: format!("shallow_clone failed: {}", e),
|
||
|
|
- source: e.get_errno(),
|
||
|
|
- })?;
|
||
|
|
+ let syspath = self.get_syspath()?;
|
||
|
|
|
||
|
|
- device
|
||
|
|
- .set_syspath(&syspath, false)
|
||
|
|
- .map_err(|e| Error::Nix {
|
||
|
|
- msg: format!("shallow_clone failed: {}", e),
|
||
|
|
- source: e.get_errno(),
|
||
|
|
- })?;
|
||
|
|
+ device.set_syspath(&syspath, false)?;
|
||
|
|
|
||
|
|
- let subsystem = self.get_subsystem().map_err(|e| Error::Nix {
|
||
|
|
- msg: format!("shallow_clone failed: {}", e),
|
||
|
|
- source: e.get_errno(),
|
||
|
|
- })?;
|
||
|
|
+ let subsystem = self.get_subsystem()?;
|
||
|
|
|
||
|
|
device.set_subsystem(&subsystem);
|
||
|
|
|
||
|
|
@@ -2651,24 +2383,15 @@ impl Device {
|
||
|
|
}
|
||
|
|
|
||
|
|
if let Ok(ifindex) = self.get_property_value("IFINDEX") {
|
||
|
|
- device.set_ifindex(&ifindex).map_err(|e| Error::Nix {
|
||
|
|
- msg: format!("shallow_clone failed: failed to set_ifindex ({})", e),
|
||
|
|
- source: e.get_errno(),
|
||
|
|
- })?;
|
||
|
|
+ device.set_ifindex(&ifindex)?;
|
||
|
|
}
|
||
|
|
|
||
|
|
if let Ok(major) = self.get_property_value("MAJOR") {
|
||
|
|
let minor = self.get_property_value("MINOR")?;
|
||
|
|
- device.set_devnum(&major, &minor).map_err(|e| Error::Nix {
|
||
|
|
- msg: format!("shallow_clone failed: {}", e),
|
||
|
|
- source: e.get_errno(),
|
||
|
|
- })?;
|
||
|
|
+ device.set_devnum(&major, &minor)?;
|
||
|
|
}
|
||
|
|
|
||
|
|
- device.read_uevent_file().map_err(|e| Error::Nix {
|
||
|
|
- msg: format!("shallow_clone failed: {}", e),
|
||
|
|
- source: e.get_errno(),
|
||
|
|
- })?;
|
||
|
|
+ device.read_uevent_file()?;
|
||
|
|
|
||
|
|
Ok(device)
|
||
|
|
}
|
||
|
|
@@ -2685,12 +2408,8 @@ impl Device {
|
||
|
|
"DRIVER" => self.set_driver(value),
|
||
|
|
"IFINDEX" => self.set_ifindex(value)?,
|
||
|
|
"USEC_INITIALIZED" => {
|
||
|
|
- self.set_usec_initialized(value.parse::<u64>().map_err(|e| Error::Nix {
|
||
|
|
- msg: format!(
|
||
|
|
- "amend_key_value failed: failed to parse initialized time '{}': {}",
|
||
|
|
- value, e
|
||
|
|
- ),
|
||
|
|
- source: Errno::EINVAL,
|
||
|
|
+ self.set_usec_initialized(value.parse::<u64>().context(ParseInt {
|
||
|
|
+ msg: format!("invalid usec integer '{}'", value),
|
||
|
|
})?);
|
||
|
|
}
|
||
|
|
"DEVMODE" => self.set_devmode(value)?,
|
||
|
|
@@ -2814,9 +2533,8 @@ impl Device {
|
||
|
|
format!("{}/{}", syspath, subdir)
|
||
|
|
};
|
||
|
|
|
||
|
|
- std::fs::read_dir(&dir).map_err(|e| Error::Nix {
|
||
|
|
+ std::fs::read_dir(&dir).context(Io {
|
||
|
|
msg: format!("Failed to read directory '{}'", &dir),
|
||
|
|
- source: nix::Error::from_i32(e.raw_os_error().unwrap_or_default()),
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
@@ -3017,7 +2735,7 @@ impl Device {
|
||
|
|
log::debug!(
|
||
|
|
"failed to read db of '{}': {}",
|
||
|
|
self.get_device_id()
|
||
|
|
- .unwrap_or(self.devpath.borrow().clone()),
|
||
|
|
+ .unwrap_or_else(|_| self.devpath.borrow().clone()),
|
||
|
|
e
|
||
|
|
)
|
||
|
|
}
|
||
|
|
@@ -3033,7 +2751,7 @@ impl Device {
|
||
|
|
log::error!(
|
||
|
|
"failed to read db of '{}': {}",
|
||
|
|
self.get_device_id()
|
||
|
|
- .unwrap_or(self.devpath.borrow().clone()),
|
||
|
|
+ .unwrap_or_else(|_| self.devpath.borrow().clone()),
|
||
|
|
e
|
||
|
|
)
|
||
|
|
}
|
||
|
|
@@ -3049,7 +2767,7 @@ impl Device {
|
||
|
|
log::debug!(
|
||
|
|
"failed to read db of '{}': {}",
|
||
|
|
self.get_device_id()
|
||
|
|
- .unwrap_or(self.devpath.borrow().clone()),
|
||
|
|
+ .unwrap_or_else(|_| self.devpath.borrow().clone()),
|
||
|
|
e
|
||
|
|
)
|
||
|
|
}
|
||
|
|
@@ -3065,7 +2783,7 @@ impl Device {
|
||
|
|
log::debug!(
|
||
|
|
"failed to prepare properties of '{}': {}",
|
||
|
|
self.get_device_id()
|
||
|
|
- .unwrap_or(self.devpath.borrow().clone()),
|
||
|
|
+ .unwrap_or_else(|_| self.devpath.borrow().clone()),
|
||
|
|
e
|
||
|
|
)
|
||
|
|
}
|
||
|
|
@@ -3081,7 +2799,7 @@ impl Device {
|
||
|
|
log::debug!(
|
||
|
|
"failed to enumerate children of '{}': {}",
|
||
|
|
self.get_device_id()
|
||
|
|
- .unwrap_or(self.devpath.borrow().clone()),
|
||
|
|
+ .unwrap_or_else(|_| self.devpath.borrow().clone()),
|
||
|
|
e
|
||
|
|
)
|
||
|
|
}
|
||
|
|
@@ -3097,7 +2815,8 @@ impl Device {
|
||
|
|
if let Err(e) = self.read_all_sysattrs() {
|
||
|
|
log::debug!(
|
||
|
|
"{}: failed to read all sysattrs: {}",
|
||
|
|
- self.get_sysname().unwrap_or(self.devpath.borrow().clone()),
|
||
|
|
+ self.get_sysname()
|
||
|
|
+ .unwrap_or_else(|_| self.devpath.borrow().clone()),
|
||
|
|
e
|
||
|
|
);
|
||
|
|
}
|
||
|
|
@@ -3117,6 +2836,7 @@ impl PartialEq for Device {
|
||
|
|
|
||
|
|
#[cfg(test)]
|
||
|
|
mod tests {
|
||
|
|
+ use std::fs::OpenOptions;
|
||
|
|
use std::panic::catch_unwind;
|
||
|
|
|
||
|
|
use crate::{
|
||
|
|
@@ -3426,6 +3146,11 @@ mod tests {
|
||
|
|
nix::Error::EINVAL
|
||
|
|
);
|
||
|
|
|
||
|
|
+ /* Test other add_* methods. */
|
||
|
|
+ device.add_property("A", "AA").unwrap();
|
||
|
|
+ device.add_property("B", "BB").unwrap();
|
||
|
|
+ device.add_tags("A:B:C", true);
|
||
|
|
+
|
||
|
|
device.update_db().unwrap();
|
||
|
|
|
||
|
|
/* Test enumerating child devices */
|
||
|
|
@@ -3902,8 +3627,8 @@ Q:devmaster
|
||
|
|
V:100
|
||
|
|
";
|
||
|
|
touch_file("/tmp/tmp_db", false, None, None, None).unwrap();
|
||
|
|
- let mut f = File::options().write(true).open("/tmp/tmp_db").unwrap();
|
||
|
|
- f.write(content.as_bytes()).unwrap();
|
||
|
|
+ let mut f = OpenOptions::new().write(true).open("/tmp/tmp_db").unwrap();
|
||
|
|
+ f.write_all(content.as_bytes()).unwrap();
|
||
|
|
let device = Device::new();
|
||
|
|
device.read_db_internal_filename("/tmp/tmp_db").unwrap();
|
||
|
|
}
|
||
|
|
@@ -3912,8 +3637,8 @@ V:100
|
||
|
|
{
|
||
|
|
let content = "error
|
||
|
|
";
|
||
|
|
- let mut f = File::options().write(true).open("/tmp/tmp_db").unwrap();
|
||
|
|
- f.write(content.as_bytes()).unwrap();
|
||
|
|
+ let mut f = OpenOptions::new().write(true).open("/tmp/tmp_db").unwrap();
|
||
|
|
+ f.write_all(content.as_bytes()).unwrap();
|
||
|
|
let device = Device::new();
|
||
|
|
device.read_db_internal_filename("/tmp/tmp_db").unwrap();
|
||
|
|
}
|
||
|
|
@@ -3922,13 +3647,13 @@ V:100
|
||
|
|
{
|
||
|
|
let content = "I:invalid
|
||
|
|
";
|
||
|
|
- let mut f = File::options().write(true).open("/tmp/tmp_db").unwrap();
|
||
|
|
- f.write(content.as_bytes()).unwrap();
|
||
|
|
+ let mut f = OpenOptions::new().write(true).open("/tmp/tmp_db").unwrap();
|
||
|
|
+ f.write_all(content.as_bytes()).unwrap();
|
||
|
|
let device = Device::new();
|
||
|
|
assert!(device.read_db_internal_filename("/tmp/tmp_db").is_err());
|
||
|
|
}
|
||
|
|
|
||
|
|
- /* DB shoud be readable. */
|
||
|
|
+ /* DB should be readable. */
|
||
|
|
{
|
||
|
|
touch_file("/tmp/tmp_db_writeonly", false, Some(0o222), None, None).unwrap();
|
||
|
|
let device = Device::new();
|
||
|
|
@@ -3973,4 +3698,98 @@ V:100
|
||
|
|
})
|
||
|
|
.is_err());
|
||
|
|
}
|
||
|
|
+
|
||
|
|
+ #[test]
|
||
|
|
+ fn test_set() {
|
||
|
|
+ let device = Device::from_subsystem_sysname("net", "lo").unwrap();
|
||
|
|
+ device.set_devuid("1").unwrap();
|
||
|
|
+ device.set_devgid("1").unwrap();
|
||
|
|
+ device.set_devmode("666").unwrap();
|
||
|
|
+ device.set_diskseq("1").unwrap();
|
||
|
|
+ device.set_action_from_string("change").unwrap();
|
||
|
|
+ device.set_sysattr_value("ifalias", Some("test")).unwrap();
|
||
|
|
+
|
||
|
|
+ assert_eq!(&device.get_property_value("DEVUID").unwrap(), "1");
|
||
|
|
+ assert_eq!(&device.get_property_value("DEVGID").unwrap(), "1");
|
||
|
|
+ assert_eq!(&device.get_property_value("DEVMODE").unwrap(), "666");
|
||
|
|
+ assert_eq!(&device.get_property_value("DISKSEQ").unwrap(), "1");
|
||
|
|
+ assert_eq!(&device.get_property_value("ACTION").unwrap(), "change");
|
||
|
|
+ assert_eq!(&device.get_cached_sysattr_value("ifalias").unwrap(), "test");
|
||
|
|
+
|
||
|
|
+ assert!(device.set_devuid("invalid").is_err());
|
||
|
|
+ assert!(device.set_devgid("invalid").is_err());
|
||
|
|
+ assert!(device.set_devmode("invalid").is_err());
|
||
|
|
+ assert!(device.set_diskseq("invalid").is_err());
|
||
|
|
+ assert!(device.set_action_from_string("invalid").is_err());
|
||
|
|
+ assert!(device.set_sysattr_value("nonexist", Some("test")).is_err());
|
||
|
|
+
|
||
|
|
+ assert!(device.set_sysattr_value("nonexist", None).is_ok());
|
||
|
|
+ assert!(device.set_sysattr_value("ifalias", None).is_ok());
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ #[test]
|
||
|
|
+ fn test_from_device_id() {
|
||
|
|
+ assert!(Device::from_device_id("invalid").is_err());
|
||
|
|
+ assert!(Device::from_device_id("b").is_err());
|
||
|
|
+ assert!(Device::from_device_id("+drivers").is_err());
|
||
|
|
+ assert!(Device::from_device_id("+drivers:").is_err());
|
||
|
|
+ assert!(Device::from_device_id("+drivers::usb").is_err());
|
||
|
|
+
|
||
|
|
+ let dev = Device::from_device_id("+drivers:usb:usb").unwrap();
|
||
|
|
+ println!("{}", dev.get_device_id().unwrap());
|
||
|
|
+
|
||
|
|
+ let dev = Device::from_syspath("/sys/bus/usb/drivers/usb", true).unwrap();
|
||
|
|
+ println!("{}", dev.get_device_id().unwrap());
|
||
|
|
+
|
||
|
|
+ let _ = unlink("/tmp/devmaster/data/+drivers:usb:usb");
|
||
|
|
+ dev.set_base_path("/tmp/devmaster");
|
||
|
|
+ assert!(dev.update_db().is_err());
|
||
|
|
+ dev.add_property("hello", "world").unwrap();
|
||
|
|
+ dev.update_db().unwrap();
|
||
|
|
+ assert!(Path::new("/tmp/devmaster/data/+drivers:usb:usb").exists());
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ #[test]
|
||
|
|
+ fn test_get_err() {
|
||
|
|
+ let device = Device::new();
|
||
|
|
+ assert!(device.get_syspath().is_err());
|
||
|
|
+ assert!(device.get_devpath().is_err());
|
||
|
|
+ assert!(device.get_parent().is_err());
|
||
|
|
+ assert!(device.get_devtype().is_err());
|
||
|
|
+ assert!(!device.get_is_initialized().unwrap());
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ #[test]
|
||
|
|
+ fn test_cleanup() {
|
||
|
|
+ let _ = touch_file("/tmp/devmaster/a", false, None, None, None);
|
||
|
|
+ let _ = touch_file("/tmp/devmaster/b", false, None, None, None);
|
||
|
|
+ Device::cleanup("/tmp/devmaster/a", "/tmp/devmaster/b");
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ #[test]
|
||
|
|
+ fn test_fmt() {
|
||
|
|
+ let device = Device::from_subsystem_sysname("net", "lo").unwrap();
|
||
|
|
+ println!("{:?}", device);
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ #[test]
|
||
|
|
+ fn test_set_syspath_no_verify() {
|
||
|
|
+ let device = Device::new();
|
||
|
|
+ device.set_syspath("/sys/test", false).unwrap();
|
||
|
|
+
|
||
|
|
+ assert!(device.set_sysname_and_sysnum().is_ok());
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ #[test]
|
||
|
|
+ fn test_partial_eq_trait() {
|
||
|
|
+ let dev1 = Device::from_syspath("/sys/class/net/lo", true).unwrap();
|
||
|
|
+ let dev2 = Device::from_subsystem_sysname("net", "lo").unwrap();
|
||
|
|
+
|
||
|
|
+ assert!(dev1 == dev2);
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ #[test]
|
||
|
|
+ fn test_from_devnum_err() {
|
||
|
|
+ assert!(Device::from_devnum('x', 100).is_err());
|
||
|
|
+ }
|
||
|
|
}
|
||
|
|
diff --git a/libs/device/src/device_enumerator.rs b/libs/device/src/device_enumerator.rs
|
||
|
|
index 96cac2d9..55f8681d 100644
|
||
|
|
--- a/libs/device/src/device_enumerator.rs
|
||
|
|
+++ b/libs/device/src/device_enumerator.rs
|
||
|
|
@@ -12,7 +12,7 @@
|
||
|
|
|
||
|
|
//! enumerate /sys to collect devices
|
||
|
|
//!
|
||
|
|
-use crate::{device::Device, err_wrapper, error::Error, utils::*};
|
||
|
|
+use crate::{device::Device, error::Error, utils::*};
|
||
|
|
use bitflags::bitflags;
|
||
|
|
use fnmatch_sys::fnmatch;
|
||
|
|
use nix::errno::Errno;
|
||
|
|
@@ -45,7 +45,7 @@ impl Default for MatchInitializedType {
|
||
|
|
}
|
||
|
|
|
||
|
|
/// enumerate devices or subsystems under /sys
|
||
|
|
-#[derive(Debug, Default)]
|
||
|
|
+#[derive(Default)]
|
||
|
|
pub struct DeviceEnumerator {
|
||
|
|
/// enumerator type
|
||
|
|
pub(crate) etype: RefCell<DeviceEnumerationType>,
|
||
|
|
@@ -289,7 +289,7 @@ impl DeviceEnumerator {
|
||
|
|
|
||
|
|
/// add match parent
|
||
|
|
pub fn add_match_parent_incremental(&mut self, parent: &Device) -> Result<(), Error> {
|
||
|
|
- let syspath = err_wrapper!(parent.get_syspath(), "add_match_parent_incremental")?;
|
||
|
|
+ let syspath = parent.get_syspath()?;
|
||
|
|
self.match_parent.borrow_mut().insert(syspath);
|
||
|
|
self.scan_up_to_date.replace(false);
|
||
|
|
Ok(())
|
||
|
|
@@ -364,7 +364,7 @@ impl DeviceEnumerator {
|
||
|
|
// remove already sorted devices from the hashmap (self.devices_by_syspath)
|
||
|
|
// avoid get repeated devices from the hashmap later
|
||
|
|
for device in devices.iter().skip(m) {
|
||
|
|
- let syspath = err_wrapper!(device.borrow().get_syspath(), "sort_devices")?;
|
||
|
|
+ let syspath = device.borrow().get_syspath()?;
|
||
|
|
|
||
|
|
self.devices_by_syspath.borrow_mut().remove(&syspath);
|
||
|
|
}
|
||
|
|
@@ -400,7 +400,7 @@ impl DeviceEnumerator {
|
||
|
|
|
||
|
|
/// add device
|
||
|
|
pub(crate) fn add_device(&self, device: Rc<RefCell<Device>>) -> Result<bool, Error> {
|
||
|
|
- let syspath = err_wrapper!(device.borrow().get_syspath(), "add_device")?;
|
||
|
|
+ let syspath = device.borrow().get_syspath()?;
|
||
|
|
|
||
|
|
match self.devices_by_syspath.borrow_mut().insert(syspath, device) {
|
||
|
|
Some(_) => {
|
||
|
|
diff --git a/libs/device/src/device_monitor.rs b/libs/device/src/device_monitor.rs
|
||
|
|
index 729a7dcb..db51c40f 100644
|
||
|
|
--- a/libs/device/src/device_monitor.rs
|
||
|
|
+++ b/libs/device/src/device_monitor.rs
|
||
|
|
@@ -250,7 +250,7 @@ mod tests {
|
||
|
|
///
|
||
|
|
fn dispatch(&self, e: &Events) -> i32 {
|
||
|
|
let device = self.device_monitor.receive_device().unwrap();
|
||
|
|
- println!("{:?}", device);
|
||
|
|
+ println!("{}", device.get_device_id().unwrap());
|
||
|
|
e.set_exit();
|
||
|
|
0
|
||
|
|
}
|
||
|
|
diff --git a/libs/device/src/error.rs b/libs/device/src/error.rs
|
||
|
|
index 40589c21..10410301 100644
|
||
|
|
--- a/libs/device/src/error.rs
|
||
|
|
+++ b/libs/device/src/error.rs
|
||
|
|
@@ -38,6 +38,24 @@ pub enum Error {
|
||
|
|
|
||
|
|
#[snafu(context, display("Basic error: {}", msg))]
|
||
|
|
Basic { msg: String, source: basic::Error },
|
||
|
|
+
|
||
|
|
+ #[snafu(context, display("Failed to parse boolean: {}", msg))]
|
||
|
|
+ ParseBool {
|
||
|
|
+ msg: String,
|
||
|
|
+ source: std::str::ParseBoolError,
|
||
|
|
+ },
|
||
|
|
+
|
||
|
|
+ #[snafu(context, display("Failed to parse integer: {}", msg))]
|
||
|
|
+ ParseInt {
|
||
|
|
+ msg: String,
|
||
|
|
+ source: std::num::ParseIntError,
|
||
|
|
+ },
|
||
|
|
+
|
||
|
|
+ #[snafu(context, display("Failed to parse utf-8: {}", msg))]
|
||
|
|
+ FromUtf8 {
|
||
|
|
+ msg: String,
|
||
|
|
+ source: std::string::FromUtf8Error,
|
||
|
|
+ },
|
||
|
|
}
|
||
|
|
|
||
|
|
impl Error {
|
||
|
|
@@ -53,21 +71,13 @@ impl Error {
|
||
|
|
source: errno,
|
||
|
|
} => Errno::from_i32(errno.raw_os_error().unwrap_or_default()),
|
||
|
|
Self::Basic { msg: _, source } => Errno::from_i32(source.get_errno()),
|
||
|
|
+ Self::ParseBool { msg: _, source: _ } => nix::Error::EINVAL,
|
||
|
|
+ Self::ParseInt { msg: _, source: _ } => nix::Error::EINVAL,
|
||
|
|
+ Self::FromUtf8 { msg: _, source: _ } => nix::Error::EINVAL,
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
-/// append current function and inherit the errno
|
||
|
|
-#[macro_export]
|
||
|
|
-macro_rules! err_wrapper {
|
||
|
|
- ($e:expr, $s:expr) => {
|
||
|
|
- $e.map_err(|e| Error::Nix {
|
||
|
|
- msg: format!("$s failed: {}", e),
|
||
|
|
- source: e.get_errno(),
|
||
|
|
- })
|
||
|
|
- };
|
||
|
|
-}
|
||
|
|
-
|
||
|
|
impl Error {
|
||
|
|
/// check whether the device error belongs to specific errno
|
||
|
|
pub fn is_errno(&self, errno: nix::Error) -> bool {
|
||
|
|
@@ -81,4 +91,37 @@ impl Error {
|
||
|
|
Errno::ENODEV | Errno::ENXIO | Errno::ENOENT
|
||
|
|
)
|
||
|
|
}
|
||
|
|
+
|
||
|
|
+ pub(crate) fn replace_errno(self, from: Errno, to: Errno) -> Self {
|
||
|
|
+ let n = self.get_errno();
|
||
|
|
+
|
||
|
|
+ if n == from {
|
||
|
|
+ Self::Nix {
|
||
|
|
+ msg: self.to_string(),
|
||
|
|
+ source: to,
|
||
|
|
+ }
|
||
|
|
+ } else {
|
||
|
|
+ self
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+
|
||
|
|
+#[cfg(test)]
|
||
|
|
+mod test {
|
||
|
|
+ use super::*;
|
||
|
|
+ use nix::errno::Errno;
|
||
|
|
+
|
||
|
|
+ #[test]
|
||
|
|
+ fn test_replace_errno() {
|
||
|
|
+ let e = Error::Nix {
|
||
|
|
+ msg: "test".to_string(),
|
||
|
|
+ source: Errno::ENOENT,
|
||
|
|
+ };
|
||
|
|
+
|
||
|
|
+ assert_eq!(
|
||
|
|
+ Errno::ENOEXEC,
|
||
|
|
+ e.replace_errno(Errno::ENOENT, Errno::ENOEXEC).get_errno(),
|
||
|
|
+ );
|
||
|
|
+ }
|
||
|
|
}
|
||
|
|
--
|
||
|
|
2.33.0
|
||
|
|
|