cfg_if! {
if #[cfg(target_os = "freebsd")] {
mod freebsd;
#[cfg(feature = "zfs")]
mod io_counters;
#[cfg(feature = "zfs")]
mod zfs_io_counters;
#[cfg(feature = "zfs")]
pub use io_counters::IoCounters;
pub(crate) use self::freebsd::*;
} else if #[cfg(target_os = "windows")] {
mod windows;
pub(crate) use self::windows::*;
} else if #[cfg(target_os = "linux")] {
mod unix;
#[cfg(feature = "zfs")]
mod zfs_io_counters;
pub(crate) use self::unix::*;
} else if #[cfg(target_os = "macos")] {
mod unix;
pub(crate) use self::unix::*;
} else {
mod other;
pub(crate) use self::other::*;
}
}
use cfg_if::cfg_if;
use rustc_hash::FxHashMap as HashMap;
use crate::app::filter::Filter;
#[derive(Clone, Debug, Default)]
pub struct DiskHarvest {
pub name: String,
pub mount_point: String,
#[cfg(target_os = "windows")]
pub volume_name: Option<String>,
pub free_space: Option<u64>,
pub used_space: Option<u64>,
pub total_space: Option<u64>,
}
#[derive(Clone, Debug)]
pub struct IoData {
pub read_bytes: u64,
pub write_bytes: u64,
}
pub type IoHarvest = HashMap<String, Option<IoData>>;
cfg_if! {
if #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))] {
mod io_counters;
pub use io_counters::IoCounters;
pub fn get_io_usage() -> anyhow::Result<IoHarvest> {
let mut io_hash: HashMap<String, Option<IoData>> = HashMap::default();
for io in io_stats()?.into_iter() {
let mount_point = io.device_name().to_string_lossy();
io_hash.insert(
mount_point.to_string(),
Some(IoData {
read_bytes: io.read_bytes(),
write_bytes: io.write_bytes(),
}),
);
}
Ok(io_hash)
}
} else if #[cfg(not(target_os = "freebsd"))] {
pub fn get_io_usage() -> anyhow::Result<IoHarvest> {
anyhow::bail!("Unsupported OS");
}
}
}
pub fn keep_disk_entry(
disk_name: &str, mount_point: &str, disk_filter: &Option<Filter>, mount_filter: &Option<Filter>,
) -> bool {
match (disk_filter, mount_filter) {
(Some(d), Some(m)) => match (d.ignore_matches(), m.ignore_matches()) {
(true, true) => !(d.has_match(disk_name) || m.has_match(mount_point)),
(true, false) => {
if m.has_match(mount_point) {
true
} else {
d.should_keep(disk_name)
}
}
(false, true) => {
if d.has_match(disk_name) {
true
} else {
m.should_keep(mount_point)
}
}
(false, false) => d.has_match(disk_name) || m.has_match(mount_point),
},
(Some(d), None) => d.should_keep(disk_name),
(None, Some(m)) => m.should_keep(mount_point),
(None, None) => true,
}
}
#[cfg(test)]
mod test {
use regex::Regex;
use super::keep_disk_entry;
use crate::app::filter::Filter;
fn run_filter(disk_filter: &Option<Filter>, mount_filter: &Option<Filter>) -> Vec<usize> {
let targets = [
("/dev/nvme0n1p1", "/boot"),
("/dev/nvme0n1p2", "/"),
("/dev/nvme0n1p3", "/home"),
("/dev/sda1", "/mnt/test"),
("/dev/sda2", "/mnt/boot"),
];
targets
.into_iter()
.enumerate()
.filter_map(|(itx, (name, mount))| {
if keep_disk_entry(name, mount, disk_filter, mount_filter) {
Some(itx)
} else {
None
}
})
.collect()
}
#[test]
fn test_keeping_disk_entry() {
let disk_ignore = Some(Filter::new(true, vec![Regex::new("nvme").unwrap()]));
let disk_keep = Some(Filter::new(false, vec![Regex::new("nvme").unwrap()]));
let mount_ignore = Some(Filter::new(true, vec![Regex::new("boot").unwrap()]));
let mount_keep = Some(Filter::new(false, vec![Regex::new("boot").unwrap()]));
assert_eq!(run_filter(&None, &None), vec![0, 1, 2, 3, 4]);
assert_eq!(run_filter(&disk_ignore, &None), vec![3, 4]);
assert_eq!(run_filter(&disk_keep, &None), vec![0, 1, 2]);
assert_eq!(run_filter(&None, &mount_ignore), vec![1, 2, 3]);
assert_eq!(run_filter(&None, &mount_keep), vec![0, 4]);
assert_eq!(run_filter(&disk_ignore, &mount_ignore), vec![3]);
assert_eq!(run_filter(&disk_keep, &mount_ignore), vec![0, 1, 2, 3]);
assert_eq!(run_filter(&disk_ignore, &mount_keep), vec![0, 3, 4]);
assert_eq!(run_filter(&disk_keep, &mount_keep), vec![0, 1, 2, 4]);
}
}