mod system;
mod types;
pub use types::*;
#[cfg(test)]
use super::mocks::SYS_BLOCK_DEV_STAT;
use super::{storage::stat, SysPath};
use crate::Result;
use system::blk_bsz_get;
fn parse_maj_min(dev: &str) -> Option<(u32, u32)> {
let mut elems = dev.split(':');
if let Some(maj) = elems.next() {
if let Some(min) = elems.next() {
if let Ok(maj) = maj.trim().parse::<u32>() {
if let Ok(min) = min.trim().parse::<u32>() {
return Some((maj, min));
}
}
}
}
None
}
pub fn block_size(device: &str) -> Result<i64> {
blk_bsz_get(SysPath::Dev(device).path().to_string_lossy().as_ref())
}
pub fn stat_block_device(name: &str) -> Result<StorageDevice> {
stat::<StorageDevice>(name)
}
pub fn stat_device_mapper(name: &str) -> Result<DeviceMapper> {
stat::<DeviceMapper>(name)
}
pub fn stat_scsi_cdrom(name: &str) -> Result<ScsiCdrom> {
stat::<ScsiCdrom>(name)
}
pub fn stat_multiple_device_storage(name: &str) -> Result<MultipleDeviceStorage> {
stat::<MultipleDeviceStorage>(name)
}
pub fn storage_devices<T: FromSysName<T> + BlockStorageDeviceName>() -> Result<Vec<T>> {
let mut devices = Vec::new();
for entry in SysPath::SysBlock.read_dir()? {
if let Ok(entry) = entry {
let filename = entry.file_name().to_string_lossy().to_string();
if filename.starts_with(T::prefix()) {
devices.push(stat::<T>(&entry.file_name().to_string_lossy().to_string())?);
}
}
}
Ok(devices)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parses_block_device_stat_from_sys_block_dev_stat() {
let dev = StorageDevice {
model: "ST2000DM008-2FR1".to_string(),
vendor: "ATA".to_string(),
state: "running".to_string(),
info: BlockStorageInfo {
stat: BlockStorageStat {
read_ios: 327,
read_merges: 72,
read_sectors: 8832,
read_ticks: 957,
write_ios: 31,
write_merges: 1,
write_sectors: 206,
write_ticks: 775,
in_flight: 0,
io_ticks: 1620,
time_in_queue: 2427,
discard_ios: 0,
discard_merges: 0,
discard_sectors: 0,
discard_ticks: 0,
},
dev: "sda".to_string(),
size: 3907029168,
maj: 8,
min: 1,
block_size: 4096,
},
partitions: vec![],
};
assert_eq!(BlockStorageStat::from_stat(SYS_BLOCK_DEV_STAT), Ok(dev.info.stat))
}
#[test]
fn parses_maj_min() {
assert_eq!(parse_maj_min("X:5"), None);
assert_eq!(parse_maj_min("1:Y"), None);
assert_eq!(parse_maj_min("rand:"), None);
assert_eq!(parse_maj_min(":xx"), None);
assert_eq!(parse_maj_min("xxx"), None);
assert_eq!(parse_maj_min("8:1"), Some((8, 1)))
}
}