sysmaster/backport-test-device-add-UT-for-device-enumerator.patch

1112 lines
39 KiB
Diff
Raw Permalink Normal View History

2023-12-07 00:19:38 +08:00
From 83cae246941e5b2c95d5c9a12746983a18f6c157 Mon Sep 17 00:00:00 2001
From: chenjiayi <chenjiayi22@huawei.com>
Date: Wed, 15 Nov 2023 15:29:02 +0800
Subject: [PATCH 061/103] test(device): add UT for device enumerator
---
libs/device/src/device_enumerator.rs | 720 ++++++++++++++-------------
libs/device/src/error.rs | 6 +-
2 files changed, 365 insertions(+), 361 deletions(-)
diff --git a/libs/device/src/device_enumerator.rs b/libs/device/src/device_enumerator.rs
index 55f8681d..29391e0b 100644
--- a/libs/device/src/device_enumerator.rs
+++ b/libs/device/src/device_enumerator.rs
@@ -12,10 +12,11 @@
//! enumerate /sys to collect devices
//!
-use crate::{device::Device, error::Error, utils::*};
+use crate::{device::Device, error::*, utils::*, TAGS_BASE_DIR};
use bitflags::bitflags;
use fnmatch_sys::fnmatch;
use nix::errno::Errno;
+use snafu::ResultExt;
use std::{
cell::RefCell,
collections::{HashMap, HashSet},
@@ -45,7 +46,6 @@ impl Default for MatchInitializedType {
}
/// enumerate devices or subsystems under /sys
-#[derive(Default)]
pub struct DeviceEnumerator {
/// enumerator type
pub(crate) etype: RefCell<DeviceEnumerationType>,
@@ -91,6 +91,40 @@ pub struct DeviceEnumerator {
/// how to match device
pub(crate) match_initialized: RefCell<MatchInitializedType>,
+
+ /// the base directory path to contain runtime temporary files of device database, tags, etc.
+ pub(crate) base_path: RefCell<String>,
+}
+
+impl Default for DeviceEnumerator {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+impl DeviceEnumerator {
+ /// create a default instance of DeviceEnumerator
+ pub fn new() -> Self {
+ Self {
+ etype: RefCell::new(DeviceEnumerationType::All),
+ devices_by_syspath: RefCell::new(HashMap::new()),
+ devices: RefCell::new(Vec::new()),
+ scan_up_to_date: RefCell::new(false),
+ sorted: RefCell::new(false),
+ prioritized_subsystems: RefCell::new(Vec::new()),
+ match_subsystem: RefCell::new(HashSet::new()),
+ not_match_subsystem: RefCell::new(HashSet::new()),
+ match_sysattr: RefCell::new(HashMap::new()),
+ not_match_sysattr: RefCell::new(HashMap::new()),
+ match_property: RefCell::new(HashMap::new()),
+ match_sysname: RefCell::new(HashSet::new()),
+ not_match_sysname: RefCell::new(HashSet::new()),
+ match_tag: RefCell::new(HashSet::new()),
+ match_parent: RefCell::new(HashSet::new()),
+ match_initialized: RefCell::new(MatchInitializedType::ALL),
+ base_path: RefCell::new(crate::DEFAULT_BASE_DIR.to_string()),
+ }
+ }
}
/// decide enumerate devices or subsystems
@@ -186,11 +220,6 @@ bitflags! {
/// public methods
impl DeviceEnumerator {
- /// create a default instance of DeviceEnumerator
- pub fn new() -> DeviceEnumerator {
- DeviceEnumerator::default()
- }
-
/// set the enumerator type
pub fn set_enumerator_type(&mut self, etype: DeviceEnumerationType) {
if *self.etype.borrow() != etype {
@@ -426,23 +455,11 @@ impl DeviceEnumerator {
for (property_pattern, value_pattern) in self.match_property.borrow().iter() {
for (property, value) in &device.property_iter() {
- if !self
- .pattern_match(property_pattern, property)
- .map_err(|e| Error::Nix {
- msg: format!("match_property failed: {}", e),
- source: e.get_errno(),
- })?
- {
+ if !self.pattern_match(property_pattern, property) {
continue;
}
- if self
- .pattern_match(value_pattern, value)
- .map_err(|e| Error::Nix {
- msg: format!("match_property failed: {}", e),
- source: e.get_errno(),
- })?
- {
+ if self.pattern_match(value_pattern, value) {
return Ok(true);
}
}
@@ -458,7 +475,7 @@ impl DeviceEnumerator {
}
/// check whether the sysname of a device matches
- pub(crate) fn match_sysname(&self, sysname: &str) -> Result<bool, Error> {
+ pub(crate) fn match_sysname(&self, sysname: &str) -> bool {
self.set_pattern_match(
&self.match_sysname.borrow(),
&self.not_match_sysname.borrow(),
@@ -473,7 +490,7 @@ impl DeviceEnumerator {
}
/// check whether the subsystem of a device matches
- pub(crate) fn match_subsystem(&self, subsystem: &str) -> Result<bool, Error> {
+ pub(crate) fn match_subsystem(&self, subsystem: &str) -> bool {
self.set_pattern_match(
&self.match_subsystem.borrow(),
&self.not_match_subsystem.borrow(),
@@ -529,7 +546,7 @@ impl DeviceEnumerator {
return Ok(true);
}
- self.pattern_match(patterns, &value)
+ Ok(self.pattern_match(patterns, &value))
}
/// check whether a device matches conditions according to flags
@@ -538,19 +555,8 @@ impl DeviceEnumerator {
device: &mut Device,
flags: MatchFlag,
) -> Result<bool, Error> {
- if (flags & MatchFlag::SYSNAME).bits() != 0 {
- match self.match_sysname(&device.get_sysname()?) {
- Ok(ret) => match ret {
- true => {}
- false => return Ok(false),
- },
- Err(e) => {
- return Err(Error::Nix {
- msg: format!("test_matches failed: match sysname failed: {}", e),
- source: e.get_errno(),
- })
- }
- }
+ if (flags & MatchFlag::SYSNAME).bits() != 0 && !self.match_sysname(&device.get_sysname()?) {
+ return Ok(false);
}
if (flags & MatchFlag::SUBSYSTEM).bits() != 0 {
@@ -568,87 +574,29 @@ impl DeviceEnumerator {
}
};
- match self.match_subsystem(&subsystem) {
- Ok(ret) => match ret {
- true => {}
- false => return Ok(false),
- },
- Err(e) => {
- return Err(Error::Nix {
- msg: format!("test_matches failed: match_subsystem ({})", e),
- source: e.get_errno(),
- });
- }
+ if !self.match_subsystem(&subsystem) {
+ return Ok(false);
}
}
- if (flags & MatchFlag::PARENT).bits() != 0 {
- match self.match_parent(device) {
- Ok(ret) => match ret {
- true => {}
- false => return Ok(false),
- },
- Err(e) => {
- return Err(Error::Nix {
- msg: format!("test_matches failed: match parent failed: {}", e),
- source: e.get_errno(),
- });
- }
- }
+ if (flags & MatchFlag::PARENT).bits() != 0 && !self.match_parent(device)? {
+ return Ok(false);
}
- if (flags & MatchFlag::TAG).bits() != 0 {
- match self.match_tag(device) {
- Ok(ret) => match ret {
- true => {}
- false => return Ok(false),
- },
- Err(e) => {
- return Err(Error::Nix {
- msg: format!("test_matches failed: match tag failed: {}", e),
- source: e.get_errno(),
- });
- }
- }
+ if (flags & MatchFlag::TAG).bits() != 0 && !self.match_tag(device)? {
+ return Ok(false);
}
- match self.match_initialized(device) {
- Ok(ret) => match ret {
- true => {}
- false => return Ok(false),
- },
- Err(e) => {
- return Err(Error::Nix {
- msg: format!("test_matches failed: match_initialized ({})", e),
- source: e.get_errno(),
- });
- }
+ if !self.match_initialized(device)? {
+ return Ok(false);
}
- match self.match_property(device) {
- Ok(ret) => match ret {
- true => {}
- false => return Ok(false),
- },
- Err(e) => {
- return Err(Error::Nix {
- msg: format!("test_matches failed: match property failed: {}", e),
- source: e.get_errno(),
- });
- }
+ if !self.match_property(device)? {
+ return Ok(false);
}
- match self.match_sysattr(device) {
- Ok(ret) => match ret {
- true => {}
- false => return Ok(false),
- },
- Err(e) => {
- return Err(Error::Nix {
- msg: format!("test_matches failed: match sysattr failed: {}", e),
- source: e.get_errno(),
- });
- }
+ if !self.match_sysattr(device)? {
+ return Ok(false);
}
Ok(true)
@@ -679,20 +627,11 @@ impl DeviceEnumerator {
d = parent.clone();
- if !self
- .test_matches(&mut parent.borrow_mut(), flags)
- .map_err(|e| Error::Nix {
- msg: format!("add_parent_devices failed: {}", e),
- source: e.get_errno(),
- })?
- {
+ if !self.test_matches(&mut parent.borrow_mut(), flags)? {
continue;
}
- if !self.add_device(parent.clone()).map_err(|e| Error::Nix {
- msg: format!("add_parent_devices failed: {}", e),
- source: e.get_errno(),
- })? {
+ if !self.add_device(parent.clone())? {
break;
}
}
@@ -711,12 +650,8 @@ impl DeviceEnumerator {
let mut path: Vec<String> = vec!["/sys".to_string(), basedir];
path.append(&mut subdirs);
let path = path.join("/");
- let path = match Path::new(&path).canonicalize().map_err(|e| Error::Nix {
- msg: format!(
- "scan_dir_and_add_devices failed: canonicalize {} ({})",
- path, e
- ),
- source: Errno::from_i32(e.raw_os_error().unwrap_or_default()),
+ let path = match Path::new(&path).canonicalize().context(Io {
+ msg: format!("failed to canonicalize '{}'", path),
}) {
Ok(p) => p,
Err(e) => {
@@ -729,37 +664,31 @@ impl DeviceEnumerator {
let entries = std::fs::read_dir(path).unwrap();
for entry in entries {
- if let Err(e) = entry {
- ret = Err(Error::Nix {
- msg: format!("scan_dir_and_add_devices failed: read entries ({})", e),
- source: Errno::from_i32(e.raw_os_error().unwrap_or_default()),
- });
- continue;
- }
-
- let entry = entry.unwrap();
+ let entry = match entry.context(Io {
+ msg: "failed to read directory entry".to_string(),
+ }) {
+ Ok(i) => i,
+ Err(e) => {
+ ret = Err(e);
+ continue;
+ }
+ };
if !relevant_sysfs_subdir(&entry) {
continue;
}
- if !self.match_sysname(entry.file_name().to_str().unwrap_or_default())? {
+ if !self.match_sysname(entry.file_name().to_str().unwrap_or_default()) {
continue;
}
- let syspath = match entry.path().canonicalize() {
+ let syspath = match entry.path().canonicalize().context(Io {
+ msg: format!("failed to canonicalize '{:?}'", entry.path()),
+ }) {
Ok(ret) => ret,
Err(e) => {
- if let Some(errno) = e.raw_os_error() {
- if errno != libc::ENODEV {
- ret = Err(Error::Nix {
- msg: format!(
- "scan_dir_and_add_devices failed: can't canonicalize '{:?}': {}",
- entry, e
- ),
- source: Errno::from_i32(errno),
- });
- }
+ if e.get_errno() != Errno::ENODEV {
+ ret = Err(e);
}
continue;
}
@@ -787,10 +716,7 @@ impl DeviceEnumerator {
continue;
}
Err(e) => {
- ret = Err(Error::Nix {
- msg: format!("scan_dir_and_add_devices failed: {}", e),
- source: e.get_errno(),
- });
+ ret = Err(e);
continue;
}
};
@@ -806,15 +732,11 @@ impl DeviceEnumerator {
};
// also include all potentially matching parent devices.
- match self.add_parent_devices(device.clone(), MatchFlag::ALL) {
- Ok(_) => {}
- Err(e) => {
- ret = Err(Error::Nix {
- msg: format!("scan_dir_and_add_devices failed: {}", e),
- source: e.get_errno(),
- });
- }
- };
+ let _ = self
+ .add_parent_devices(device.clone(), MatchFlag::ALL)
+ .map_err(|e| {
+ ret = Err(e);
+ });
}
ret
@@ -828,15 +750,9 @@ impl DeviceEnumerator {
subsystem: Option<String>,
) -> Result<(), Error> {
let path_str = "/sys/".to_string() + basedir.as_str();
- let path = match Path::new(&path_str).canonicalize() {
- Ok(ret) => ret,
- Err(e) => {
- return Err(Error::Nix {
- msg: format!("scan_dir failed: can't canonicalize '{}': {}", basedir, e),
- source: Errno::EINVAL,
- });
- }
- };
+ let path = Path::new(&path_str).canonicalize().context(Io {
+ msg: format!("fail to canonicalize '{}'", path_str),
+ })?;
let dir = std::fs::read_dir(path);
if let Err(e) = dir {
@@ -853,16 +769,12 @@ impl DeviceEnumerator {
let mut ret = Result::<(), Error>::Ok(());
for entry in dir.unwrap() {
- let entry = match entry {
+ let entry = match entry.context(Io {
+ msg: format!("failed to read entry under '{}'", path_str),
+ }) {
Ok(e) => e,
Err(e) => {
- ret = Err(Error::Nix {
- msg: format!(
- "scan_dir failed: can't read entries from directory '{}'",
- path_str
- ),
- source: Errno::from_i32(e.raw_os_error().unwrap_or_default()),
- });
+ ret = Err(e);
continue;
}
};
@@ -871,14 +783,13 @@ impl DeviceEnumerator {
continue;
}
- match self.match_subsystem(
+ if !self.match_subsystem(
subsystem
.clone()
.unwrap_or_else(|| entry.file_name().to_str().unwrap_or_default().to_string())
.as_str(),
) {
- Ok(false) | Err(_) => continue,
- Ok(true) => {}
+ continue;
}
let mut subdirs = vec![entry.file_name().to_str().unwrap_or_default().to_string()];
@@ -887,30 +798,30 @@ impl DeviceEnumerator {
subdirs.push(subdir.clone().unwrap());
}
- if let Err(e) = self.scan_dir_and_add_devices(basedir.clone(), subdirs) {
- ret = Err(Error::Nix {
- msg: format!("scan_dir failed: {}", e),
- source: e.get_errno(),
+ let _ = self
+ .scan_dir_and_add_devices(basedir.clone(), subdirs)
+ .map_err(|e| {
+ ret = Err(e);
});
- }
}
ret
}
/// scan devices for a single tag
pub(crate) fn scan_devices_tag(&self, tag: &str) -> Result<(), Error> {
- let path = Path::new("/run/devmaster/tags/").join(tag);
- let dir = std::fs::read_dir(path);
- let tag_dir = match dir {
+ let path = Path::new(self.base_path.borrow().as_str())
+ .join(TAGS_BASE_DIR)
+ .join(tag);
+ let dir = std::fs::read_dir(&path);
+ let tag_dir = match dir.context(Io {
+ msg: format!("failed to read '{:?}'", path),
+ }) {
Ok(d) => d,
Err(e) => {
- if e.raw_os_error().unwrap_or_default() == libc::ENOENT {
+ if e.get_errno() == Errno::ENOENT {
return Ok(());
} else {
- return Err(Error::Nix {
- msg: format!("scan_dir failed: can't read directory '{}'", tag),
- source: Errno::from_i32(e.raw_os_error().unwrap_or_default()),
- });
+ return Err(e);
}
}
};
@@ -919,16 +830,12 @@ impl DeviceEnumerator {
let mut ret = Ok(());
for entry in tag_dir {
- let entry = match entry {
+ let entry = match entry.context(Io {
+ msg: format!("failed to read entry under '{:?}'", path),
+ }) {
Ok(e) => e,
Err(e) => {
- ret = Err(Error::Nix {
- msg: format!(
- "scan_dir failed: can't read entries from directory '{}'",
- tag
- ),
- source: Errno::from_i32(e.raw_os_error().unwrap_or_default()),
- });
+ ret = Err(e);
continue;
}
};
@@ -977,10 +884,7 @@ impl DeviceEnumerator {
for tag in self.match_tag.borrow().iter() {
if let Err(e) = self.scan_devices_tag(tag) {
- ret = Err(Error::Nix {
- msg: format!("scan_devices_tags failed: {}", e),
- source: e.get_errno(),
- });
+ ret = Err(e);
}
}
ret
@@ -1012,40 +916,31 @@ impl DeviceEnumerator {
path: &str,
stack: &mut HashSet<String>,
) -> Result<(), Error> {
- let entries = match std::fs::read_dir(path) {
+ let entries = match std::fs::read_dir(path).context(Io {
+ msg: format!("failed to read '{}'", path),
+ }) {
Ok(ret) => ret,
Err(e) => {
- let errno = e.raw_os_error().unwrap_or_default();
- if errno == libc::ENOENT {
+ if e.get_errno() == Errno::ENOENT {
return Ok(());
} else {
- return Err(Error::Nix {
- msg: format!(
- "parent_crawl_children failed: can't read directory '{}'",
- path
- ),
- source: Errno::from_i32(errno),
- });
+ return Err(e);
}
}
};
let mut ret = Result::<(), Error>::Ok(());
for entry in entries {
- let entry = match entry {
+ let entry = match entry.context(Io {
+ msg: format!("failed to read entry under'{:?}'", path),
+ }) {
Ok(e) => e,
Err(e) => {
- ret = Err(Error::Nix {
- msg: format!(
- "parent_crawl_children failed: can't read entries under '{}'",
- path
- ),
- source: Errno::from_i32(e.raw_os_error().unwrap_or_default()),
- });
+ ret = Err(e);
continue;
}
};
- let file_name = entry.file_name();
- let file_name = file_name.to_str().unwrap_or_default();
+
+ let file_name = entry.file_name().to_str().unwrap_or_default().to_string();
if file_name.is_empty() || file_name.starts_with('.') {
continue;
}
@@ -1055,29 +950,22 @@ impl DeviceEnumerator {
continue;
}
- let entry_path = match entry.path().canonicalize() {
+ let entry_path = match entry.path().canonicalize().context(Io {
+ msg: format!("fail to canonicalize '{:?}'", entry.path()),
+ }) {
Ok(p) => p.to_str().unwrap_or_default().to_string(),
Err(e) => {
- ret = Err(Error::Nix {
- msg: format!(
- "parent_crawl_children failed: can't canonicalize '{:?}'",
- entry
- ),
- source: Errno::from_i32(e.raw_os_error().unwrap_or_default()),
- });
+ ret = Err(e);
continue;
}
};
- if let Ok(true) = self.match_sysname(file_name) {
+ if self.match_sysname(&file_name) {
if let Err(e) = self.parent_add_child(
&entry_path,
MatchFlag::ALL & !(MatchFlag::SYSNAME | MatchFlag::PARENT),
) {
- ret = Err(Error::Nix {
- msg: format!("parent_crawl_children failed: {}", e),
- source: e.get_errno(),
- });
+ ret = Err(e);
};
}
@@ -1099,17 +987,11 @@ impl DeviceEnumerator {
.parent_add_child(path, MatchFlag::ALL & !MatchFlag::PARENT)
.map(|_| ())
{
- ret = Err(Error::Nix {
- msg: format!("scan_devices_children failed: {}", e),
- source: e.get_errno(),
- })
+ ret = Err(e)
}
if let Err(e) = self.parent_crawl_children(path, &mut stack) {
- ret = Err(Error::Nix {
- msg: format!("scan_devices_children failed: {}", e),
- source: e.get_errno(),
- })
+ ret = Err(e)
}
}
@@ -1117,10 +999,7 @@ impl DeviceEnumerator {
stack.remove(&path);
if let Err(e) = self.parent_crawl_children(&path, &mut stack) {
- ret = Err(Error::Nix {
- msg: format!("scan_devices_children failed: {}", e),
- source: e.get_errno(),
- })
+ ret = Err(e)
}
}
@@ -1132,17 +1011,11 @@ impl DeviceEnumerator {
let mut ret = Result::<(), Error>::Ok(());
if let Err(e) = self.scan_dir("bus".to_string(), Some("devices".to_string()), None) {
- ret = Err(Error::Nix {
- msg: format!("scan_devices_all failed: {}", e),
- source: e.get_errno(),
- })
+ ret = Err(e);
}
if let Err(e) = self.scan_dir("class".to_string(), None, None) {
- ret = Err(Error::Nix {
- msg: format!("scan_devices_all failed: {}", e),
- source: e.get_errno(),
- })
+ ret = Err(e);
}
ret
@@ -1152,44 +1025,35 @@ impl DeviceEnumerator {
pub(crate) fn scan_subsystems_all(&mut self) -> Result<(), Error> {
let mut ret = Result::<(), Error>::Ok(());
- if self.match_subsystem("module").map_err(|e| Error::Nix {
- msg: format!("scan_subsystems_all failed: {}", e),
- source: e.get_errno(),
- })? {
- if let Err(e) = self.scan_dir_and_add_devices("module".to_string(), vec![]) {
- ret = Err(Error::Nix {
- msg: format!("scan_subsystems_all failed: {}", e),
- source: e.get_errno(),
- })
- }
+ if self.match_subsystem("module") {
+ let _ = self
+ .scan_dir_and_add_devices("module".to_string(), vec![])
+ .map_err(|e| {
+ ret = Err(e);
+ log::error!("Enumerator: failed to scan modules");
+ });
}
- if self.match_subsystem("subsystem").map_err(|e| Error::Nix {
- msg: format!("scan_subsystems_all failed: {}", e),
- source: e.get_errno(),
- })? {
- if let Err(e) = self.scan_dir_and_add_devices("bus".to_string(), vec![]) {
- ret = Err(Error::Nix {
- msg: format!("scan_subsystems_all failed: {}", e),
- source: e.get_errno(),
- })
- }
+ if self.match_subsystem("subsystem") {
+ let _ = self
+ .scan_dir_and_add_devices("bus".to_string(), vec![])
+ .map_err(|e| {
+ ret = Err(e);
+ log::error!("Enumerator: failed to scan subsystems");
+ });
}
- if self.match_subsystem("drivers").map_err(|e| Error::Nix {
- msg: format!("scan_subsystems_all failed: {}", e),
- source: e.get_errno(),
- })? {
- if let Err(e) = self.scan_dir(
- "bus".to_string(),
- Some("drivers".to_string()),
- Some("drivers".to_string()),
- ) {
- ret = Err(Error::Nix {
- msg: format!("scan_subsystems_all failed: {}", e),
- source: e.get_errno(),
- })
- }
+ if self.match_subsystem("drivers") {
+ let _ = self
+ .scan_dir(
+ "bus".to_string(),
+ Some("drivers".to_string()),
+ Some("drivers".to_string()),
+ )
+ .map_err(|e| {
+ ret = Err(e);
+ log::error!("Enumerator: failed to scan drivers");
+ });
}
ret
@@ -1209,24 +1073,11 @@ impl DeviceEnumerator {
let mut ret = Result::<(), Error>::Ok(());
if !self.match_tag.borrow().is_empty() {
- if let Err(e) = self.scan_devices_tags() {
- ret = Err(Error::Nix {
- msg: format!("scan_devices failed: {}", e),
- source: e.get_errno(),
- })
- }
+ let _ = self.scan_devices_tags().map_err(|e| ret = Err(e));
} else if !self.match_parent.borrow().is_empty() {
- if let Err(e) = self.scan_devices_children() {
- ret = Err(Error::Nix {
- msg: format!("scan_devices failed: {}", e),
- source: e.get_errno(),
- })
- }
+ let _ = self.scan_devices_children().map_err(|e| ret = Err(e));
} else if let Err(e) = self.scan_devices_all() {
- ret = Err(Error::Nix {
- msg: format!("scan_devices failed: {}", e),
- source: e.get_errno(),
- })
+ ret = Err(e);
}
self.scan_up_to_date.replace(true);
@@ -1247,10 +1098,7 @@ impl DeviceEnumerator {
self.devices_by_syspath.borrow_mut().clear();
self.devices.borrow_mut().clear();
- let ret = self.scan_subsystems_all().map_err(|e| Error::Nix {
- msg: format!("scan_subsystems failed: {}", e),
- source: e.get_errno(),
- });
+ let ret = self.scan_subsystems_all();
self.scan_up_to_date.replace(true);
self.etype.replace(DeviceEnumerationType::Subsystems);
@@ -1271,33 +1119,18 @@ impl DeviceEnumerator {
let mut ret = Result::<(), Error>::Ok(());
if !self.match_tag.borrow().is_empty() {
- if let Err(e) = self.scan_devices_tags() {
- ret = Err(Error::Nix {
- msg: format!("scan_devices_and_subsystems failed: {}", e),
- source: e.get_errno(),
- })
- }
+ ret = self.scan_devices_tags();
} else if !self.match_parent.borrow().is_empty() {
- if let Err(e) = self.scan_devices_children() {
- ret = Err(Error::Nix {
- msg: format!("scan_devices_and_subsystems failed: {}", e),
- source: e.get_errno(),
- })
- }
+ ret = self.scan_devices_children();
} else {
- if let Err(e) = self.scan_devices_all() {
- ret = Err(Error::Nix {
- msg: format!("scan_devices_and_subsystems failed: {}", e),
- source: e.get_errno(),
- })
- }
+ let _ = self.scan_devices_all().map_err(|e| {
+ ret = Err(e);
+ log::error!("Failed to scan devices.");
+ });
- if let Err(e) = self.scan_subsystems_all() {
- ret = Err(Error::Nix {
- msg: format!("scan_devices_and_subsystems failed: {}", e),
- source: e.get_errno(),
- })
- }
+ let _ = self.scan_subsystems_all().map_err(|e| {
+ ret = Err(e);
+ });
}
self.scan_up_to_date.replace(true);
@@ -1306,20 +1139,18 @@ impl DeviceEnumerator {
ret
}
- /// pattern match
- /// if the enumerator filter is of Glob type, use unix glob-fnmatch to check whether match
- /// if the enumerator filter is of Regular type, use typical regular expression to check whether match
- pub(crate) fn pattern_match(&self, pattern: &str, value: &str) -> Result<bool, Error> {
+ /// Pattern match based on glob style pattern
+ pub(crate) fn pattern_match(&self, pattern: &str, value: &str) -> bool {
let pattern = format!("{}\0", pattern);
let value = format!("{}\0", value);
- Ok(unsafe {
+ unsafe {
fnmatch(
pattern.as_ptr() as *const c_char,
value.as_ptr() as *const c_char,
0,
- )
- } == 0)
+ ) == 0
+ }
}
/// if any exclude pattern matches, return false
@@ -1330,38 +1161,32 @@ impl DeviceEnumerator {
include_pattern_set: &HashSet<String>,
exclude_pattern_set: &HashSet<String>,
value: &str,
- ) -> Result<bool, Error> {
+ ) -> bool {
for pattern in exclude_pattern_set.iter() {
- if self.pattern_match(pattern, value).map_err(|e| Error::Nix {
- msg: format!("set_pattern_match failed: pattern_match exclude ({})", e),
- source: e.get_errno(),
- })? {
- return Ok(false);
+ if self.pattern_match(pattern, value) {
+ return false;
}
}
if include_pattern_set.is_empty() {
- return Ok(true);
+ return true;
}
for pattern in include_pattern_set.iter() {
- if self.pattern_match(pattern, value).map_err(|e| Error::Nix {
- msg: format!("set_pattern_match failed: pattern_match include ({})", e),
- source: e.get_errno(),
- })? {
- return Ok(true);
+ if self.pattern_match(pattern, value) {
+ return true;
}
}
- Ok(false)
+ false
}
}
#[cfg(test)]
mod tests {
- use crate::device_enumerator::DeviceEnumerationType;
+ use crate::{device_enumerator::DeviceEnumerationType, Device};
- use super::DeviceEnumerator;
+ use super::{DeviceEnumerator, MatchInitializedType};
#[test]
fn test_enumerator_inialize() {
@@ -1374,6 +1199,17 @@ mod tests {
enumerator.add_match_property("DEVTYPE", "char").unwrap();
enumerator.add_match_sysname("sda", true).unwrap();
enumerator.add_match_sysname("sdb", false).unwrap();
+ enumerator.add_prioritized_subsystem("net").unwrap();
+ enumerator.add_match_tag("devmaster").unwrap();
+
+ let dev = Device::from_subsystem_sysname("net", "lo").unwrap();
+
+ enumerator.add_match_parent_incremental(&dev).unwrap();
+ enumerator.add_match_parent(&dev).unwrap();
+ enumerator.allow_uninitialized().unwrap();
+ enumerator
+ .add_match_is_initialized(MatchInitializedType::ALL)
+ .unwrap();
}
#[test]
@@ -1409,6 +1245,176 @@ mod tests {
#[test]
fn test_pattern_match() {
let enumerator = DeviceEnumerator::new();
- assert!(enumerator.pattern_match("hello*", "hello world").unwrap());
+ assert!(enumerator.pattern_match("hello*", "hello world"));
+ assert!(!enumerator.pattern_match("hello*", "world"));
+ }
+
+ trait State {
+ fn trans(self: Box<Self>, s: &str) -> Box<dyn State>;
+ }
+
+ struct StateMachine {
+ state: Option<Box<dyn State>>,
+ }
+
+ impl StateMachine {
+ fn trans(&mut self, s: &str) {
+ if let Some(state) = self.state.take() {
+ self.state = Some(state.trans(s));
+ }
+ }
+ }
+
+ struct Init;
+
+ impl State for Init {
+ fn trans(self: Box<Self>, s: &str) -> Box<dyn State> {
+ match s {
+ "net" => Box::new(Front {}),
+ _ => panic!(),
+ }
+ }
+ }
+
+ struct Front;
+
+ impl State for Front {
+ fn trans(self: Box<Self>, s: &str) -> Box<dyn State> {
+ match s {
+ "net" => Box::new(Front {}),
+ _ => Box::new(Tail {}),
+ }
+ }
+ }
+
+ struct Tail;
+
+ impl State for Tail {
+ fn trans(self: Box<Self>, s: &str) -> Box<dyn State> {
+ match s {
+ "net" => panic!(),
+ _ => Box::new(Tail {}),
+ }
+ }
+ }
+
+ #[test]
+ fn test_priority_subsystem() {
+ /* If the prioritized subsystem is set, e.g., "net",
+ * the "net" devices should be ordered in the front of the scanned devices.
+ */
+ let mut ert = DeviceEnumerator::new();
+ ert.set_enumerator_type(DeviceEnumerationType::Devices);
+ ert.add_prioritized_subsystem("net").unwrap();
+ ert.add_prioritized_subsystem("block").unwrap();
+
+ let mut sm = StateMachine {
+ state: Some(Box::new(Init {})),
+ };
+
+ for dev in ert.iter() {
+ sm.trans(&dev.borrow().get_subsystem().unwrap());
+ }
+
+ ert.sort_devices().unwrap();
+ }
+
+ #[test]
+ fn test_match_property() {
+ let mut ert = DeviceEnumerator::new();
+
+ let mut dev = Device::from_subsystem_sysname("net", "lo").unwrap();
+
+ dev.add_property("helloxxx", "worldxxx").unwrap();
+
+ ert.add_match_property("hello*", "world*").unwrap();
+ assert!(ert.match_property(&mut dev).unwrap());
+ }
+
+ #[test]
+ fn test_match_subsystem() {
+ let mut ert = DeviceEnumerator::new();
+
+ ert.add_match_subsystem("net", true).unwrap();
+ ert.add_match_subsystem("block", false).unwrap();
+
+ assert!(ert.match_subsystem("net"));
+ assert!(!ert.match_subsystem("block"));
+ }
+
+ #[test]
+ fn test_match_sysattr() {
+ let mut ert = DeviceEnumerator::new();
+ let dev = Device::from_subsystem_sysname("net", "lo").unwrap();
+
+ ert.add_match_sysattr("ifindex", "1", true).unwrap();
+ ert.add_match_sysattr("address", "aa:aa:aa:aa:aa:aa", false)
+ .unwrap();
+
+ assert!(ert.match_sysattr(&dev).unwrap());
+ }
+
+ #[test]
+ fn test_match_sysname() {
+ let mut ert = DeviceEnumerator::new();
+ ert.add_match_sysname("loop*", true).unwrap();
+ ert.add_match_sysname("sd*", false).unwrap();
+ assert!(ert.match_sysname("loop1"));
+ assert!(!ert.match_sysname("sda"));
+ }
+
+ #[test]
+ fn test_match_tag() {
+ let mut ert = DeviceEnumerator::new();
+ let dev = Device::from_subsystem_sysname("net", "lo").unwrap();
+ dev.set_base_path("/tmp/devmaster");
+ dev.add_tag("devmaster", true);
+ dev.update_tag("devmaster", true).unwrap();
+ ert.add_match_tag("devmaster").unwrap();
+ assert!(ert.match_tag(&dev).unwrap());
+
+ ert.set_enumerator_type(DeviceEnumerationType::Devices);
+ ert.scan_devices().unwrap();
+
+ dev.update_tag("devmaster", false).unwrap();
+ }
+
+ #[test]
+ fn test_match_parent_incremental() {
+ let mut ert = DeviceEnumerator::new();
+ let dev = Device::from_subsystem_sysname("net", "lo").unwrap();
+ assert!(ert.match_parent(&dev).unwrap());
+ ert.add_match_parent_incremental(&dev).unwrap();
+ assert!(ert.match_parent(&dev).unwrap());
+ let dev_1 = Device::from_subsystem_sysname("drivers", "usb:usb").unwrap();
+ assert!(!ert.match_parent(&dev_1).unwrap());
+
+ ert.set_enumerator_type(DeviceEnumerationType::Devices);
+ ert.scan_devices().unwrap();
+ }
+
+ #[test]
+ fn test_match_parent() {
+ let mut ert = DeviceEnumerator::new();
+ let dev = Device::from_subsystem_sysname("net", "lo").unwrap();
+ ert.add_match_parent_incremental(&dev).unwrap();
+ assert!(ert.match_parent(&dev).unwrap());
+ }
+
+ #[test]
+ fn test_match_is_initialized() {
+ let mut ert = DeviceEnumerator::new();
+ let dev = Device::from_subsystem_sysname("net", "lo").unwrap();
+ ert.add_match_is_initialized(MatchInitializedType::ALL)
+ .unwrap();
+ assert!(ert.match_initialized(&dev).unwrap());
+ }
+
+ #[test]
+ fn test_scan_subsystems_all() {
+ let mut ert = DeviceEnumerator::new();
+ ert.add_match_subsystem("module", true).unwrap();
+ ert.add_match_subsystem("subsystem", true).unwrap();
+ ert.add_match_subsystem("drivers", true).unwrap();
}
}
diff --git a/libs/device/src/error.rs b/libs/device/src/error.rs
index 2cea6f4b..3d7307b7 100644
--- a/libs/device/src/error.rs
+++ b/libs/device/src/error.rs
@@ -12,6 +12,7 @@
//! Error definition of device
//!
+use basic::IN_SET;
use nix::errno::Errno;
use snafu::prelude::Snafu;
@@ -77,10 +78,7 @@ impl Error {
/// check whether the device error indicates the device is absent
pub fn is_absent(&self) -> bool {
- matches!(
- self.get_errno(),
- Errno::ENODEV | Errno::ENXIO | Errno::ENOENT
- )
+ IN_SET!(self.get_errno(), Errno::ENODEV, Errno::ENXIO, Errno::ENOENT)
}
pub(crate) fn replace_errno(self, from: Errno, to: Errno) -> Self {
--
2.33.0