diff options
author | Wesley Moore <wes@wezm.net> | 2022-07-24 10:44:29 +1000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-07-23 20:44:29 -0400 |
commit | 577fda96fc30165fe613ae2131b70844ba47c3b2 (patch) | |
tree | b981baebc49dd47e2813ad585a0f7787da6b505b /src/app/data_harvester/disks | |
parent | 510aa5c4042d9933310d24da38f08ff4647875d9 (diff) |
Implement support for FreeBSD (#766)
* WIP FreeBSD support
* Implement get_cpu_data_list for FreeBSD
* Implement disks for FreeBSD
It doesn't work though as sysinfo doesn't make the device name available.
* Use libxo to read process cpu info on FreeBSD
* Populate get_io_usage with libxo too
Actual I/O stats still aren't populated though as there's not an
easy source for them.
* Share more processes code between macos and freebsd
* Extract function for deserializing libxo output on FreeBSD
* Implement filtering of disks in FreeBSD
* Clean up memory data collection
* Update module docs
Diffstat (limited to 'src/app/data_harvester/disks')
-rw-r--r-- | src/app/data_harvester/disks/freebsd.rs | 105 | ||||
-rw-r--r-- | src/app/data_harvester/disks/heim.rs | 21 |
2 files changed, 109 insertions, 17 deletions
diff --git a/src/app/data_harvester/disks/freebsd.rs b/src/app/data_harvester/disks/freebsd.rs new file mode 100644 index 00000000..3f15dff4 --- /dev/null +++ b/src/app/data_harvester/disks/freebsd.rs @@ -0,0 +1,105 @@ +//! Disk stats for FreeBSD. + +use serde::Deserialize; +use std::io; + +use super::{DiskHarvest, IoHarvest}; +use crate::app::Filter; +use crate::data_harvester::deserialize_xo; + +#[derive(Deserialize, Debug, Default)] +#[serde(rename_all = "kebab-case")] +struct StorageSystemInformation { + filesystem: Vec<FileSystem>, +} + +#[derive(Deserialize, Debug)] +#[serde(rename_all = "kebab-case")] +struct FileSystem { + name: String, + total_blocks: u64, + used_blocks: u64, + available_blocks: u64, + mounted_on: String, +} + +pub async fn get_io_usage(actually_get: bool) -> crate::utils::error::Result<Option<IoHarvest>> { + if !actually_get { + return Ok(None); + } + + let io_harvest = get_disk_info().map(|storage_system_information| { + storage_system_information + .filesystem + .into_iter() + .map(|disk| (disk.name, None)) + .collect() + })?; + Ok(Some(io_harvest)) +} + +pub async fn get_disk_usage( + actually_get: bool, disk_filter: &Option<Filter>, mount_filter: &Option<Filter>, +) -> crate::utils::error::Result<Option<Vec<DiskHarvest>>> { + if !actually_get { + return Ok(None); + } + + let mut vec_disks: Vec<DiskHarvest> = get_disk_info().map(|storage_system_information| { + storage_system_information + .filesystem + .into_iter() + .filter_map(|disk| { + // Precedence ordering in the case where name and mount filters disagree, "allow" + // takes precedence over "deny". + // + // For implementation, we do this as follows: + // + // 1. Is the entry allowed through any filter? That is, does it match an entry in a + // filter where `is_list_ignored` is `false`? If so, we always keep this entry. + // 2. Is the entry denied through any filter? That is, does it match an entry in a + // filter where `is_list_ignored` is `true`? If so, we always deny this entry. + // 3. Anything else is allowed. + let filter_check_map = + [(disk_filter, &disk.name), (mount_filter, &disk.mounted_on)]; + if matches_allow_list(filter_check_map.as_slice()) + || !matches_ignore_list(filter_check_map.as_slice()) + { + Some(DiskHarvest { + free_space: Some(disk.available_blocks * 1024), + used_space: Some(disk.used_blocks * 1024), + total_space: Some(disk.total_blocks * 1024), + mount_point: disk.mounted_on, + name: disk.name, + }) + } else { + None + } + }) + .collect() + })?; + + vec_disks.sort_by(|a, b| a.name.cmp(&b.name)); + Ok(Some(vec_disks)) +} + +fn matches_allow_list(filter_check_map: &[(&Option<Filter>, &String)]) -> bool { + filter_check_map.iter().any(|(filter, text)| match filter { + Some(f) if !f.is_list_ignored => f.list.iter().any(|r| r.is_match(text)), + Some(_) | None => false, + }) +} + +fn matches_ignore_list(filter_check_map: &[(&Option<Filter>, &String)]) -> bool { + filter_check_map.iter().any(|(filter, text)| match filter { + Some(f) if f.is_list_ignored => f.list.iter().any(|r| r.is_match(text)), + Some(_) | None => false, + }) +} + +fn get_disk_info() -> io::Result<StorageSystemInformation> { + let output = std::process::Command::new("df") + .args(&["--libxo", "json", "-k", "-t", "ufs,msdosfs,zfs"]) + .output()?; + deserialize_xo("storage-system-information", &output.stdout) +} diff --git a/src/app/data_harvester/disks/heim.rs b/src/app/data_harvester/disks/heim.rs index c99ae105..85608858 100644 --- a/src/app/data_harvester/disks/heim.rs +++ b/src/app/data_harvester/disks/heim.rs @@ -1,4 +1,8 @@ +//! Disk stats through heim. +//! Supports macOS, Linux, and Windows. + use crate::app::Filter; +use crate::data_harvester::disks::{DiskHarvest, IoData, IoHarvest}; cfg_if::cfg_if! { if #[cfg(target_os = "linux")] { @@ -10,23 +14,6 @@ cfg_if::cfg_if! { } } -#[derive(Debug, Clone, Default)] -pub struct DiskHarvest { - pub name: String, - pub mount_point: 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 = std::collections::HashMap<String, Option<IoData>>; - pub async fn get_io_usage(actually_get: bool) -> crate::utils::error::Result<Option<IoHarvest>> { if !actually_get { return Ok(None); |