summaryrefslogtreecommitdiffstats
path: root/src/app/data_harvester/disks
diff options
context:
space:
mode:
authorWesley Moore <wes@wezm.net>2022-07-24 10:44:29 +1000
committerGitHub <noreply@github.com>2022-07-23 20:44:29 -0400
commit577fda96fc30165fe613ae2131b70844ba47c3b2 (patch)
treeb981baebc49dd47e2813ad585a0f7787da6b505b /src/app/data_harvester/disks
parent510aa5c4042d9933310d24da38f08ff4647875d9 (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.rs105
-rw-r--r--src/app/data_harvester/disks/heim.rs21
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);