use udevrs::{udev_new, UdevDevice, UdevHwdb};
use crate::error::{Error, ErrorKind};
#[derive(Debug, Clone, PartialEq, Default)]
pub struct UdevInfo {
pub driver: Option<String>,
pub syspath: Option<String>,
}
fn get_device(port_path: &str) -> Result<UdevDevice, Error> {
UdevDevice::new_from_subsystem_sysname(udev_new(), "usb", port_path).map_err(|e| {
log::error!("Failed to get udev info for device at {port_path}: Error({e})");
Error::new(
ErrorKind::Udev,
&format!("Failed to get udev info for device at {port_path}: Error({e})"),
)
})
}
pub fn get_udev_info(port_path: &str) -> Result<UdevInfo, Error> {
let mut device = get_device(port_path)?;
Ok({
UdevInfo {
driver: device.get_driver().map(|s| s.trim().to_string()),
syspath: Some(device.syspath().trim().to_string()),
}
})
}
pub fn get_udev_driver_name(port_path: &str) -> Result<Option<String>, Error> {
let mut device = get_device(port_path)?;
Ok(device.get_driver().map(|s| s.trim().to_string()))
}
pub fn get_udev_syspath(port_path: &str) -> Result<Option<String>, Error> {
let device = get_device(port_path)?;
Ok(Some(device.syspath().trim().to_string()))
}
pub fn get_udev_attribute<T: AsRef<std::ffi::OsStr> + std::fmt::Display + Into<String>>(
port_path: &str,
attribute: T,
) -> Result<Option<String>, Error> {
let mut device = get_device(port_path)?;
Ok(device
.get_sysattr_value(&attribute.into())
.map(|s| s.trim().to_string()))
}
pub fn get_devlinks(sys_dev: &str) -> Result<Option<Vec<String>>, Error> {
let device = get_device(sys_dev)?;
log::debug!("Device Syspath: {:?}", device);
let devlinks = device.devlinks_list();
log::debug!("Devlinks: {:?}", devlinks);
Ok(device
.get_property_value("DEVLINKS")
.map(|s| s.split_whitespace().map(|s| s.to_string()).collect()))
}
pub mod hwdb {
use super::*;
pub fn get(modalias: &str, key: &'static str) -> Result<Option<String>, Error> {
let mut hwdb = UdevHwdb::new(udev_new()).map_err(|e| {
log::error!("Failed to get hwdb: Error({e})");
Error::new(ErrorKind::Udev, &format!("Failed to get hwdb: Error({e})"))
})?;
Ok(udevrs::udev_hwdb_query_one(&mut hwdb, modalias, key).map(|s| s.trim().to_string()))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[cfg_attr(not(feature = "usb_test"), ignore)]
#[test]
fn test_udev_info() {
let udevi = get_udev_info("1-0:1.0").unwrap();
assert_eq!(udevi.driver, Some("hub".into()));
assert!(udevi.syspath.unwrap().contains("1-0:1.0"));
}
#[cfg_attr(not(feature = "usb_test"), ignore)]
#[test]
fn test_udev_attribute() {
let interface_class = get_udev_attribute("1-0:1.0", "bInterfaceClass").unwrap();
assert_eq!(interface_class, Some("09".into()));
}
}